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