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