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