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