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