linprocfs.c revision 299219
1/*- 2 * Copyright (c) 2000 Dag-Erling Co��dan Sm��rgrav 3 * Copyright (c) 1999 Pierre Beyssac 4 * Copyright (c) 1993 Jan-Simon Pendry 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 40 */ 41 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: stable/10/sys/compat/linprocfs/linprocfs.c 299219 2016-05-07 18:54:35Z dchagin $"); 44 45#include <sys/param.h> 46#include <sys/queue.h> 47#include <sys/systm.h> 48#include <sys/blist.h> 49#include <sys/conf.h> 50#include <sys/exec.h> 51#include <sys/fcntl.h> 52#include <sys/filedesc.h> 53#include <sys/jail.h> 54#include <sys/kernel.h> 55#include <sys/limits.h> 56#include <sys/linker.h> 57#include <sys/lock.h> 58#include <sys/malloc.h> 59#include <sys/mount.h> 60#include <sys/msg.h> 61#include <sys/mutex.h> 62#include <sys/namei.h> 63#include <sys/proc.h> 64#include <sys/ptrace.h> 65#include <sys/resourcevar.h> 66#include <sys/sbuf.h> 67#include <sys/sem.h> 68#include <sys/smp.h> 69#include <sys/socket.h> 70#include <sys/sysctl.h> 71#include <sys/sysent.h> 72#include <sys/systm.h> 73#include <sys/time.h> 74#include <sys/tty.h> 75#include <sys/user.h> 76#include <sys/uuid.h> 77#include <sys/vmmeter.h> 78#include <sys/vnode.h> 79#include <sys/bus.h> 80 81#include <net/if.h> 82#include <net/if_types.h> 83 84#include <vm/vm.h> 85#include <vm/vm_extern.h> 86#include <vm/pmap.h> 87#include <vm/vm_map.h> 88#include <vm/vm_param.h> 89#include <vm/vm_object.h> 90#include <vm/swap_pager.h> 91 92#include <machine/clock.h> 93 94#include <geom/geom.h> 95#include <geom/geom_int.h> 96 97#if defined(__i386__) || defined(__amd64__) 98#include <machine/cputypes.h> 99#include <machine/md_var.h> 100#endif /* __i386__ || __amd64__ */ 101 102#include <compat/linux/linux.h> 103#include <compat/linux/linux_mib.h> 104#include <compat/linux/linux_misc.h> 105#include <compat/linux/linux_util.h> 106#include <fs/pseudofs/pseudofs.h> 107#include <fs/procfs/procfs.h> 108 109/* 110 * Various conversion macros 111 */ 112#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */ 113#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */ 114#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 115#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 116#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 117#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 118#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 119#define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000) 120 121/** 122 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 123 * 124 * The linux procfs state field displays one of the characters RSDZTW to 125 * denote running, sleeping in an interruptible wait, waiting in an 126 * uninterruptible disk sleep, a zombie process, process is being traced 127 * or stopped, or process is paging respectively. 128 * 129 * Our struct kinfo_proc contains the variable ki_stat which contains a 130 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 131 * 132 * This character array is used with ki_stati-1 as an index and tries to 133 * map our states to suitable linux states. 134 */ 135static char linux_state[] = "RRSTZDD"; 136 137/* 138 * Filler function for proc/meminfo 139 */ 140static int 141linprocfs_domeminfo(PFS_FILL_ARGS) 142{ 143 unsigned long memtotal; /* total memory in bytes */ 144 unsigned long memused; /* used memory in bytes */ 145 unsigned long memfree; /* free memory in bytes */ 146 unsigned long memshared; /* shared memory ??? */ 147 unsigned long buffers, cached; /* buffer / cache memory ??? */ 148 unsigned long long swaptotal; /* total swap space in bytes */ 149 unsigned long long swapused; /* used swap space in bytes */ 150 unsigned long long swapfree; /* free swap space in bytes */ 151 vm_object_t object; 152 int i, j; 153 154 memtotal = physmem * PAGE_SIZE; 155 /* 156 * The correct thing here would be: 157 * 158 memfree = cnt.v_free_count * PAGE_SIZE; 159 memused = memtotal - memfree; 160 * 161 * but it might mislead linux binaries into thinking there 162 * is very little memory left, so we cheat and tell them that 163 * all memory that isn't wired down is free. 164 */ 165 memused = cnt.v_wire_count * PAGE_SIZE; 166 memfree = memtotal - memused; 167 swap_pager_status(&i, &j); 168 swaptotal = (unsigned long long)i * PAGE_SIZE; 169 swapused = (unsigned long long)j * PAGE_SIZE; 170 swapfree = swaptotal - swapused; 171 memshared = 0; 172 mtx_lock(&vm_object_list_mtx); 173 TAILQ_FOREACH(object, &vm_object_list, object_list) 174 if (object->shadow_count > 1) 175 memshared += object->resident_page_count; 176 mtx_unlock(&vm_object_list_mtx); 177 memshared *= PAGE_SIZE; 178 /* 179 * We'd love to be able to write: 180 * 181 buffers = bufspace; 182 * 183 * but bufspace is internal to vfs_bio.c and we don't feel 184 * like unstaticizing it just for linprocfs's sake. 185 */ 186 buffers = 0; 187 cached = cnt.v_cache_count * PAGE_SIZE; 188 189 sbuf_printf(sb, 190 " total: used: free: shared: buffers: cached:\n" 191 "Mem: %lu %lu %lu %lu %lu %lu\n" 192 "Swap: %llu %llu %llu\n" 193 "MemTotal: %9lu kB\n" 194 "MemFree: %9lu kB\n" 195 "MemShared:%9lu kB\n" 196 "Buffers: %9lu kB\n" 197 "Cached: %9lu kB\n" 198 "SwapTotal:%9llu kB\n" 199 "SwapFree: %9llu kB\n", 200 memtotal, memused, memfree, memshared, buffers, cached, 201 swaptotal, swapused, swapfree, 202 B2K(memtotal), B2K(memfree), 203 B2K(memshared), B2K(buffers), B2K(cached), 204 B2K(swaptotal), B2K(swapfree)); 205 206 return (0); 207} 208 209#if defined(__i386__) || defined(__amd64__) 210/* 211 * Filler function for proc/cpuinfo (i386 & amd64 version) 212 */ 213static int 214linprocfs_docpuinfo(PFS_FILL_ARGS) 215{ 216 int hw_model[2]; 217 char model[128]; 218 uint64_t freq; 219 size_t size; 220 int class, fqmhz, fqkhz; 221 int i; 222 223 /* 224 * We default the flags to include all non-conflicting flags, 225 * and the Intel versions of conflicting flags. 226 */ 227 static char *flags[] = { 228 "fpu", "vme", "de", "pse", "tsc", 229 "msr", "pae", "mce", "cx8", "apic", 230 "sep", "sep", "mtrr", "pge", "mca", 231 "cmov", "pat", "pse36", "pn", "b19", 232 "b20", "b21", "mmxext", "mmx", "fxsr", 233 "xmm", "sse2", "b27", "b28", "b29", 234 "3dnowext", "3dnow" 235 }; 236 237 switch (cpu_class) { 238#ifdef __i386__ 239 case CPUCLASS_286: 240 class = 2; 241 break; 242 case CPUCLASS_386: 243 class = 3; 244 break; 245 case CPUCLASS_486: 246 class = 4; 247 break; 248 case CPUCLASS_586: 249 class = 5; 250 break; 251 case CPUCLASS_686: 252 class = 6; 253 break; 254 default: 255 class = 0; 256 break; 257#else /* __amd64__ */ 258 default: 259 class = 15; 260 break; 261#endif 262 } 263 264 hw_model[0] = CTL_HW; 265 hw_model[1] = HW_MODEL; 266 model[0] = '\0'; 267 size = sizeof(model); 268 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 269 strcpy(model, "unknown"); 270 for (i = 0; i < mp_ncpus; ++i) { 271 sbuf_printf(sb, 272 "processor\t: %d\n" 273 "vendor_id\t: %.20s\n" 274 "cpu family\t: %u\n" 275 "model\t\t: %u\n" 276 "model name\t: %s\n" 277 "stepping\t: %u\n\n", 278 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id), 279 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); 280 /* XXX per-cpu vendor / class / model / id? */ 281 } 282 283 sbuf_cat(sb, "flags\t\t:"); 284 285#ifdef __i386__ 286 switch (cpu_vendor_id) { 287 case CPU_VENDOR_AMD: 288 if (class < 6) 289 flags[16] = "fcmov"; 290 break; 291 case CPU_VENDOR_CYRIX: 292 flags[24] = "cxmmx"; 293 break; 294 } 295#endif 296 297 for (i = 0; i < 32; i++) 298 if (cpu_feature & (1 << i)) 299 sbuf_printf(sb, " %s", flags[i]); 300 sbuf_cat(sb, "\n"); 301 freq = atomic_load_acq_64(&tsc_freq); 302 if (freq != 0) { 303 fqmhz = (freq + 4999) / 1000000; 304 fqkhz = ((freq + 4999) / 10000) % 100; 305 sbuf_printf(sb, 306 "cpu MHz\t\t: %d.%02d\n" 307 "bogomips\t: %d.%02d\n", 308 fqmhz, fqkhz, fqmhz, fqkhz); 309 } 310 311 return (0); 312} 313#endif /* __i386__ || __amd64__ */ 314 315/* 316 * Filler function for proc/mtab 317 * 318 * This file doesn't exist in Linux' procfs, but is included here so 319 * users can symlink /compat/linux/etc/mtab to /proc/mtab 320 */ 321static int 322linprocfs_domtab(PFS_FILL_ARGS) 323{ 324 struct nameidata nd; 325 struct mount *mp; 326 const char *lep; 327 char *dlep, *flep, *mntto, *mntfrom, *fstype; 328 size_t lep_len; 329 int error; 330 331 /* resolve symlinks etc. in the emulation tree prefix */ 332 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 333 flep = NULL; 334 error = namei(&nd); 335 lep = linux_emul_path; 336 if (error == 0) { 337 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 338 lep = dlep; 339 vrele(nd.ni_vp); 340 } 341 lep_len = strlen(lep); 342 343 mtx_lock(&mountlist_mtx); 344 error = 0; 345 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 346 /* determine device name */ 347 mntfrom = mp->mnt_stat.f_mntfromname; 348 349 /* determine mount point */ 350 mntto = mp->mnt_stat.f_mntonname; 351 if (strncmp(mntto, lep, lep_len) == 0 && 352 mntto[lep_len] == '/') 353 mntto += lep_len; 354 355 /* determine fs type */ 356 fstype = mp->mnt_stat.f_fstypename; 357 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 358 mntfrom = fstype = "proc"; 359 else if (strcmp(fstype, "procfs") == 0) 360 continue; 361 362 if (strcmp(fstype, "linsysfs") == 0) { 363 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 364 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 365 } else { 366 /* For Linux msdosfs is called vfat */ 367 if (strcmp(fstype, "msdosfs") == 0) 368 fstype = "vfat"; 369 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 370 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 371 } 372#define ADD_OPTION(opt, name) \ 373 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 374 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 375 ADD_OPTION(MNT_NOEXEC, "noexec"); 376 ADD_OPTION(MNT_NOSUID, "nosuid"); 377 ADD_OPTION(MNT_UNION, "union"); 378 ADD_OPTION(MNT_ASYNC, "async"); 379 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 380 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 381 ADD_OPTION(MNT_NOATIME, "noatime"); 382#undef ADD_OPTION 383 /* a real Linux mtab will also show NFS options */ 384 sbuf_printf(sb, " 0 0\n"); 385 } 386 mtx_unlock(&mountlist_mtx); 387 free(flep, M_TEMP); 388 return (error); 389} 390 391/* 392 * Filler function for proc/partitions 393 */ 394static int 395linprocfs_dopartitions(PFS_FILL_ARGS) 396{ 397 struct g_class *cp; 398 struct g_geom *gp; 399 struct g_provider *pp; 400 int major, minor; 401 402 g_topology_lock(); 403 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 404 "ruse wio wmerge wsect wuse running use aveq\n"); 405 406 LIST_FOREACH(cp, &g_classes, class) { 407 if (strcmp(cp->name, "DISK") == 0 || 408 strcmp(cp->name, "PART") == 0) 409 LIST_FOREACH(gp, &cp->geom, geom) { 410 LIST_FOREACH(pp, &gp->provider, provider) { 411 if (linux_driver_get_major_minor( 412 pp->name, &major, &minor) != 0) { 413 major = 0; 414 minor = 0; 415 } 416 sbuf_printf(sb, "%d %d %lld %s " 417 "%d %d %d %d %d " 418 "%d %d %d %d %d %d\n", 419 major, minor, 420 (long long)pp->mediasize, pp->name, 421 0, 0, 0, 0, 0, 422 0, 0, 0, 0, 0, 0); 423 } 424 } 425 } 426 g_topology_unlock(); 427 428 return (0); 429} 430 431 432/* 433 * Filler function for proc/stat 434 */ 435static int 436linprocfs_dostat(PFS_FILL_ARGS) 437{ 438 struct pcpu *pcpu; 439 long cp_time[CPUSTATES]; 440 long *cp; 441 int i; 442 443 read_cpu_time(cp_time); 444 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 445 T2J(cp_time[CP_USER]), 446 T2J(cp_time[CP_NICE]), 447 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 448 T2J(cp_time[CP_IDLE])); 449 CPU_FOREACH(i) { 450 pcpu = pcpu_find(i); 451 cp = pcpu->pc_cp_time; 452 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 453 T2J(cp[CP_USER]), 454 T2J(cp[CP_NICE]), 455 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 456 T2J(cp[CP_IDLE])); 457 } 458 sbuf_printf(sb, 459 "disk 0 0 0 0\n" 460 "page %u %u\n" 461 "swap %u %u\n" 462 "intr %u\n" 463 "ctxt %u\n" 464 "btime %lld\n", 465 cnt.v_vnodepgsin, 466 cnt.v_vnodepgsout, 467 cnt.v_swappgsin, 468 cnt.v_swappgsout, 469 cnt.v_intr, 470 cnt.v_swtch, 471 (long long)boottime.tv_sec); 472 return (0); 473} 474 475static int 476linprocfs_doswaps(PFS_FILL_ARGS) 477{ 478 struct xswdev xsw; 479 uintmax_t total, used; 480 int n; 481 char devname[SPECNAMELEN + 1]; 482 483 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); 484 mtx_lock(&Giant); 485 for (n = 0; ; n++) { 486 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0) 487 break; 488 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024; 489 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024; 490 491 /* 492 * The space and not tab after the device name is on 493 * purpose. Linux does so. 494 */ 495 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n", 496 devname, total, used); 497 } 498 mtx_unlock(&Giant); 499 return (0); 500} 501 502/* 503 * Filler function for proc/uptime 504 */ 505static int 506linprocfs_douptime(PFS_FILL_ARGS) 507{ 508 long cp_time[CPUSTATES]; 509 struct timeval tv; 510 511 getmicrouptime(&tv); 512 read_cpu_time(cp_time); 513 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 514 (long long)tv.tv_sec, tv.tv_usec / 10000, 515 T2S(cp_time[CP_IDLE] / mp_ncpus), 516 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 517 return (0); 518} 519 520/* 521 * Get OS build date 522 */ 523static void 524linprocfs_osbuild(struct thread *td, struct sbuf *sb) 525{ 526#if 0 527 char osbuild[256]; 528 char *cp1, *cp2; 529 530 strncpy(osbuild, version, 256); 531 osbuild[255] = '\0'; 532 cp1 = strstr(osbuild, "\n"); 533 cp2 = strstr(osbuild, ":"); 534 if (cp1 && cp2) { 535 *cp1 = *cp2 = '\0'; 536 cp1 = strstr(osbuild, "#"); 537 } else 538 cp1 = NULL; 539 if (cp1) 540 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 541 else 542#endif 543 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 544} 545 546/* 547 * Get OS builder 548 */ 549static void 550linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 551{ 552#if 0 553 char builder[256]; 554 char *cp; 555 556 cp = strstr(version, "\n "); 557 if (cp) { 558 strncpy(builder, cp + 5, 256); 559 builder[255] = '\0'; 560 cp = strstr(builder, ":"); 561 if (cp) 562 *cp = '\0'; 563 } 564 if (cp) 565 sbuf_cat(sb, builder); 566 else 567#endif 568 sbuf_cat(sb, "des@freebsd.org"); 569} 570 571/* 572 * Filler function for proc/version 573 */ 574static int 575linprocfs_doversion(PFS_FILL_ARGS) 576{ 577 char osname[LINUX_MAX_UTSNAME]; 578 char osrelease[LINUX_MAX_UTSNAME]; 579 580 linux_get_osname(td, osname); 581 linux_get_osrelease(td, osrelease); 582 sbuf_printf(sb, "%s version %s (", osname, osrelease); 583 linprocfs_osbuilder(td, sb); 584 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 585 linprocfs_osbuild(td, sb); 586 sbuf_cat(sb, "\n"); 587 588 return (0); 589} 590 591/* 592 * Filler function for proc/loadavg 593 */ 594static int 595linprocfs_doloadavg(PFS_FILL_ARGS) 596{ 597 598 sbuf_printf(sb, 599 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 600 (int)(averunnable.ldavg[0] / averunnable.fscale), 601 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 602 (int)(averunnable.ldavg[1] / averunnable.fscale), 603 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 604 (int)(averunnable.ldavg[2] / averunnable.fscale), 605 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 606 1, /* number of running tasks */ 607 nprocs, /* number of tasks */ 608 lastpid /* the last pid */ 609 ); 610 return (0); 611} 612 613/* 614 * Filler function for proc/pid/stat 615 */ 616static int 617linprocfs_doprocstat(PFS_FILL_ARGS) 618{ 619 struct kinfo_proc kp; 620 char state; 621 static int ratelimit = 0; 622 vm_offset_t startcode, startdata; 623 624 PROC_LOCK(p); 625 fill_kinfo_proc(p, &kp); 626 if (p->p_vmspace) { 627 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 628 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 629 } else { 630 startcode = 0; 631 startdata = 0; 632 }; 633 sbuf_printf(sb, "%d", p->p_pid); 634#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 635 PS_ADD("comm", "(%s)", p->p_comm); 636 if (kp.ki_stat > sizeof(linux_state)) { 637 state = 'R'; 638 639 if (ratelimit == 0) { 640 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 641 kp.ki_stat, sizeof(linux_state)); 642 ++ratelimit; 643 } 644 } else 645 state = linux_state[kp.ki_stat - 1]; 646 PS_ADD("state", "%c", state); 647 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 648 PS_ADD("pgrp", "%d", p->p_pgid); 649 PS_ADD("session", "%d", p->p_session->s_sid); 650 PROC_UNLOCK(p); 651 PS_ADD("tty", "%d", kp.ki_tdev); 652 PS_ADD("tpgid", "%d", kp.ki_tpgid); 653 PS_ADD("flags", "%u", 0); /* XXX */ 654 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 655 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 656 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 657 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 658 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 659 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 660 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 661 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 662 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 663 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 664 PS_ADD("0", "%d", 0); /* removed field */ 665 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 666 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 667 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 668 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 669 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 670 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 671 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 672 PS_ADD("startstack", "%u", 0); /* XXX */ 673 PS_ADD("kstkesp", "%u", 0); /* XXX */ 674 PS_ADD("kstkeip", "%u", 0); /* XXX */ 675 PS_ADD("signal", "%u", 0); /* XXX */ 676 PS_ADD("blocked", "%u", 0); /* XXX */ 677 PS_ADD("sigignore", "%u", 0); /* XXX */ 678 PS_ADD("sigcatch", "%u", 0); /* XXX */ 679 PS_ADD("wchan", "%u", 0); /* XXX */ 680 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 681 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 682 PS_ADD("exitsignal", "%d", 0); /* XXX */ 683 PS_ADD("processor", "%u", kp.ki_lastcpu); 684 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 685 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 686#undef PS_ADD 687 sbuf_putc(sb, '\n'); 688 689 return (0); 690} 691 692/* 693 * Filler function for proc/pid/statm 694 */ 695static int 696linprocfs_doprocstatm(PFS_FILL_ARGS) 697{ 698 struct kinfo_proc kp; 699 segsz_t lsize; 700 701 PROC_LOCK(p); 702 fill_kinfo_proc(p, &kp); 703 PROC_UNLOCK(p); 704 705 /* 706 * See comments in linprocfs_doprocstatus() regarding the 707 * computation of lsize. 708 */ 709 /* size resident share trs drs lrs dt */ 710 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 711 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 712 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 713 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 714 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 715 lsize = B2P(kp.ki_size) - kp.ki_dsize - 716 kp.ki_ssize - kp.ki_tsize - 1; 717 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 718 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 719 720 return (0); 721} 722 723/* 724 * Filler function for proc/pid/status 725 */ 726static int 727linprocfs_doprocstatus(PFS_FILL_ARGS) 728{ 729 struct kinfo_proc kp; 730 char *state; 731 segsz_t lsize; 732 struct thread *td2; 733 struct sigacts *ps; 734 l_sigset_t siglist, sigignore, sigcatch; 735 int i; 736 737 PROC_LOCK(p); 738 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 739 740 if (P_SHOULDSTOP(p)) { 741 state = "T (stopped)"; 742 } else { 743 switch(p->p_state) { 744 case PRS_NEW: 745 state = "I (idle)"; 746 break; 747 case PRS_NORMAL: 748 if (p->p_flag & P_WEXIT) { 749 state = "X (exiting)"; 750 break; 751 } 752 switch(td2->td_state) { 753 case TDS_INHIBITED: 754 state = "S (sleeping)"; 755 break; 756 case TDS_RUNQ: 757 case TDS_RUNNING: 758 state = "R (running)"; 759 break; 760 default: 761 state = "? (unknown)"; 762 break; 763 } 764 break; 765 case PRS_ZOMBIE: 766 state = "Z (zombie)"; 767 break; 768 default: 769 state = "? (unknown)"; 770 break; 771 } 772 } 773 774 fill_kinfo_proc(p, &kp); 775 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 776 sbuf_printf(sb, "State:\t%s\n", state); 777 778 /* 779 * Credentials 780 */ 781 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 782 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 783 p->p_pptr->p_pid : 0); 784 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 785 p->p_ucred->cr_uid, 786 p->p_ucred->cr_svuid, 787 /* FreeBSD doesn't have fsuid */ 788 p->p_ucred->cr_uid); 789 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 790 p->p_ucred->cr_gid, 791 p->p_ucred->cr_svgid, 792 /* FreeBSD doesn't have fsgid */ 793 p->p_ucred->cr_gid); 794 sbuf_cat(sb, "Groups:\t"); 795 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 796 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 797 PROC_UNLOCK(p); 798 sbuf_putc(sb, '\n'); 799 800 /* 801 * Memory 802 * 803 * While our approximation of VmLib may not be accurate (I 804 * don't know of a simple way to verify it, and I'm not sure 805 * it has much meaning anyway), I believe it's good enough. 806 * 807 * The same code that could (I think) accurately compute VmLib 808 * could also compute VmLck, but I don't really care enough to 809 * implement it. Submissions are welcome. 810 */ 811 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 812 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 813 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 814 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 815 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 816 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 817 lsize = B2P(kp.ki_size) - kp.ki_dsize - 818 kp.ki_ssize - kp.ki_tsize - 1; 819 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 820 821 /* 822 * Signal masks 823 */ 824 PROC_LOCK(p); 825 bsd_to_linux_sigset(&p->p_siglist, &siglist); 826 ps = p->p_sigacts; 827 mtx_lock(&ps->ps_mtx); 828 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore); 829 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch); 830 mtx_unlock(&ps->ps_mtx); 831 PROC_UNLOCK(p); 832 833 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask); 834 /* 835 * XXX. SigBlk - target thread's signal mask, td_sigmask. 836 * To implement SigBlk pseudofs should support proc/tid dir entries. 837 */ 838 sbuf_printf(sb, "SigBlk:\t%016x\n", 0); 839 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask); 840 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask); 841 842 /* 843 * Linux also prints the capability masks, but we don't have 844 * capabilities yet, and when we do get them they're likely to 845 * be meaningless to Linux programs, so we lie. XXX 846 */ 847 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 848 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 849 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 850 851 return (0); 852} 853 854 855/* 856 * Filler function for proc/pid/cwd 857 */ 858static int 859linprocfs_doproccwd(PFS_FILL_ARGS) 860{ 861 struct filedesc *fdp; 862 struct vnode *vp; 863 char *fullpath = "unknown"; 864 char *freepath = NULL; 865 866 fdp = p->p_fd; 867 FILEDESC_SLOCK(fdp); 868 vp = fdp->fd_cdir; 869 if (vp != NULL) 870 VREF(vp); 871 FILEDESC_SUNLOCK(fdp); 872 vn_fullpath(td, vp, &fullpath, &freepath); 873 if (vp != NULL) 874 vrele(vp); 875 sbuf_printf(sb, "%s", fullpath); 876 if (freepath) 877 free(freepath, M_TEMP); 878 return (0); 879} 880 881/* 882 * Filler function for proc/pid/root 883 */ 884static int 885linprocfs_doprocroot(PFS_FILL_ARGS) 886{ 887 struct filedesc *fdp; 888 struct vnode *vp; 889 char *fullpath = "unknown"; 890 char *freepath = NULL; 891 892 fdp = p->p_fd; 893 FILEDESC_SLOCK(fdp); 894 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir; 895 if (vp != NULL) 896 VREF(vp); 897 FILEDESC_SUNLOCK(fdp); 898 vn_fullpath(td, vp, &fullpath, &freepath); 899 if (vp != NULL) 900 vrele(vp); 901 sbuf_printf(sb, "%s", fullpath); 902 if (freepath) 903 free(freepath, M_TEMP); 904 return (0); 905} 906 907/* 908 * Filler function for proc/pid/cmdline 909 */ 910static int 911linprocfs_doproccmdline(PFS_FILL_ARGS) 912{ 913 int ret; 914 915 PROC_LOCK(p); 916 if ((ret = p_cansee(td, p)) != 0) { 917 PROC_UNLOCK(p); 918 return (ret); 919 } 920 921 /* 922 * Mimic linux behavior and pass only processes with usermode 923 * address space as valid. Return zero silently otherwize. 924 */ 925 if (p->p_vmspace == &vmspace0) { 926 PROC_UNLOCK(p); 927 return (0); 928 } 929 if (p->p_args != NULL) { 930 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 931 PROC_UNLOCK(p); 932 return (0); 933 } 934 935 if ((p->p_flag & P_SYSTEM) != 0) { 936 PROC_UNLOCK(p); 937 return (0); 938 } 939 940 PROC_UNLOCK(p); 941 942 ret = proc_getargv(td, p, sb); 943 return (ret); 944} 945 946/* 947 * Filler function for proc/pid/environ 948 */ 949static int 950linprocfs_doprocenviron(PFS_FILL_ARGS) 951{ 952 953 /* 954 * Mimic linux behavior and pass only processes with usermode 955 * address space as valid. Return zero silently otherwize. 956 */ 957 if (p->p_vmspace == &vmspace0) 958 return (0); 959 960 return (proc_getenvv(td, p, sb)); 961} 962 963static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n"; 964static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n"; 965static char vdso_str[] = " [vdso]"; 966static char stack_str[] = " [stack]"; 967 968/* 969 * Filler function for proc/pid/maps 970 */ 971static int 972linprocfs_doprocmaps(PFS_FILL_ARGS) 973{ 974 struct vmspace *vm; 975 vm_map_t map; 976 vm_map_entry_t entry, tmp_entry; 977 vm_object_t obj, tobj, lobj; 978 vm_offset_t e_start, e_end; 979 vm_ooffset_t off = 0; 980 vm_prot_t e_prot; 981 unsigned int last_timestamp; 982 char *name = "", *freename = NULL; 983 const char *l_map_str; 984 ino_t ino; 985 int ref_count, shadow_count, flags; 986 int error; 987 struct vnode *vp; 988 struct vattr vat; 989 990 PROC_LOCK(p); 991 error = p_candebug(td, p); 992 PROC_UNLOCK(p); 993 if (error) 994 return (error); 995 996 if (uio->uio_rw != UIO_READ) 997 return (EOPNOTSUPP); 998 999 error = 0; 1000 vm = vmspace_acquire_ref(p); 1001 if (vm == NULL) 1002 return (ESRCH); 1003 1004 if (SV_CURPROC_FLAG(SV_LP64)) 1005 l_map_str = l64_map_str; 1006 else 1007 l_map_str = l32_map_str; 1008 map = &vm->vm_map; 1009 vm_map_lock_read(map); 1010 for (entry = map->header.next; entry != &map->header; 1011 entry = entry->next) { 1012 name = ""; 1013 freename = NULL; 1014 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1015 continue; 1016 e_prot = entry->protection; 1017 e_start = entry->start; 1018 e_end = entry->end; 1019 obj = entry->object.vm_object; 1020 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1021 VM_OBJECT_RLOCK(tobj); 1022 if (lobj != obj) 1023 VM_OBJECT_RUNLOCK(lobj); 1024 lobj = tobj; 1025 } 1026 last_timestamp = map->timestamp; 1027 vm_map_unlock_read(map); 1028 ino = 0; 1029 if (lobj) { 1030 off = IDX_TO_OFF(lobj->size); 1031 vp = vm_object_vnode(lobj); 1032 if (vp != NULL) 1033 vref(vp); 1034 if (lobj != obj) 1035 VM_OBJECT_RUNLOCK(lobj); 1036 flags = obj->flags; 1037 ref_count = obj->ref_count; 1038 shadow_count = obj->shadow_count; 1039 VM_OBJECT_RUNLOCK(obj); 1040 if (vp != NULL) { 1041 vn_fullpath(td, vp, &name, &freename); 1042 vn_lock(vp, LK_SHARED | LK_RETRY); 1043 VOP_GETATTR(vp, &vat, td->td_ucred); 1044 ino = vat.va_fileid; 1045 vput(vp); 1046 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) { 1047 if (e_start == p->p_sysent->sv_shared_page_base) 1048 name = vdso_str; 1049 if (e_end == p->p_sysent->sv_usrstack) 1050 name = stack_str; 1051 } 1052 } else { 1053 flags = 0; 1054 ref_count = 0; 1055 shadow_count = 0; 1056 } 1057 1058 /* 1059 * format: 1060 * start, end, access, offset, major, minor, inode, name. 1061 */ 1062 error = sbuf_printf(sb, l_map_str, 1063 (u_long)e_start, (u_long)e_end, 1064 (e_prot & VM_PROT_READ)?"r":"-", 1065 (e_prot & VM_PROT_WRITE)?"w":"-", 1066 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1067 "p", 1068 (u_long)off, 1069 0, 1070 0, 1071 (u_long)ino, 1072 *name ? " " : "", 1073 name 1074 ); 1075 if (freename) 1076 free(freename, M_TEMP); 1077 vm_map_lock_read(map); 1078 if (error == -1) { 1079 error = 0; 1080 break; 1081 } 1082 if (last_timestamp != map->timestamp) { 1083 /* 1084 * Look again for the entry because the map was 1085 * modified while it was unlocked. Specifically, 1086 * the entry may have been clipped, merged, or deleted. 1087 */ 1088 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1089 entry = tmp_entry; 1090 } 1091 } 1092 vm_map_unlock_read(map); 1093 vmspace_free(vm); 1094 1095 return (error); 1096} 1097 1098/* 1099 * Criteria for interface name translation 1100 */ 1101#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) 1102 1103static int 1104linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen) 1105{ 1106 struct ifnet *ifscan; 1107 int ethno; 1108 1109 IFNET_RLOCK_ASSERT(); 1110 1111 /* Short-circuit non ethernet interfaces */ 1112 if (!IFP_IS_ETH(ifp)) 1113 return (strlcpy(buffer, ifp->if_xname, buflen)); 1114 1115 /* Determine the (relative) unit number for ethernet interfaces */ 1116 ethno = 0; 1117 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) { 1118 if (ifscan == ifp) 1119 return (snprintf(buffer, buflen, "eth%d", ethno)); 1120 if (IFP_IS_ETH(ifscan)) 1121 ethno++; 1122 } 1123 1124 return (0); 1125} 1126 1127/* 1128 * Filler function for proc/net/dev 1129 */ 1130static int 1131linprocfs_donetdev(PFS_FILL_ARGS) 1132{ 1133 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1134 struct ifnet *ifp; 1135 1136 sbuf_printf(sb, "%6s|%58s|%s\n" 1137 "%6s|%58s|%58s\n", 1138 "Inter-", " Receive", " Transmit", 1139 " face", 1140 "bytes packets errs drop fifo frame compressed multicast", 1141 "bytes packets errs drop fifo colls carrier compressed"); 1142 1143 CURVNET_SET(TD_TO_VNET(curthread)); 1144 IFNET_RLOCK(); 1145 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1146 linux_ifname(ifp, ifname, sizeof ifname); 1147 sbuf_printf(sb, "%6.6s: ", ifname); 1148 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1149 ifp->if_ibytes, /* rx_bytes */ 1150 ifp->if_ipackets, /* rx_packets */ 1151 ifp->if_ierrors, /* rx_errors */ 1152 ifp->if_iqdrops, /* rx_dropped + 1153 * rx_missed_errors */ 1154 0UL, /* rx_fifo_errors */ 1155 0UL, /* rx_length_errors + 1156 * rx_over_errors + 1157 * rx_crc_errors + 1158 * rx_frame_errors */ 1159 0UL, /* rx_compressed */ 1160 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1161 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1162 ifp->if_obytes, /* tx_bytes */ 1163 ifp->if_opackets, /* tx_packets */ 1164 ifp->if_oerrors, /* tx_errors */ 1165 0UL, /* tx_dropped */ 1166 0UL, /* tx_fifo_errors */ 1167 ifp->if_collisions, /* collisions */ 1168 0UL, /* tx_carrier_errors + 1169 * tx_aborted_errors + 1170 * tx_window_errors + 1171 * tx_heartbeat_errors */ 1172 0UL); /* tx_compressed */ 1173 } 1174 IFNET_RUNLOCK(); 1175 CURVNET_RESTORE(); 1176 1177 return (0); 1178} 1179 1180/* 1181 * Filler function for proc/sys/kernel/osrelease 1182 */ 1183static int 1184linprocfs_doosrelease(PFS_FILL_ARGS) 1185{ 1186 char osrelease[LINUX_MAX_UTSNAME]; 1187 1188 linux_get_osrelease(td, osrelease); 1189 sbuf_printf(sb, "%s\n", osrelease); 1190 1191 return (0); 1192} 1193 1194/* 1195 * Filler function for proc/sys/kernel/ostype 1196 */ 1197static int 1198linprocfs_doostype(PFS_FILL_ARGS) 1199{ 1200 char osname[LINUX_MAX_UTSNAME]; 1201 1202 linux_get_osname(td, osname); 1203 sbuf_printf(sb, "%s\n", osname); 1204 1205 return (0); 1206} 1207 1208/* 1209 * Filler function for proc/sys/kernel/version 1210 */ 1211static int 1212linprocfs_doosbuild(PFS_FILL_ARGS) 1213{ 1214 1215 linprocfs_osbuild(td, sb); 1216 sbuf_cat(sb, "\n"); 1217 return (0); 1218} 1219 1220/* 1221 * Filler function for proc/sys/kernel/msgmni 1222 */ 1223static int 1224linprocfs_domsgmni(PFS_FILL_ARGS) 1225{ 1226 1227 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1228 return (0); 1229} 1230 1231/* 1232 * Filler function for proc/sys/kernel/pid_max 1233 */ 1234static int 1235linprocfs_dopid_max(PFS_FILL_ARGS) 1236{ 1237 1238 sbuf_printf(sb, "%i\n", PID_MAX); 1239 return (0); 1240} 1241 1242/* 1243 * Filler function for proc/sys/kernel/sem 1244 */ 1245static int 1246linprocfs_dosem(PFS_FILL_ARGS) 1247{ 1248 1249 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1250 seminfo.semopm, seminfo.semmni); 1251 return (0); 1252} 1253 1254/* 1255 * Filler function for proc/scsi/device_info 1256 */ 1257static int 1258linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1259{ 1260 1261 return (0); 1262} 1263 1264/* 1265 * Filler function for proc/scsi/scsi 1266 */ 1267static int 1268linprocfs_doscsiscsi(PFS_FILL_ARGS) 1269{ 1270 1271 return (0); 1272} 1273 1274/* 1275 * Filler function for proc/devices 1276 */ 1277static int 1278linprocfs_dodevices(PFS_FILL_ARGS) 1279{ 1280 char *char_devices; 1281 sbuf_printf(sb, "Character devices:\n"); 1282 1283 char_devices = linux_get_char_devices(); 1284 sbuf_printf(sb, "%s", char_devices); 1285 linux_free_get_char_devices(char_devices); 1286 1287 sbuf_printf(sb, "\nBlock devices:\n"); 1288 1289 return (0); 1290} 1291 1292/* 1293 * Filler function for proc/cmdline 1294 */ 1295static int 1296linprocfs_docmdline(PFS_FILL_ARGS) 1297{ 1298 1299 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1300 sbuf_printf(sb, " ro root=302\n"); 1301 return (0); 1302} 1303 1304/* 1305 * Filler function for proc/filesystems 1306 */ 1307static int 1308linprocfs_dofilesystems(PFS_FILL_ARGS) 1309{ 1310 struct vfsconf *vfsp; 1311 1312 mtx_lock(&Giant); 1313 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1314 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1315 sbuf_printf(sb, "nodev"); 1316 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1317 } 1318 mtx_unlock(&Giant); 1319 return(0); 1320} 1321 1322#if 0 1323/* 1324 * Filler function for proc/modules 1325 */ 1326static int 1327linprocfs_domodules(PFS_FILL_ARGS) 1328{ 1329 struct linker_file *lf; 1330 1331 TAILQ_FOREACH(lf, &linker_files, link) { 1332 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1333 (unsigned long)lf->size, lf->refs); 1334 } 1335 return (0); 1336} 1337#endif 1338 1339/* 1340 * Filler function for proc/pid/fd 1341 */ 1342static int 1343linprocfs_dofdescfs(PFS_FILL_ARGS) 1344{ 1345 1346 if (p == curproc) 1347 sbuf_printf(sb, "/dev/fd"); 1348 else 1349 sbuf_printf(sb, "unknown"); 1350 return (0); 1351} 1352 1353 1354/* 1355 * Filler function for proc/sys/kernel/random/uuid 1356 */ 1357static int 1358linprocfs_douuid(PFS_FILL_ARGS) 1359{ 1360 struct uuid uuid; 1361 1362 kern_uuidgen(&uuid, 1); 1363 sbuf_printf_uuid(sb, &uuid); 1364 sbuf_printf(sb, "\n"); 1365 return(0); 1366} 1367 1368/* 1369 * Filler function for proc/pid/auxv 1370 */ 1371static int 1372linprocfs_doauxv(PFS_FILL_ARGS) 1373{ 1374 struct sbuf *asb; 1375 off_t buflen, resid; 1376 int error; 1377 1378 /* 1379 * Mimic linux behavior and pass only processes with usermode 1380 * address space as valid. Return zero silently otherwise. 1381 */ 1382 if (p->p_vmspace == &vmspace0) 1383 return (0); 1384 1385 if (uio->uio_resid == 0) 1386 return (0); 1387 if (uio->uio_offset < 0 || uio->uio_resid < 0) 1388 return (EINVAL); 1389 1390 asb = sbuf_new_auto(); 1391 if (asb == NULL) 1392 return (ENOMEM); 1393 error = proc_getauxv(td, p, asb); 1394 if (error == 0) 1395 error = sbuf_finish(asb); 1396 1397 resid = sbuf_len(asb) - uio->uio_offset; 1398 if (resid > uio->uio_resid) 1399 buflen = uio->uio_resid; 1400 else 1401 buflen = resid; 1402 if (buflen > IOSIZE_MAX) 1403 return (EINVAL); 1404 if (buflen > MAXPHYS) 1405 buflen = MAXPHYS; 1406 if (resid <= 0) 1407 return (0); 1408 1409 if (error == 0) 1410 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio); 1411 sbuf_delete(asb); 1412 return (error); 1413} 1414 1415/* 1416 * Constructor 1417 */ 1418static int 1419linprocfs_init(PFS_INIT_ARGS) 1420{ 1421 struct pfs_node *root; 1422 struct pfs_node *dir; 1423 1424 root = pi->pi_root; 1425 1426 /* /proc/... */ 1427 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1428 NULL, NULL, NULL, PFS_RD); 1429 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1430 NULL, NULL, NULL, PFS_RD); 1431 pfs_create_file(root, "devices", &linprocfs_dodevices, 1432 NULL, NULL, NULL, PFS_RD); 1433 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1434 NULL, NULL, NULL, PFS_RD); 1435 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1436 NULL, NULL, NULL, PFS_RD); 1437 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1438 NULL, NULL, NULL, PFS_RD); 1439#if 0 1440 pfs_create_file(root, "modules", &linprocfs_domodules, 1441 NULL, NULL, NULL, PFS_RD); 1442#endif 1443 pfs_create_file(root, "mounts", &linprocfs_domtab, 1444 NULL, NULL, NULL, PFS_RD); 1445 pfs_create_file(root, "mtab", &linprocfs_domtab, 1446 NULL, NULL, NULL, PFS_RD); 1447 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1448 NULL, NULL, NULL, PFS_RD); 1449 pfs_create_link(root, "self", &procfs_docurproc, 1450 NULL, NULL, NULL, 0); 1451 pfs_create_file(root, "stat", &linprocfs_dostat, 1452 NULL, NULL, NULL, PFS_RD); 1453 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1454 NULL, NULL, NULL, PFS_RD); 1455 pfs_create_file(root, "uptime", &linprocfs_douptime, 1456 NULL, NULL, NULL, PFS_RD); 1457 pfs_create_file(root, "version", &linprocfs_doversion, 1458 NULL, NULL, NULL, PFS_RD); 1459 1460 /* /proc/net/... */ 1461 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1462 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1463 NULL, NULL, NULL, PFS_RD); 1464 1465 /* /proc/<pid>/... */ 1466 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1467 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1468 NULL, NULL, NULL, PFS_RD); 1469 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1470 NULL, NULL, NULL, 0); 1471 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1472 NULL, &procfs_candebug, NULL, PFS_RD); 1473 pfs_create_link(dir, "exe", &procfs_doprocfile, 1474 NULL, &procfs_notsystem, NULL, 0); 1475 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1476 NULL, NULL, NULL, PFS_RD); 1477 pfs_create_file(dir, "mem", &procfs_doprocmem, 1478 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1479 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1480 NULL, NULL, NULL, 0); 1481 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1482 NULL, NULL, NULL, PFS_RD); 1483 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1484 NULL, NULL, NULL, PFS_RD); 1485 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1486 NULL, NULL, NULL, PFS_RD); 1487 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1488 NULL, NULL, NULL, 0); 1489 pfs_create_file(dir, "auxv", &linprocfs_doauxv, 1490 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); 1491 1492 /* /proc/scsi/... */ 1493 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1494 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1495 NULL, NULL, NULL, PFS_RD); 1496 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1497 NULL, NULL, NULL, PFS_RD); 1498 1499 /* /proc/sys/... */ 1500 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1501 /* /proc/sys/kernel/... */ 1502 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1503 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1504 NULL, NULL, NULL, PFS_RD); 1505 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1506 NULL, NULL, NULL, PFS_RD); 1507 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1508 NULL, NULL, NULL, PFS_RD); 1509 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1510 NULL, NULL, NULL, PFS_RD); 1511 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1512 NULL, NULL, NULL, PFS_RD); 1513 pfs_create_file(dir, "sem", &linprocfs_dosem, 1514 NULL, NULL, NULL, PFS_RD); 1515 1516 /* /proc/sys/kernel/random/... */ 1517 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); 1518 pfs_create_file(dir, "uuid", &linprocfs_douuid, 1519 NULL, NULL, NULL, PFS_RD); 1520 1521 return (0); 1522} 1523 1524/* 1525 * Destructor 1526 */ 1527static int 1528linprocfs_uninit(PFS_INIT_ARGS) 1529{ 1530 1531 /* nothing to do, pseudofs will GC */ 1532 return (0); 1533} 1534 1535PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS); 1536#if defined(__amd64__) 1537MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1); 1538#else 1539MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1540#endif 1541MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1542MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1543MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1544