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/vimage.h> 77 #include <sys/bus.h> 78 79 #include <net/if.h> 80 #include <net/route.h> 81 #include <net/vnet.h> 82 83 #include <vm/vm.h> 84 #include <vm/vm_extern.h> 85 #include <vm/pmap.h> 86 #include <vm/vm_map.h> 87 #include <vm/vm_param.h> 88 #include <vm/vm_object.h> 89 #include <vm/swap_pager.h> 90 91 #include <machine/clock.h> 92 93 #include <geom/geom.h> 94 #include <geom/geom_int.h> 95 96 #if defined(__i386__) || defined(__amd64__) 97 #include <machine/cputypes.h> 98 #include <machine/md_var.h> 99 #endif /* __i386__ || __amd64__ */ 100 101 #ifdef COMPAT_LINUX32 /* XXX */ 102 #include <machine/../linux32/linux.h> 103 #else 104 #include <machine/../linux/linux.h> 105 #endif 106 #include <compat/linux/linux_ioctl.h> 107 #include <compat/linux/linux_mib.h> 108 #include <compat/linux/linux_util.h> 109 #include <fs/pseudofs/pseudofs.h> 110 #include <fs/procfs/procfs.h> 111 112 /* 113 * Various conversion macros 114 */ 115 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 116 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 117 #define B2K(x) ((x) >> 10) /* bytes to kbytes */ 118 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 119 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 120 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 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", 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 for (i = 0; i <= mp_maxid; ++i) { 472 if (CPU_ABSENT(i)) 473 continue; 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 cnt.v_vnodepgsin, 490 cnt.v_vnodepgsout, 491 cnt.v_swappgsin, 492 cnt.v_swappgsout, 493 cnt.v_intr, 494 cnt.v_swtch, 495 (long long)boottime.tv_sec); 496 return (0); 497 } 498 499 /* 500 * Filler function for proc/uptime 501 */ 502 static int 503 linprocfs_douptime(PFS_FILL_ARGS) 504 { 505 long cp_time[CPUSTATES]; 506 struct timeval tv; 507 508 getmicrouptime(&tv); 509 read_cpu_time(cp_time); 510 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 511 (long long)tv.tv_sec, tv.tv_usec / 10000, 512 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 513 return (0); 514 } 515 516 /* 517 * Get OS build date 518 */ 519 static void 520 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 521 { 522 #if 0 523 char osbuild[256]; 524 char *cp1, *cp2; 525 526 strncpy(osbuild, version, 256); 527 osbuild[255] = '\0'; 528 cp1 = strstr(osbuild, "\n"); 529 cp2 = strstr(osbuild, ":"); 530 if (cp1 && cp2) { 531 *cp1 = *cp2 = '\0'; 532 cp1 = strstr(osbuild, "#"); 533 } else 534 cp1 = NULL; 535 if (cp1) 536 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 537 else 538 #endif 539 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 540 } 541 542 /* 543 * Get OS builder 544 */ 545 static void 546 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 547 { 548 #if 0 549 char builder[256]; 550 char *cp; 551 552 cp = strstr(version, "\n "); 553 if (cp) { 554 strncpy(builder, cp + 5, 256); 555 builder[255] = '\0'; 556 cp = strstr(builder, ":"); 557 if (cp) 558 *cp = '\0'; 559 } 560 if (cp) 561 sbuf_cat(sb, builder); 562 else 563 #endif 564 sbuf_cat(sb, "des@freebsd.org"); 565 } 566 567 /* 568 * Filler function for proc/version 569 */ 570 static int 571 linprocfs_doversion(PFS_FILL_ARGS) 572 { 573 char osname[LINUX_MAX_UTSNAME]; 574 char osrelease[LINUX_MAX_UTSNAME]; 575 576 linux_get_osname(td, osname); 577 linux_get_osrelease(td, osrelease); 578 sbuf_printf(sb, "%s version %s (", osname, osrelease); 579 linprocfs_osbuilder(td, sb); 580 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 581 linprocfs_osbuild(td, sb); 582 sbuf_cat(sb, "\n"); 583 584 return (0); 585 } 586 587 /* 588 * Filler function for proc/loadavg 589 */ 590 static int 591 linprocfs_doloadavg(PFS_FILL_ARGS) 592 { 593 594 sbuf_printf(sb, 595 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 596 (int)(averunnable.ldavg[0] / averunnable.fscale), 597 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 598 (int)(averunnable.ldavg[1] / averunnable.fscale), 599 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 600 (int)(averunnable.ldavg[2] / averunnable.fscale), 601 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 602 1, /* number of running tasks */ 603 nprocs, /* number of tasks */ 604 lastpid /* the last pid */ 605 ); 606 return (0); 607 } 608 609 /* 610 * Filler function for proc/pid/stat 611 */ 612 static int 613 linprocfs_doprocstat(PFS_FILL_ARGS) 614 { 615 struct kinfo_proc kp; 616 char state; 617 static int ratelimit = 0; 618 619 PROC_LOCK(p); 620 fill_kinfo_proc(p, &kp); 621 sbuf_printf(sb, "%d", p->p_pid); 622 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 623 PS_ADD("comm", "(%s)", p->p_comm); 624 if (kp.ki_stat > sizeof(linux_state)) { 625 state = 'R'; 626 627 if (ratelimit == 0) { 628 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 629 kp.ki_stat, sizeof(linux_state)); 630 ++ratelimit; 631 } 632 } else 633 state = linux_state[kp.ki_stat - 1]; 634 PS_ADD("state", "%c", state); 635 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 636 PS_ADD("pgrp", "%d", p->p_pgid); 637 PS_ADD("session", "%d", p->p_session->s_sid); 638 PROC_UNLOCK(p); 639 PS_ADD("tty", "%d", 0); /* XXX */ 640 PS_ADD("tpgid", "%d", kp.ki_tpgid); 641 PS_ADD("flags", "%u", 0); /* XXX */ 642 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 643 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 644 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 645 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 646 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 647 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 648 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 649 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 650 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 651 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 652 PS_ADD("0", "%d", 0); /* removed field */ 653 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 654 /* XXX: starttime is not right, it is the _same_ for _every_ process. 655 It should be the number of jiffies between system boot and process 656 start. */ 657 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 658 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 659 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 660 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 661 PS_ADD("startcode", "%u", (unsigned)0); 662 PS_ADD("endcode", "%u", 0); /* XXX */ 663 PS_ADD("startstack", "%u", 0); /* XXX */ 664 PS_ADD("kstkesp", "%u", 0); /* XXX */ 665 PS_ADD("kstkeip", "%u", 0); /* XXX */ 666 PS_ADD("signal", "%u", 0); /* XXX */ 667 PS_ADD("blocked", "%u", 0); /* XXX */ 668 PS_ADD("sigignore", "%u", 0); /* XXX */ 669 PS_ADD("sigcatch", "%u", 0); /* XXX */ 670 PS_ADD("wchan", "%u", 0); /* XXX */ 671 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 672 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 673 PS_ADD("exitsignal", "%d", 0); /* XXX */ 674 PS_ADD("processor", "%u", kp.ki_lastcpu); 675 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 676 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 677 #undef PS_ADD 678 sbuf_putc(sb, '\n'); 679 680 return (0); 681 } 682 683 /* 684 * Filler function for proc/pid/statm 685 */ 686 static int 687 linprocfs_doprocstatm(PFS_FILL_ARGS) 688 { 689 struct kinfo_proc kp; 690 segsz_t lsize; 691 692 PROC_LOCK(p); 693 fill_kinfo_proc(p, &kp); 694 PROC_UNLOCK(p); 695 696 /* 697 * See comments in linprocfs_doprocstatus() regarding the 698 * computation of lsize. 699 */ 700 /* size resident share trs drs lrs dt */ 701 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 702 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 703 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 704 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 705 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 706 lsize = B2P(kp.ki_size) - kp.ki_dsize - 707 kp.ki_ssize - kp.ki_tsize - 1; 708 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 709 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 710 711 return (0); 712 } 713 714 /* 715 * Filler function for proc/pid/status 716 */ 717 static int 718 linprocfs_doprocstatus(PFS_FILL_ARGS) 719 { 720 struct kinfo_proc kp; 721 char *state; 722 segsz_t lsize; 723 struct thread *td2; 724 struct sigacts *ps; 725 int i; 726 727 PROC_LOCK(p); 728 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 729 730 if (P_SHOULDSTOP(p)) { 731 state = "T (stopped)"; 732 } else { 733 PROC_SLOCK(p); 734 switch(p->p_state) { 735 case PRS_NEW: 736 state = "I (idle)"; 737 break; 738 case PRS_NORMAL: 739 if (p->p_flag & P_WEXIT) { 740 state = "X (exiting)"; 741 break; 742 } 743 switch(td2->td_state) { 744 case TDS_INHIBITED: 745 state = "S (sleeping)"; 746 break; 747 case TDS_RUNQ: 748 case TDS_RUNNING: 749 state = "R (running)"; 750 break; 751 default: 752 state = "? (unknown)"; 753 break; 754 } 755 break; 756 case PRS_ZOMBIE: 757 state = "Z (zombie)"; 758 break; 759 default: 760 state = "? (unknown)"; 761 break; 762 } 763 PROC_SUNLOCK(p); 764 } 765 766 fill_kinfo_proc(p, &kp); 767 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 768 sbuf_printf(sb, "State:\t%s\n", state); 769 770 /* 771 * Credentials 772 */ 773 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 774 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 775 p->p_pptr->p_pid : 0); 776 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 777 p->p_ucred->cr_uid, 778 p->p_ucred->cr_svuid, 779 /* FreeBSD doesn't have fsuid */ 780 p->p_ucred->cr_uid); 781 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 782 p->p_ucred->cr_gid, 783 p->p_ucred->cr_svgid, 784 /* FreeBSD doesn't have fsgid */ 785 p->p_ucred->cr_gid); 786 sbuf_cat(sb, "Groups:\t"); 787 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 788 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 789 PROC_UNLOCK(p); 790 sbuf_putc(sb, '\n'); 791 792 /* 793 * Memory 794 * 795 * While our approximation of VmLib may not be accurate (I 796 * don't know of a simple way to verify it, and I'm not sure 797 * it has much meaning anyway), I believe it's good enough. 798 * 799 * The same code that could (I think) accurately compute VmLib 800 * could also compute VmLck, but I don't really care enough to 801 * implement it. Submissions are welcome. 802 */ 803 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 804 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 805 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 806 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 807 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 808 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 809 lsize = B2P(kp.ki_size) - kp.ki_dsize - 810 kp.ki_ssize - kp.ki_tsize - 1; 811 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 812 813 /* 814 * Signal masks 815 * 816 * We support up to 128 signals, while Linux supports 32, 817 * but we only define 32 (the same 32 as Linux, to boot), so 818 * just show the lower 32 bits of each mask. XXX hack. 819 * 820 * NB: on certain platforms (Sparc at least) Linux actually 821 * supports 64 signals, but this code is a long way from 822 * running on anything but i386, so ignore that for now. 823 */ 824 PROC_LOCK(p); 825 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 826 /* 827 * I can't seem to find out where the signal mask is in 828 * relation to struct proc, so SigBlk is left unimplemented. 829 */ 830 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 831 ps = p->p_sigacts; 832 mtx_lock(&ps->ps_mtx); 833 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 834 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 835 mtx_unlock(&ps->ps_mtx); 836 PROC_UNLOCK(p); 837 838 /* 839 * Linux also prints the capability masks, but we don't have 840 * capabilities yet, and when we do get them they're likely to 841 * be meaningless to Linux programs, so we lie. XXX 842 */ 843 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 844 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 845 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 846 847 return (0); 848 } 849 850 851 /* 852 * Filler function for proc/pid/cwd 853 */ 854 static int 855 linprocfs_doproccwd(PFS_FILL_ARGS) 856 { 857 char *fullpath = "unknown"; 858 char *freepath = NULL; 859 860 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 861 sbuf_printf(sb, "%s", fullpath); 862 if (freepath) 863 free(freepath, M_TEMP); 864 return (0); 865 } 866 867 /* 868 * Filler function for proc/pid/root 869 */ 870 static int 871 linprocfs_doprocroot(PFS_FILL_ARGS) 872 { 873 struct vnode *rvp; 874 char *fullpath = "unknown"; 875 char *freepath = NULL; 876 877 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 878 vn_fullpath(td, rvp, &fullpath, &freepath); 879 sbuf_printf(sb, "%s", fullpath); 880 if (freepath) 881 free(freepath, M_TEMP); 882 return (0); 883 } 884 885 /* 886 * Filler function for proc/pid/cmdline 887 */ 888 static int 889 linprocfs_doproccmdline(PFS_FILL_ARGS) 890 { 891 struct ps_strings pstr; 892 char **ps_argvstr; 893 int error, i; 894 895 /* 896 * If we are using the ps/cmdline caching, use that. Otherwise 897 * revert back to the old way which only implements full cmdline 898 * for the currept process and just p->p_comm for all other 899 * processes. 900 * Note that if the argv is no longer available, we deliberately 901 * don't fall back on p->p_comm or return an error: the authentic 902 * Linux behaviour is to return zero-length in this case. 903 */ 904 905 PROC_LOCK(p); 906 if (p->p_args && p_cansee(td, p) == 0) { 907 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 908 PROC_UNLOCK(p); 909 } else if (p != td->td_proc) { 910 PROC_UNLOCK(p); 911 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 912 } else { 913 PROC_UNLOCK(p); 914 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 915 sizeof(pstr)); 916 if (error) 917 return (error); 918 if (pstr.ps_nargvstr > ARG_MAX) 919 return (E2BIG); 920 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 921 M_TEMP, M_WAITOK); 922 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 923 pstr.ps_nargvstr * sizeof(char *)); 924 if (error) { 925 free(ps_argvstr, M_TEMP); 926 return (error); 927 } 928 for (i = 0; i < pstr.ps_nargvstr; i++) { 929 sbuf_copyin(sb, ps_argvstr[i], 0); 930 sbuf_printf(sb, "%c", '\0'); 931 } 932 free(ps_argvstr, M_TEMP); 933 } 934 935 return (0); 936 } 937 938 /* 939 * Filler function for proc/pid/environ 940 */ 941 static int 942 linprocfs_doprocenviron(PFS_FILL_ARGS) 943 { 944 945 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 946 return (0); 947 } 948 949 /* 950 * Filler function for proc/pid/maps 951 */ 952 static int 953 linprocfs_doprocmaps(PFS_FILL_ARGS) 954 { 955 struct vmspace *vm; 956 vm_map_t map; 957 vm_map_entry_t entry, tmp_entry; 958 vm_object_t obj, tobj, lobj; 959 vm_offset_t e_start, e_end; 960 vm_ooffset_t off = 0; 961 vm_prot_t e_prot; 962 unsigned int last_timestamp; 963 char *name = "", *freename = NULL; 964 ino_t ino; 965 int ref_count, shadow_count, flags; 966 int error; 967 struct vnode *vp; 968 struct vattr vat; 969 int locked; 970 971 PROC_LOCK(p); 972 error = p_candebug(td, p); 973 PROC_UNLOCK(p); 974 if (error) 975 return (error); 976 977 if (uio->uio_rw != UIO_READ) 978 return (EOPNOTSUPP); 979 980 error = 0; 981 vm = vmspace_acquire_ref(p); 982 if (vm == NULL) 983 return (ESRCH); 984 map = &vm->vm_map; 985 vm_map_lock_read(map); 986 for (entry = map->header.next; entry != &map->header; 987 entry = entry->next) { 988 name = ""; 989 freename = NULL; 990 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 991 continue; 992 e_prot = entry->protection; 993 e_start = entry->start; 994 e_end = entry->end; 995 obj = entry->object.vm_object; 996 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 997 VM_OBJECT_LOCK(tobj); 998 if (lobj != obj) 999 VM_OBJECT_UNLOCK(lobj); 1000 lobj = tobj; 1001 } 1002 last_timestamp = map->timestamp; 1003 vm_map_unlock_read(map); 1004 ino = 0; 1005 if (lobj) { 1006 off = IDX_TO_OFF(lobj->size); 1007 if (lobj->type == OBJT_VNODE) { 1008 vp = lobj->handle; 1009 if (vp) 1010 vref(vp); 1011 } 1012 else 1013 vp = NULL; 1014 if (lobj != obj) 1015 VM_OBJECT_UNLOCK(lobj); 1016 flags = obj->flags; 1017 ref_count = obj->ref_count; 1018 shadow_count = obj->shadow_count; 1019 VM_OBJECT_UNLOCK(obj); 1020 if (vp) { 1021 vn_fullpath(td, vp, &name, &freename); 1022 locked = VFS_LOCK_GIANT(vp->v_mount); 1023 vn_lock(vp, LK_SHARED | LK_RETRY); 1024 VOP_GETATTR(vp, &vat, td->td_ucred); 1025 ino = vat.va_fileid; 1026 vput(vp); 1027 VFS_UNLOCK_GIANT(locked); 1028 } 1029 } else { 1030 flags = 0; 1031 ref_count = 0; 1032 shadow_count = 0; 1033 } 1034 1035 /* 1036 * format: 1037 * start, end, access, offset, major, minor, inode, name. 1038 */ 1039 error = sbuf_printf(sb, 1040 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1041 (u_long)e_start, (u_long)e_end, 1042 (e_prot & VM_PROT_READ)?"r":"-", 1043 (e_prot & VM_PROT_WRITE)?"w":"-", 1044 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1045 "p", 1046 (u_long)off, 1047 0, 1048 0, 1049 (u_long)ino, 1050 *name ? " " : "", 1051 name 1052 ); 1053 if (freename) 1054 free(freename, M_TEMP); 1055 vm_map_lock_read(map); 1056 if (error == -1) { 1057 error = 0; 1058 break; 1059 } 1060 if (last_timestamp != map->timestamp) { 1061 /* 1062 * Look again for the entry because the map was 1063 * modified while it was unlocked. Specifically, 1064 * the entry may have been clipped, merged, or deleted. 1065 */ 1066 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1067 entry = tmp_entry; 1068 } 1069 } 1070 vm_map_unlock_read(map); 1071 vmspace_free(vm); 1072 1073 return (error); 1074 } 1075 1076 /* 1077 * Filler function for proc/net/dev 1078 */ 1079 static int 1080 linprocfs_donetdev(PFS_FILL_ARGS) 1081 { 1082 INIT_VNET_NET(TD_TO_VNET(td)); 1083 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1084 struct ifnet *ifp; 1085 1086 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 1087 "Inter-", " Receive", " Transmit", " face", 1088 "bytes packets errs drop fifo frame compressed", 1089 "bytes packets errs drop fifo frame compressed"); 1090 1091 IFNET_RLOCK(); 1092 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1093 linux_ifname(ifp, ifname, sizeof ifname); 1094 sbuf_printf(sb, "%6.6s:", ifname); 1095 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1096 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1097 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1098 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1099 } 1100 IFNET_RUNLOCK(); 1101 1102 return (0); 1103 } 1104 1105 /* 1106 * Filler function for proc/sys/kernel/osrelease 1107 */ 1108 static int 1109 linprocfs_doosrelease(PFS_FILL_ARGS) 1110 { 1111 char osrelease[LINUX_MAX_UTSNAME]; 1112 1113 linux_get_osrelease(td, osrelease); 1114 sbuf_printf(sb, "%s\n", osrelease); 1115 1116 return (0); 1117 } 1118 1119 /* 1120 * Filler function for proc/sys/kernel/ostype 1121 */ 1122 static int 1123 linprocfs_doostype(PFS_FILL_ARGS) 1124 { 1125 char osname[LINUX_MAX_UTSNAME]; 1126 1127 linux_get_osname(td, osname); 1128 sbuf_printf(sb, "%s\n", osname); 1129 1130 return (0); 1131 } 1132 1133 /* 1134 * Filler function for proc/sys/kernel/version 1135 */ 1136 static int 1137 linprocfs_doosbuild(PFS_FILL_ARGS) 1138 { 1139 1140 linprocfs_osbuild(td, sb); 1141 sbuf_cat(sb, "\n"); 1142 return (0); 1143 } 1144 1145 /* 1146 * Filler function for proc/sys/kernel/msgmni 1147 */ 1148 static int 1149 linprocfs_domsgmni(PFS_FILL_ARGS) 1150 { 1151 1152 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1153 return (0); 1154 } 1155 1156 /* 1157 * Filler function for proc/sys/kernel/pid_max 1158 */ 1159 static int 1160 linprocfs_dopid_max(PFS_FILL_ARGS) 1161 { 1162 1163 sbuf_printf(sb, "%i\n", PID_MAX); 1164 return (0); 1165 } 1166 1167 /* 1168 * Filler function for proc/sys/kernel/sem 1169 */ 1170 static int 1171 linprocfs_dosem(PFS_FILL_ARGS) 1172 { 1173 1174 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1175 seminfo.semopm, seminfo.semmni); 1176 return (0); 1177 } 1178 1179 /* 1180 * Filler function for proc/scsi/device_info 1181 */ 1182 static int 1183 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1184 { 1185 1186 return (0); 1187 } 1188 1189 /* 1190 * Filler function for proc/scsi/scsi 1191 */ 1192 static int 1193 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1194 { 1195 1196 return (0); 1197 } 1198 1199 extern struct cdevsw *cdevsw[]; 1200 1201 /* 1202 * Filler function for proc/devices 1203 */ 1204 static int 1205 linprocfs_dodevices(PFS_FILL_ARGS) 1206 { 1207 char *char_devices; 1208 sbuf_printf(sb, "Character devices:\n"); 1209 1210 char_devices = linux_get_char_devices(); 1211 sbuf_printf(sb, "%s", char_devices); 1212 linux_free_get_char_devices(char_devices); 1213 1214 sbuf_printf(sb, "\nBlock devices:\n"); 1215 1216 return (0); 1217 } 1218 1219 /* 1220 * Filler function for proc/cmdline 1221 */ 1222 static int 1223 linprocfs_docmdline(PFS_FILL_ARGS) 1224 { 1225 1226 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1227 sbuf_printf(sb, " ro root=302\n"); 1228 return (0); 1229 } 1230 1231 #if 0 1232 /* 1233 * Filler function for proc/modules 1234 */ 1235 static int 1236 linprocfs_domodules(PFS_FILL_ARGS) 1237 { 1238 struct linker_file *lf; 1239 1240 TAILQ_FOREACH(lf, &linker_files, link) { 1241 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1242 (unsigned long)lf->size, lf->refs); 1243 } 1244 return (0); 1245 } 1246 #endif 1247 1248 /* 1249 * Constructor 1250 */ 1251 static int 1252 linprocfs_init(PFS_INIT_ARGS) 1253 { 1254 struct pfs_node *root; 1255 struct pfs_node *dir; 1256 1257 root = pi->pi_root; 1258 1259 /* /proc/... */ 1260 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1261 NULL, NULL, NULL, PFS_RD); 1262 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1263 NULL, NULL, NULL, PFS_RD); 1264 pfs_create_file(root, "devices", &linprocfs_dodevices, 1265 NULL, NULL, NULL, PFS_RD); 1266 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1267 NULL, NULL, NULL, PFS_RD); 1268 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1269 NULL, NULL, NULL, PFS_RD); 1270 #if 0 1271 pfs_create_file(root, "modules", &linprocfs_domodules, 1272 NULL, NULL, NULL, PFS_RD); 1273 #endif 1274 pfs_create_file(root, "mounts", &linprocfs_domtab, 1275 NULL, NULL, NULL, PFS_RD); 1276 pfs_create_file(root, "mtab", &linprocfs_domtab, 1277 NULL, NULL, NULL, PFS_RD); 1278 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1279 NULL, NULL, NULL, PFS_RD); 1280 pfs_create_link(root, "self", &procfs_docurproc, 1281 NULL, NULL, NULL, 0); 1282 pfs_create_file(root, "stat", &linprocfs_dostat, 1283 NULL, NULL, NULL, PFS_RD); 1284 pfs_create_file(root, "uptime", &linprocfs_douptime, 1285 NULL, NULL, NULL, PFS_RD); 1286 pfs_create_file(root, "version", &linprocfs_doversion, 1287 NULL, NULL, NULL, PFS_RD); 1288 1289 /* /proc/net/... */ 1290 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1291 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1292 NULL, NULL, NULL, PFS_RD); 1293 1294 /* /proc/<pid>/... */ 1295 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1296 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1297 NULL, NULL, NULL, PFS_RD); 1298 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1299 NULL, NULL, NULL, 0); 1300 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1301 NULL, NULL, NULL, PFS_RD); 1302 pfs_create_link(dir, "exe", &procfs_doprocfile, 1303 NULL, &procfs_notsystem, NULL, 0); 1304 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1305 NULL, NULL, NULL, PFS_RD); 1306 pfs_create_file(dir, "mem", &procfs_doprocmem, 1307 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1308 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1309 NULL, NULL, NULL, 0); 1310 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1311 NULL, NULL, NULL, PFS_RD); 1312 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1313 NULL, NULL, NULL, PFS_RD); 1314 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1315 NULL, NULL, NULL, PFS_RD); 1316 1317 /* /proc/scsi/... */ 1318 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1319 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1320 NULL, NULL, NULL, PFS_RD); 1321 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1322 NULL, NULL, NULL, PFS_RD); 1323 1324 /* /proc/sys/... */ 1325 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1326 /* /proc/sys/kernel/... */ 1327 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1328 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1329 NULL, NULL, NULL, PFS_RD); 1330 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1331 NULL, NULL, NULL, PFS_RD); 1332 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1333 NULL, NULL, NULL, PFS_RD); 1334 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1335 NULL, NULL, NULL, PFS_RD); 1336 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1337 NULL, NULL, NULL, PFS_RD); 1338 pfs_create_file(dir, "sem", &linprocfs_dosem, 1339 NULL, NULL, NULL, PFS_RD); 1340 1341 return (0); 1342 } 1343 1344 /* 1345 * Destructor 1346 */ 1347 static int 1348 linprocfs_uninit(PFS_INIT_ARGS) 1349 { 1350 1351 /* nothing to do, pseudofs will GC */ 1352 return (0); 1353 } 1354 1355 PSEUDOFS(linprocfs, 1); 1356 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1357 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1358 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1359 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1360