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 | MPSAFE, 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 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 347 } 348 lep_len = strlen(lep); 349 350 mtx_lock(&mountlist_mtx); 351 error = 0; 352 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 353 /* determine device name */ 354 mntfrom = mp->mnt_stat.f_mntfromname; 355 356 /* determine mount point */ 357 mntto = mp->mnt_stat.f_mntonname; 358 if (strncmp(mntto, lep, lep_len) == 0 && 359 mntto[lep_len] == '/') 360 mntto += lep_len; 361 362 /* determine fs type */ 363 fstype = mp->mnt_stat.f_fstypename; 364 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 365 mntfrom = fstype = "proc"; 366 else if (strcmp(fstype, "procfs") == 0) 367 continue; 368 369 if (strcmp(fstype, "linsysfs") == 0) { 370 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 371 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 372 } else { 373 /* For Linux msdosfs is called vfat */ 374 if (strcmp(fstype, "msdosfs") == 0) 375 fstype = "vfat"; 376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 377 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 378 } 379 #define ADD_OPTION(opt, name) \ 380 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 381 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 382 ADD_OPTION(MNT_NOEXEC, "noexec"); 383 ADD_OPTION(MNT_NOSUID, "nosuid"); 384 ADD_OPTION(MNT_UNION, "union"); 385 ADD_OPTION(MNT_ASYNC, "async"); 386 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 387 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 388 ADD_OPTION(MNT_NOATIME, "noatime"); 389 #undef ADD_OPTION 390 /* a real Linux mtab will also show NFS options */ 391 sbuf_printf(sb, " 0 0\n"); 392 } 393 mtx_unlock(&mountlist_mtx); 394 if (flep != NULL) 395 free(flep, M_TEMP); 396 return (error); 397 } 398 399 /* 400 * Filler function for proc/partitions 401 * 402 */ 403 static int 404 linprocfs_dopartitions(PFS_FILL_ARGS) 405 { 406 struct g_class *cp; 407 struct g_geom *gp; 408 struct g_provider *pp; 409 struct nameidata nd; 410 const char *lep; 411 char *dlep, *flep; 412 size_t lep_len; 413 int error; 414 int major, minor; 415 416 /* resolve symlinks etc. in the emulation tree prefix */ 417 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 418 flep = NULL; 419 error = namei(&nd); 420 lep = linux_emul_path; 421 if (error == 0) { 422 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 423 lep = dlep; 424 vrele(nd.ni_vp); 425 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 426 } 427 lep_len = strlen(lep); 428 429 g_topology_lock(); 430 error = 0; 431 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 432 "ruse wio wmerge wsect wuse running use aveq\n"); 433 434 LIST_FOREACH(cp, &g_classes, class) { 435 if (strcmp(cp->name, "DISK") == 0 || 436 strcmp(cp->name, "PART") == 0) 437 LIST_FOREACH(gp, &cp->geom, geom) { 438 LIST_FOREACH(pp, &gp->provider, provider) { 439 if (linux_driver_get_major_minor( 440 pp->name, &major, &minor) != 0) { 441 major = 0; 442 minor = 0; 443 } 444 sbuf_printf(sb, "%d %d %lld %s " 445 "%d %d %d %d %d " 446 "%d %d %d %d %d %d\n", 447 major, minor, 448 (long long)pp->mediasize, pp->name, 449 0, 0, 0, 0, 0, 450 0, 0, 0, 0, 0, 0); 451 } 452 } 453 } 454 g_topology_unlock(); 455 456 if (flep != NULL) 457 free(flep, M_TEMP); 458 return (error); 459 } 460 461 462 /* 463 * Filler function for proc/stat 464 */ 465 static int 466 linprocfs_dostat(PFS_FILL_ARGS) 467 { 468 struct pcpu *pcpu; 469 long cp_time[CPUSTATES]; 470 long *cp; 471 int i; 472 473 read_cpu_time(cp_time); 474 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 475 T2J(cp_time[CP_USER]), 476 T2J(cp_time[CP_NICE]), 477 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 478 T2J(cp_time[CP_IDLE])); 479 CPU_FOREACH(i) { 480 pcpu = pcpu_find(i); 481 cp = pcpu->pc_cp_time; 482 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 483 T2J(cp[CP_USER]), 484 T2J(cp[CP_NICE]), 485 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 486 T2J(cp[CP_IDLE])); 487 } 488 sbuf_printf(sb, 489 "disk 0 0 0 0\n" 490 "page %u %u\n" 491 "swap %u %u\n" 492 "intr %u\n" 493 "ctxt %u\n" 494 "btime %lld\n", 495 cnt.v_vnodepgsin, 496 cnt.v_vnodepgsout, 497 cnt.v_swappgsin, 498 cnt.v_swappgsout, 499 cnt.v_intr, 500 cnt.v_swtch, 501 (long long)boottime.tv_sec); 502 return (0); 503 } 504 505 static int 506 linprocfs_doswaps(PFS_FILL_ARGS) 507 { 508 struct xswdev xsw; 509 uintmax_t total, used; 510 int n; 511 char devname[SPECNAMELEN + 1]; 512 513 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); 514 mtx_lock(&Giant); 515 for (n = 0; ; n++) { 516 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0) 517 break; 518 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024; 519 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024; 520 521 /* 522 * The space and not tab after the device name is on 523 * purpose. Linux does so. 524 */ 525 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n", 526 devname, total, used); 527 } 528 mtx_unlock(&Giant); 529 return (0); 530 } 531 532 /* 533 * Filler function for proc/uptime 534 */ 535 static int 536 linprocfs_douptime(PFS_FILL_ARGS) 537 { 538 long cp_time[CPUSTATES]; 539 struct timeval tv; 540 541 getmicrouptime(&tv); 542 read_cpu_time(cp_time); 543 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 544 (long long)tv.tv_sec, tv.tv_usec / 10000, 545 T2S(cp_time[CP_IDLE] / mp_ncpus), 546 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 547 return (0); 548 } 549 550 /* 551 * Get OS build date 552 */ 553 static void 554 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 555 { 556 #if 0 557 char osbuild[256]; 558 char *cp1, *cp2; 559 560 strncpy(osbuild, version, 256); 561 osbuild[255] = '\0'; 562 cp1 = strstr(osbuild, "\n"); 563 cp2 = strstr(osbuild, ":"); 564 if (cp1 && cp2) { 565 *cp1 = *cp2 = '\0'; 566 cp1 = strstr(osbuild, "#"); 567 } else 568 cp1 = NULL; 569 if (cp1) 570 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 571 else 572 #endif 573 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 574 } 575 576 /* 577 * Get OS builder 578 */ 579 static void 580 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 581 { 582 #if 0 583 char builder[256]; 584 char *cp; 585 586 cp = strstr(version, "\n "); 587 if (cp) { 588 strncpy(builder, cp + 5, 256); 589 builder[255] = '\0'; 590 cp = strstr(builder, ":"); 591 if (cp) 592 *cp = '\0'; 593 } 594 if (cp) 595 sbuf_cat(sb, builder); 596 else 597 #endif 598 sbuf_cat(sb, "des@freebsd.org"); 599 } 600 601 /* 602 * Filler function for proc/version 603 */ 604 static int 605 linprocfs_doversion(PFS_FILL_ARGS) 606 { 607 char osname[LINUX_MAX_UTSNAME]; 608 char osrelease[LINUX_MAX_UTSNAME]; 609 610 linux_get_osname(td, osname); 611 linux_get_osrelease(td, osrelease); 612 sbuf_printf(sb, "%s version %s (", osname, osrelease); 613 linprocfs_osbuilder(td, sb); 614 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 615 linprocfs_osbuild(td, sb); 616 sbuf_cat(sb, "\n"); 617 618 return (0); 619 } 620 621 /* 622 * Filler function for proc/loadavg 623 */ 624 static int 625 linprocfs_doloadavg(PFS_FILL_ARGS) 626 { 627 628 sbuf_printf(sb, 629 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 630 (int)(averunnable.ldavg[0] / averunnable.fscale), 631 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 632 (int)(averunnable.ldavg[1] / averunnable.fscale), 633 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 634 (int)(averunnable.ldavg[2] / averunnable.fscale), 635 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 636 1, /* number of running tasks */ 637 nprocs, /* number of tasks */ 638 lastpid /* the last pid */ 639 ); 640 return (0); 641 } 642 643 /* 644 * Filler function for proc/pid/stat 645 */ 646 static int 647 linprocfs_doprocstat(PFS_FILL_ARGS) 648 { 649 struct kinfo_proc kp; 650 char state; 651 static int ratelimit = 0; 652 vm_offset_t startcode, startdata; 653 654 PROC_LOCK(p); 655 fill_kinfo_proc(p, &kp); 656 if (p->p_vmspace) { 657 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 658 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 659 } else { 660 startcode = 0; 661 startdata = 0; 662 }; 663 sbuf_printf(sb, "%d", p->p_pid); 664 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 665 PS_ADD("comm", "(%s)", p->p_comm); 666 if (kp.ki_stat > sizeof(linux_state)) { 667 state = 'R'; 668 669 if (ratelimit == 0) { 670 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 671 kp.ki_stat, sizeof(linux_state)); 672 ++ratelimit; 673 } 674 } else 675 state = linux_state[kp.ki_stat - 1]; 676 PS_ADD("state", "%c", state); 677 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 678 PS_ADD("pgrp", "%d", p->p_pgid); 679 PS_ADD("session", "%d", p->p_session->s_sid); 680 PROC_UNLOCK(p); 681 PS_ADD("tty", "%d", kp.ki_tdev); 682 PS_ADD("tpgid", "%d", kp.ki_tpgid); 683 PS_ADD("flags", "%u", 0); /* XXX */ 684 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 685 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 686 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 687 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 688 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 689 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 690 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 691 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 692 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 693 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 694 PS_ADD("0", "%d", 0); /* removed field */ 695 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 696 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 697 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 698 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 699 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 700 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 701 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 702 PS_ADD("startstack", "%u", 0); /* XXX */ 703 PS_ADD("kstkesp", "%u", 0); /* XXX */ 704 PS_ADD("kstkeip", "%u", 0); /* XXX */ 705 PS_ADD("signal", "%u", 0); /* XXX */ 706 PS_ADD("blocked", "%u", 0); /* XXX */ 707 PS_ADD("sigignore", "%u", 0); /* XXX */ 708 PS_ADD("sigcatch", "%u", 0); /* XXX */ 709 PS_ADD("wchan", "%u", 0); /* XXX */ 710 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 711 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 712 PS_ADD("exitsignal", "%d", 0); /* XXX */ 713 PS_ADD("processor", "%u", kp.ki_lastcpu); 714 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 715 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 716 #undef PS_ADD 717 sbuf_putc(sb, '\n'); 718 719 return (0); 720 } 721 722 /* 723 * Filler function for proc/pid/statm 724 */ 725 static int 726 linprocfs_doprocstatm(PFS_FILL_ARGS) 727 { 728 struct kinfo_proc kp; 729 segsz_t lsize; 730 731 PROC_LOCK(p); 732 fill_kinfo_proc(p, &kp); 733 PROC_UNLOCK(p); 734 735 /* 736 * See comments in linprocfs_doprocstatus() regarding the 737 * computation of lsize. 738 */ 739 /* size resident share trs drs lrs dt */ 740 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 741 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 742 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 743 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 744 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 745 lsize = B2P(kp.ki_size) - kp.ki_dsize - 746 kp.ki_ssize - kp.ki_tsize - 1; 747 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 748 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 749 750 return (0); 751 } 752 753 /* 754 * Filler function for proc/pid/status 755 */ 756 static int 757 linprocfs_doprocstatus(PFS_FILL_ARGS) 758 { 759 struct kinfo_proc kp; 760 char *state; 761 segsz_t lsize; 762 struct thread *td2; 763 struct sigacts *ps; 764 int i; 765 766 PROC_LOCK(p); 767 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 768 769 if (P_SHOULDSTOP(p)) { 770 state = "T (stopped)"; 771 } else { 772 switch(p->p_state) { 773 case PRS_NEW: 774 state = "I (idle)"; 775 break; 776 case PRS_NORMAL: 777 if (p->p_flag & P_WEXIT) { 778 state = "X (exiting)"; 779 break; 780 } 781 switch(td2->td_state) { 782 case TDS_INHIBITED: 783 state = "S (sleeping)"; 784 break; 785 case TDS_RUNQ: 786 case TDS_RUNNING: 787 state = "R (running)"; 788 break; 789 default: 790 state = "? (unknown)"; 791 break; 792 } 793 break; 794 case PRS_ZOMBIE: 795 state = "Z (zombie)"; 796 break; 797 default: 798 state = "? (unknown)"; 799 break; 800 } 801 } 802 803 fill_kinfo_proc(p, &kp); 804 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 805 sbuf_printf(sb, "State:\t%s\n", state); 806 807 /* 808 * Credentials 809 */ 810 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 811 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 812 p->p_pptr->p_pid : 0); 813 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 814 p->p_ucred->cr_uid, 815 p->p_ucred->cr_svuid, 816 /* FreeBSD doesn't have fsuid */ 817 p->p_ucred->cr_uid); 818 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 819 p->p_ucred->cr_gid, 820 p->p_ucred->cr_svgid, 821 /* FreeBSD doesn't have fsgid */ 822 p->p_ucred->cr_gid); 823 sbuf_cat(sb, "Groups:\t"); 824 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 825 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 826 PROC_UNLOCK(p); 827 sbuf_putc(sb, '\n'); 828 829 /* 830 * Memory 831 * 832 * While our approximation of VmLib may not be accurate (I 833 * don't know of a simple way to verify it, and I'm not sure 834 * it has much meaning anyway), I believe it's good enough. 835 * 836 * The same code that could (I think) accurately compute VmLib 837 * could also compute VmLck, but I don't really care enough to 838 * implement it. Submissions are welcome. 839 */ 840 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 841 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 842 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 843 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 844 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 845 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 846 lsize = B2P(kp.ki_size) - kp.ki_dsize - 847 kp.ki_ssize - kp.ki_tsize - 1; 848 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 849 850 /* 851 * Signal masks 852 * 853 * We support up to 128 signals, while Linux supports 32, 854 * but we only define 32 (the same 32 as Linux, to boot), so 855 * just show the lower 32 bits of each mask. XXX hack. 856 * 857 * NB: on certain platforms (Sparc at least) Linux actually 858 * supports 64 signals, but this code is a long way from 859 * running on anything but i386, so ignore that for now. 860 */ 861 PROC_LOCK(p); 862 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 863 /* 864 * I can't seem to find out where the signal mask is in 865 * relation to struct proc, so SigBlk is left unimplemented. 866 */ 867 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 868 ps = p->p_sigacts; 869 mtx_lock(&ps->ps_mtx); 870 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 871 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 872 mtx_unlock(&ps->ps_mtx); 873 PROC_UNLOCK(p); 874 875 /* 876 * Linux also prints the capability masks, but we don't have 877 * capabilities yet, and when we do get them they're likely to 878 * be meaningless to Linux programs, so we lie. XXX 879 */ 880 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 881 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 882 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 883 884 return (0); 885 } 886 887 888 /* 889 * Filler function for proc/pid/cwd 890 */ 891 static int 892 linprocfs_doproccwd(PFS_FILL_ARGS) 893 { 894 char *fullpath = "unknown"; 895 char *freepath = NULL; 896 897 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 898 sbuf_printf(sb, "%s", fullpath); 899 if (freepath) 900 free(freepath, M_TEMP); 901 return (0); 902 } 903 904 /* 905 * Filler function for proc/pid/root 906 */ 907 static int 908 linprocfs_doprocroot(PFS_FILL_ARGS) 909 { 910 struct vnode *rvp; 911 char *fullpath = "unknown"; 912 char *freepath = NULL; 913 914 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 915 vn_fullpath(td, rvp, &fullpath, &freepath); 916 sbuf_printf(sb, "%s", fullpath); 917 if (freepath) 918 free(freepath, M_TEMP); 919 return (0); 920 } 921 922 /* 923 * Filler function for proc/pid/cmdline 924 */ 925 static int 926 linprocfs_doproccmdline(PFS_FILL_ARGS) 927 { 928 int ret; 929 930 PROC_LOCK(p); 931 if ((ret = p_cansee(td, p)) != 0) { 932 PROC_UNLOCK(p); 933 return (ret); 934 } 935 936 /* 937 * Mimic linux behavior and pass only processes with usermode 938 * address space as valid. Return zero silently otherwize. 939 */ 940 if (p->p_vmspace == &vmspace0) { 941 PROC_UNLOCK(p); 942 return (0); 943 } 944 if (p->p_args != NULL) { 945 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 946 PROC_UNLOCK(p); 947 return (0); 948 } 949 950 if ((p->p_flag & P_SYSTEM) != 0) { 951 PROC_UNLOCK(p); 952 return (0); 953 } 954 955 PROC_UNLOCK(p); 956 957 ret = proc_getargv(td, p, sb, ARG_MAX); 958 return (ret); 959 } 960 961 /* 962 * Filler function for proc/pid/environ 963 */ 964 static int 965 linprocfs_doprocenviron(PFS_FILL_ARGS) 966 { 967 int ret; 968 969 PROC_LOCK(p); 970 if ((ret = p_candebug(td, p)) != 0) { 971 PROC_UNLOCK(p); 972 return (ret); 973 } 974 975 /* 976 * Mimic linux behavior and pass only processes with usermode 977 * address space as valid. Return zero silently otherwize. 978 */ 979 if (p->p_vmspace == &vmspace0) { 980 PROC_UNLOCK(p); 981 return (0); 982 } 983 984 if ((p->p_flag & P_SYSTEM) != 0) { 985 PROC_UNLOCK(p); 986 return (0); 987 } 988 989 PROC_UNLOCK(p); 990 991 ret = proc_getenvv(td, p, sb, ARG_MAX); 992 return (ret); 993 } 994 995 /* 996 * Filler function for proc/pid/maps 997 */ 998 static int 999 linprocfs_doprocmaps(PFS_FILL_ARGS) 1000 { 1001 struct vmspace *vm; 1002 vm_map_t map; 1003 vm_map_entry_t entry, tmp_entry; 1004 vm_object_t obj, tobj, lobj; 1005 vm_offset_t e_start, e_end; 1006 vm_ooffset_t off = 0; 1007 vm_prot_t e_prot; 1008 unsigned int last_timestamp; 1009 char *name = "", *freename = NULL; 1010 ino_t ino; 1011 int ref_count, shadow_count, flags; 1012 int error; 1013 struct vnode *vp; 1014 struct vattr vat; 1015 int locked; 1016 1017 PROC_LOCK(p); 1018 error = p_candebug(td, p); 1019 PROC_UNLOCK(p); 1020 if (error) 1021 return (error); 1022 1023 if (uio->uio_rw != UIO_READ) 1024 return (EOPNOTSUPP); 1025 1026 error = 0; 1027 vm = vmspace_acquire_ref(p); 1028 if (vm == NULL) 1029 return (ESRCH); 1030 map = &vm->vm_map; 1031 vm_map_lock_read(map); 1032 for (entry = map->header.next; entry != &map->header; 1033 entry = entry->next) { 1034 name = ""; 1035 freename = NULL; 1036 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1037 continue; 1038 e_prot = entry->protection; 1039 e_start = entry->start; 1040 e_end = entry->end; 1041 obj = entry->object.vm_object; 1042 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1043 VM_OBJECT_LOCK(tobj); 1044 if (lobj != obj) 1045 VM_OBJECT_UNLOCK(lobj); 1046 lobj = tobj; 1047 } 1048 last_timestamp = map->timestamp; 1049 vm_map_unlock_read(map); 1050 ino = 0; 1051 if (lobj) { 1052 off = IDX_TO_OFF(lobj->size); 1053 if (lobj->type == OBJT_VNODE) { 1054 vp = lobj->handle; 1055 if (vp) 1056 vref(vp); 1057 } 1058 else 1059 vp = NULL; 1060 if (lobj != obj) 1061 VM_OBJECT_UNLOCK(lobj); 1062 flags = obj->flags; 1063 ref_count = obj->ref_count; 1064 shadow_count = obj->shadow_count; 1065 VM_OBJECT_UNLOCK(obj); 1066 if (vp) { 1067 vn_fullpath(td, vp, &name, &freename); 1068 locked = VFS_LOCK_GIANT(vp->v_mount); 1069 vn_lock(vp, LK_SHARED | LK_RETRY); 1070 VOP_GETATTR(vp, &vat, td->td_ucred); 1071 ino = vat.va_fileid; 1072 vput(vp); 1073 VFS_UNLOCK_GIANT(locked); 1074 } 1075 } else { 1076 flags = 0; 1077 ref_count = 0; 1078 shadow_count = 0; 1079 } 1080 1081 /* 1082 * format: 1083 * start, end, access, offset, major, minor, inode, name. 1084 */ 1085 error = sbuf_printf(sb, 1086 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1087 (u_long)e_start, (u_long)e_end, 1088 (e_prot & VM_PROT_READ)?"r":"-", 1089 (e_prot & VM_PROT_WRITE)?"w":"-", 1090 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1091 "p", 1092 (u_long)off, 1093 0, 1094 0, 1095 (u_long)ino, 1096 *name ? " " : "", 1097 name 1098 ); 1099 if (freename) 1100 free(freename, M_TEMP); 1101 vm_map_lock_read(map); 1102 if (error == -1) { 1103 error = 0; 1104 break; 1105 } 1106 if (last_timestamp != map->timestamp) { 1107 /* 1108 * Look again for the entry because the map was 1109 * modified while it was unlocked. Specifically, 1110 * the entry may have been clipped, merged, or deleted. 1111 */ 1112 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1113 entry = tmp_entry; 1114 } 1115 } 1116 vm_map_unlock_read(map); 1117 vmspace_free(vm); 1118 1119 return (error); 1120 } 1121 1122 /* 1123 * Filler function for proc/net/dev 1124 */ 1125 static int 1126 linprocfs_donetdev(PFS_FILL_ARGS) 1127 { 1128 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1129 struct ifnet *ifp; 1130 1131 sbuf_printf(sb, "%6s|%58s|%s\n" 1132 "%6s|%58s|%58s\n", 1133 "Inter-", " Receive", " Transmit", 1134 " face", 1135 "bytes packets errs drop fifo frame compressed multicast", 1136 "bytes packets errs drop fifo colls carrier compressed"); 1137 1138 CURVNET_SET(TD_TO_VNET(curthread)); 1139 IFNET_RLOCK(); 1140 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1141 linux_ifname(ifp, ifname, sizeof ifname); 1142 sbuf_printf(sb, "%6.6s: ", ifname); 1143 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1144 ifp->if_ibytes, /* rx_bytes */ 1145 ifp->if_ipackets, /* rx_packets */ 1146 ifp->if_ierrors, /* rx_errors */ 1147 ifp->if_iqdrops, /* rx_dropped + 1148 * rx_missed_errors */ 1149 0UL, /* rx_fifo_errors */ 1150 0UL, /* rx_length_errors + 1151 * rx_over_errors + 1152 * rx_crc_errors + 1153 * rx_frame_errors */ 1154 0UL, /* rx_compressed */ 1155 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1156 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1157 ifp->if_obytes, /* tx_bytes */ 1158 ifp->if_opackets, /* tx_packets */ 1159 ifp->if_oerrors, /* tx_errors */ 1160 0UL, /* tx_dropped */ 1161 0UL, /* tx_fifo_errors */ 1162 ifp->if_collisions, /* collisions */ 1163 0UL, /* tx_carrier_errors + 1164 * tx_aborted_errors + 1165 * tx_window_errors + 1166 * tx_heartbeat_errors */ 1167 0UL); /* tx_compressed */ 1168 } 1169 IFNET_RUNLOCK(); 1170 CURVNET_RESTORE(); 1171 1172 return (0); 1173 } 1174 1175 /* 1176 * Filler function for proc/sys/kernel/osrelease 1177 */ 1178 static int 1179 linprocfs_doosrelease(PFS_FILL_ARGS) 1180 { 1181 char osrelease[LINUX_MAX_UTSNAME]; 1182 1183 linux_get_osrelease(td, osrelease); 1184 sbuf_printf(sb, "%s\n", osrelease); 1185 1186 return (0); 1187 } 1188 1189 /* 1190 * Filler function for proc/sys/kernel/ostype 1191 */ 1192 static int 1193 linprocfs_doostype(PFS_FILL_ARGS) 1194 { 1195 char osname[LINUX_MAX_UTSNAME]; 1196 1197 linux_get_osname(td, osname); 1198 sbuf_printf(sb, "%s\n", osname); 1199 1200 return (0); 1201 } 1202 1203 /* 1204 * Filler function for proc/sys/kernel/version 1205 */ 1206 static int 1207 linprocfs_doosbuild(PFS_FILL_ARGS) 1208 { 1209 1210 linprocfs_osbuild(td, sb); 1211 sbuf_cat(sb, "\n"); 1212 return (0); 1213 } 1214 1215 /* 1216 * Filler function for proc/sys/kernel/msgmni 1217 */ 1218 static int 1219 linprocfs_domsgmni(PFS_FILL_ARGS) 1220 { 1221 1222 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1223 return (0); 1224 } 1225 1226 /* 1227 * Filler function for proc/sys/kernel/pid_max 1228 */ 1229 static int 1230 linprocfs_dopid_max(PFS_FILL_ARGS) 1231 { 1232 1233 sbuf_printf(sb, "%i\n", PID_MAX); 1234 return (0); 1235 } 1236 1237 /* 1238 * Filler function for proc/sys/kernel/sem 1239 */ 1240 static int 1241 linprocfs_dosem(PFS_FILL_ARGS) 1242 { 1243 1244 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1245 seminfo.semopm, seminfo.semmni); 1246 return (0); 1247 } 1248 1249 /* 1250 * Filler function for proc/scsi/device_info 1251 */ 1252 static int 1253 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1254 { 1255 1256 return (0); 1257 } 1258 1259 /* 1260 * Filler function for proc/scsi/scsi 1261 */ 1262 static int 1263 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1264 { 1265 1266 return (0); 1267 } 1268 1269 extern struct cdevsw *cdevsw[]; 1270 1271 /* 1272 * Filler function for proc/devices 1273 */ 1274 static int 1275 linprocfs_dodevices(PFS_FILL_ARGS) 1276 { 1277 char *char_devices; 1278 sbuf_printf(sb, "Character devices:\n"); 1279 1280 char_devices = linux_get_char_devices(); 1281 sbuf_printf(sb, "%s", char_devices); 1282 linux_free_get_char_devices(char_devices); 1283 1284 sbuf_printf(sb, "\nBlock devices:\n"); 1285 1286 return (0); 1287 } 1288 1289 /* 1290 * Filler function for proc/cmdline 1291 */ 1292 static int 1293 linprocfs_docmdline(PFS_FILL_ARGS) 1294 { 1295 1296 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1297 sbuf_printf(sb, " ro root=302\n"); 1298 return (0); 1299 } 1300 1301 /* 1302 * Filler function for proc/filesystems 1303 */ 1304 static int 1305 linprocfs_dofilesystems(PFS_FILL_ARGS) 1306 { 1307 struct vfsconf *vfsp; 1308 1309 mtx_lock(&Giant); 1310 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1311 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1312 sbuf_printf(sb, "nodev"); 1313 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1314 } 1315 mtx_unlock(&Giant); 1316 return(0); 1317 } 1318 1319 #if 0 1320 /* 1321 * Filler function for proc/modules 1322 */ 1323 static int 1324 linprocfs_domodules(PFS_FILL_ARGS) 1325 { 1326 struct linker_file *lf; 1327 1328 TAILQ_FOREACH(lf, &linker_files, link) { 1329 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1330 (unsigned long)lf->size, lf->refs); 1331 } 1332 return (0); 1333 } 1334 #endif 1335 1336 /* 1337 * Filler function for proc/pid/fd 1338 */ 1339 static int 1340 linprocfs_dofdescfs(PFS_FILL_ARGS) 1341 { 1342 1343 if (p == curproc) 1344 sbuf_printf(sb, "/dev/fd"); 1345 else 1346 sbuf_printf(sb, "unknown"); 1347 return (0); 1348 } 1349 1350 /* 1351 * Constructor 1352 */ 1353 static int 1354 linprocfs_init(PFS_INIT_ARGS) 1355 { 1356 struct pfs_node *root; 1357 struct pfs_node *dir; 1358 1359 root = pi->pi_root; 1360 1361 /* /proc/... */ 1362 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1363 NULL, NULL, NULL, PFS_RD); 1364 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1365 NULL, NULL, NULL, PFS_RD); 1366 pfs_create_file(root, "devices", &linprocfs_dodevices, 1367 NULL, NULL, NULL, PFS_RD); 1368 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1369 NULL, NULL, NULL, PFS_RD); 1370 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1371 NULL, NULL, NULL, PFS_RD); 1372 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1373 NULL, NULL, NULL, PFS_RD); 1374 #if 0 1375 pfs_create_file(root, "modules", &linprocfs_domodules, 1376 NULL, NULL, NULL, PFS_RD); 1377 #endif 1378 pfs_create_file(root, "mounts", &linprocfs_domtab, 1379 NULL, NULL, NULL, PFS_RD); 1380 pfs_create_file(root, "mtab", &linprocfs_domtab, 1381 NULL, NULL, NULL, PFS_RD); 1382 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1383 NULL, NULL, NULL, PFS_RD); 1384 pfs_create_link(root, "self", &procfs_docurproc, 1385 NULL, NULL, NULL, 0); 1386 pfs_create_file(root, "stat", &linprocfs_dostat, 1387 NULL, NULL, NULL, PFS_RD); 1388 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1389 NULL, NULL, NULL, PFS_RD); 1390 pfs_create_file(root, "uptime", &linprocfs_douptime, 1391 NULL, NULL, NULL, PFS_RD); 1392 pfs_create_file(root, "version", &linprocfs_doversion, 1393 NULL, NULL, NULL, PFS_RD); 1394 1395 /* /proc/net/... */ 1396 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1397 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1398 NULL, NULL, NULL, PFS_RD); 1399 1400 /* /proc/<pid>/... */ 1401 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1402 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1403 NULL, NULL, NULL, PFS_RD); 1404 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1405 NULL, NULL, NULL, 0); 1406 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1407 NULL, NULL, NULL, PFS_RD); 1408 pfs_create_link(dir, "exe", &procfs_doprocfile, 1409 NULL, &procfs_notsystem, NULL, 0); 1410 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1411 NULL, NULL, NULL, PFS_RD); 1412 pfs_create_file(dir, "mem", &procfs_doprocmem, 1413 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1414 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1415 NULL, NULL, NULL, 0); 1416 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1417 NULL, NULL, NULL, PFS_RD); 1418 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1419 NULL, NULL, NULL, PFS_RD); 1420 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1421 NULL, NULL, NULL, PFS_RD); 1422 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1423 NULL, NULL, NULL, 0); 1424 1425 /* /proc/scsi/... */ 1426 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1427 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1428 NULL, NULL, NULL, PFS_RD); 1429 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1430 NULL, NULL, NULL, PFS_RD); 1431 1432 /* /proc/sys/... */ 1433 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1434 /* /proc/sys/kernel/... */ 1435 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1436 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1437 NULL, NULL, NULL, PFS_RD); 1438 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1439 NULL, NULL, NULL, PFS_RD); 1440 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1441 NULL, NULL, NULL, PFS_RD); 1442 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1443 NULL, NULL, NULL, PFS_RD); 1444 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1445 NULL, NULL, NULL, PFS_RD); 1446 pfs_create_file(dir, "sem", &linprocfs_dosem, 1447 NULL, NULL, NULL, PFS_RD); 1448 1449 return (0); 1450 } 1451 1452 /* 1453 * Destructor 1454 */ 1455 static int 1456 linprocfs_uninit(PFS_INIT_ARGS) 1457 { 1458 1459 /* nothing to do, pseudofs will GC */ 1460 return (0); 1461 } 1462 1463 PSEUDOFS(linprocfs, 1); 1464 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1465 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1466 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1467 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1468