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