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