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