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