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