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