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