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 * $FreeBSD$ 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/blist.h> 47 #include <sys/conf.h> 48 #include <sys/dkstat.h> 49 #include <sys/jail.h> 50 #include <sys/kernel.h> 51 #include <sys/lock.h> 52 #include <sys/malloc.h> 53 #include <sys/mount.h> 54 #include <sys/mutex.h> 55 #include <sys/proc.h> 56 #include <sys/resourcevar.h> 57 #include <sys/sbuf.h> 58 #include <sys/sysctl.h> 59 #include <sys/tty.h> 60 #include <sys/vnode.h> 61 62 #include <vm/vm.h> 63 #include <vm/pmap.h> 64 #include <vm/vm_map.h> 65 #include <vm/vm_param.h> 66 #include <vm/vm_object.h> 67 #include <vm/vm_zone.h> 68 #include <vm/swap_pager.h> 69 70 #include <sys/exec.h> 71 #include <sys/user.h> 72 #include <sys/vmmeter.h> 73 74 #include <machine/clock.h> 75 76 #ifdef __alpha__ 77 #include <machine/alpha_cpu.h> 78 #include <machine/cpuconf.h> 79 #include <machine/rpb.h> 80 extern int ncpus; 81 #endif /* __alpha__ */ 82 83 #ifdef __i386__ 84 #include <machine/cputypes.h> 85 #include <machine/md_var.h> 86 #endif /* __i386__ */ 87 88 #include <sys/socket.h> 89 #include <net/if.h> 90 91 #include <compat/linux/linux_mib.h> 92 #include <fs/pseudofs/pseudofs.h> 93 94 extern struct cdevsw *cdevsw[]; 95 96 /* 97 * Various conversion macros 98 */ 99 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 100 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 101 #define B2K(x) ((x) >> 10) /* bytes to kbytes */ 102 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 103 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 104 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 105 106 /* 107 * Filler function for proc/meminfo 108 */ 109 static int 110 linprocfs_domeminfo(PFS_FILL_ARGS) 111 { 112 unsigned long memtotal; /* total memory in bytes */ 113 unsigned long memused; /* used memory in bytes */ 114 unsigned long memfree; /* free memory in bytes */ 115 unsigned long memshared; /* shared memory ??? */ 116 unsigned long buffers, cached; /* buffer / cache memory ??? */ 117 u_quad_t swaptotal; /* total swap space in bytes */ 118 u_quad_t swapused; /* used swap space in bytes */ 119 u_quad_t swapfree; /* free swap space in bytes */ 120 vm_object_t object; 121 122 memtotal = physmem * PAGE_SIZE; 123 /* 124 * The correct thing here would be: 125 * 126 memfree = cnt.v_free_count * PAGE_SIZE; 127 memused = memtotal - memfree; 128 * 129 * but it might mislead linux binaries into thinking there 130 * is very little memory left, so we cheat and tell them that 131 * all memory that isn't wired down is free. 132 */ 133 memused = cnt.v_wire_count * PAGE_SIZE; 134 memfree = memtotal - memused; 135 if (swapblist == NULL) { 136 swaptotal = 0; 137 swapfree = 0; 138 } else { 139 swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */ 140 swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 141 } 142 swapused = swaptotal - swapfree; 143 memshared = 0; 144 TAILQ_FOREACH(object, &vm_object_list, object_list) 145 if (object->shadow_count > 1) 146 memshared += object->resident_page_count; 147 memshared *= PAGE_SIZE; 148 /* 149 * We'd love to be able to write: 150 * 151 buffers = bufspace; 152 * 153 * but bufspace is internal to vfs_bio.c and we don't feel 154 * like unstaticizing it just for linprocfs's sake. 155 */ 156 buffers = 0; 157 cached = cnt.v_cache_count * PAGE_SIZE; 158 159 sbuf_printf(sb, 160 " total: used: free: shared: buffers: cached:\n" 161 "Mem: %lu %lu %lu %lu %lu %lu\n" 162 "Swap: %llu %llu %llu\n" 163 "MemTotal: %9lu kB\n" 164 "MemFree: %9lu kB\n" 165 "MemShared:%9lu kB\n" 166 "Buffers: %9lu kB\n" 167 "Cached: %9lu kB\n" 168 "SwapTotal:%9llu kB\n" 169 "SwapFree: %9llu kB\n", 170 memtotal, memused, memfree, memshared, buffers, cached, 171 swaptotal, swapused, swapfree, 172 B2K(memtotal), B2K(memfree), 173 B2K(memshared), B2K(buffers), B2K(cached), 174 B2K(swaptotal), B2K(swapfree)); 175 176 return (0); 177 } 178 179 #ifdef __alpha__ 180 /* 181 * Filler function for proc/cpuinfo (Alpha version) 182 */ 183 static int 184 linprocfs_docpuinfo(PFS_FILL_ARGS) 185 { 186 u_int64_t type, major; 187 struct pcs *pcsp; 188 const char *model, *sysname; 189 190 static const char *cpuname[] = { 191 "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", 192 "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" 193 }; 194 195 pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 196 type = pcsp->pcs_proc_type; 197 major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; 198 if (major < sizeof(cpuname)/sizeof(char *)) { 199 model = cpuname[major - 1]; 200 } else { 201 model = "unknown"; 202 } 203 204 sysname = alpha_dsr_sysname(); 205 206 sbuf_printf(sb, 207 "cpu\t\t\t: Alpha\n" 208 "cpu model\t\t: %s\n" 209 "cpu variation\t\t: %ld\n" 210 "cpu revision\t\t: %ld\n" 211 "cpu serial number\t: %s\n" 212 "system type\t\t: %s\n" 213 "system variation\t: %s\n" 214 "system revision\t\t: %ld\n" 215 "system serial number\t: %s\n" 216 "cycle frequency [Hz]\t: %lu\n" 217 "timer frequency [Hz]\t: %lu\n" 218 "page size [bytes]\t: %ld\n" 219 "phys. address bits\t: %ld\n" 220 "max. addr. space #\t: %ld\n" 221 "BogoMIPS\t\t: %lu.%02lu\n" 222 "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 223 "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 224 "platform string\t\t: %s\n" 225 "cpus detected\t\t: %d\n" 226 , 227 model, 228 pcsp->pcs_proc_var, 229 *(int *)hwrpb->rpb_revision, 230 " ", 231 " ", 232 "0", 233 0, 234 " ", 235 hwrpb->rpb_cc_freq, 236 hz, 237 hwrpb->rpb_page_size, 238 hwrpb->rpb_phys_addr_size, 239 hwrpb->rpb_max_asn, 240 0, 0, 241 0, 0, 0, 242 0, 0, 0, 243 sysname, 244 ncpus); 245 return (0); 246 } 247 #endif /* __alpha__ */ 248 249 #ifdef __i386__ 250 /* 251 * Filler function for proc/cpuinfo (i386 version) 252 */ 253 static int 254 linprocfs_docpuinfo(PFS_FILL_ARGS) 255 { 256 int class, i, fqmhz, fqkhz; 257 258 /* 259 * We default the flags to include all non-conflicting flags, 260 * and the Intel versions of conflicting flags. 261 */ 262 static char *flags[] = { 263 "fpu", "vme", "de", "pse", "tsc", 264 "msr", "pae", "mce", "cx8", "apic", 265 "sep", "sep", "mtrr", "pge", "mca", 266 "cmov", "pat", "pse36", "pn", "b19", 267 "b20", "b21", "mmxext", "mmx", "fxsr", 268 "xmm", "b26", "b27", "b28", "b29", 269 "3dnowext", "3dnow" 270 }; 271 272 switch (cpu_class) { 273 case CPUCLASS_286: 274 class = 2; 275 break; 276 case CPUCLASS_386: 277 class = 3; 278 break; 279 case CPUCLASS_486: 280 class = 4; 281 break; 282 case CPUCLASS_586: 283 class = 5; 284 break; 285 case CPUCLASS_686: 286 class = 6; 287 break; 288 default: 289 class = 0; 290 break; 291 } 292 293 sbuf_printf(sb, 294 "processor\t: %d\n" 295 "vendor_id\t: %.20s\n" 296 "cpu family\t: %d\n" 297 "model\t\t: %d\n" 298 "stepping\t: %d\n", 299 0, cpu_vendor, class, cpu, cpu_id & 0xf); 300 301 sbuf_cat(sb, 302 "flags\t\t:"); 303 304 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 305 flags[16] = "fcmov"; 306 } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 307 flags[24] = "cxmmx"; 308 } 309 310 for (i = 0; i < 32; i++) 311 if (cpu_feature & (1 << i)) 312 sbuf_printf(sb, " %s", flags[i]); 313 sbuf_cat(sb, "\n"); 314 if (class >= 5) { 315 fqmhz = (tsc_freq + 4999) / 1000000; 316 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 317 sbuf_printf(sb, 318 "cpu MHz\t\t: %d.%02d\n" 319 "bogomips\t: %d.%02d\n", 320 fqmhz, fqkhz, fqmhz, fqkhz); 321 } 322 323 return (0); 324 } 325 #endif /* __i386__ */ 326 327 /* 328 * Filler function for proc/stat 329 */ 330 static int 331 linprocfs_dostat(PFS_FILL_ARGS) 332 { 333 sbuf_printf(sb, 334 "cpu %ld %ld %ld %ld\n" 335 "disk 0 0 0 0\n" 336 "page %u %u\n" 337 "swap %u %u\n" 338 "intr %u\n" 339 "ctxt %u\n" 340 "btime %ld\n", 341 T2J(cp_time[CP_USER]), 342 T2J(cp_time[CP_NICE]), 343 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 344 T2J(cp_time[CP_IDLE]), 345 cnt.v_vnodepgsin, 346 cnt.v_vnodepgsout, 347 cnt.v_swappgsin, 348 cnt.v_swappgsout, 349 cnt.v_intr, 350 cnt.v_swtch, 351 boottime.tv_sec); 352 return (0); 353 } 354 355 /* 356 * Filler function for proc/uptime 357 */ 358 static int 359 linprocfs_douptime(PFS_FILL_ARGS) 360 { 361 struct timeval tv; 362 363 getmicrouptime(&tv); 364 sbuf_printf(sb, "%ld.%02ld %ld.%02ld\n", 365 tv.tv_sec, tv.tv_usec / 10000, 366 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 367 return (0); 368 } 369 370 /* 371 * Filler function for proc/version 372 */ 373 static int 374 linprocfs_doversion(PFS_FILL_ARGS) 375 { 376 sbuf_printf(sb, 377 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 378 " #4 Sun Dec 18 04:30:00 CET 1977\n", 379 linux_get_osname(curp), 380 linux_get_osrelease(curp)); 381 return (0); 382 } 383 384 /* 385 * Filler function for proc/loadavg 386 */ 387 static int 388 linprocfs_doloadavg(PFS_FILL_ARGS) 389 { 390 sbuf_printf(sb, 391 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 392 (int)(averunnable.ldavg[0] / averunnable.fscale), 393 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 394 (int)(averunnable.ldavg[1] / averunnable.fscale), 395 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 396 (int)(averunnable.ldavg[2] / averunnable.fscale), 397 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 398 1, /* number of running tasks */ 399 nprocs, /* number of tasks */ 400 lastpid /* the last pid */ 401 ); 402 403 return (0); 404 } 405 406 /* 407 * Filler function for proc/pid/stat 408 */ 409 static int 410 linprocfs_doprocstat(PFS_FILL_ARGS) 411 { 412 struct kinfo_proc kp; 413 414 fill_kinfo_proc(p, &kp); 415 sbuf_printf(sb, "%d", p->p_pid); 416 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 417 PS_ADD("comm", "(%s)", p->p_comm); 418 PS_ADD("statr", "%c", '0'); /* XXX */ 419 PROC_LOCK(p); 420 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 421 PROC_UNLOCK(p); 422 PS_ADD("pgrp", "%d", p->p_pgid); 423 PS_ADD("session", "%d", p->p_session->s_sid); 424 PS_ADD("tty", "%d", 0); /* XXX */ 425 PS_ADD("tpgid", "%d", 0); /* XXX */ 426 PS_ADD("flags", "%u", 0); /* XXX */ 427 PS_ADD("minflt", "%u", 0); /* XXX */ 428 PS_ADD("cminflt", "%u", 0); /* XXX */ 429 PS_ADD("majflt", "%u", 0); /* XXX */ 430 PS_ADD("cminflt", "%u", 0); /* XXX */ 431 PS_ADD("utime", "%d", 0); /* XXX */ 432 PS_ADD("stime", "%d", 0); /* XXX */ 433 PS_ADD("cutime", "%d", 0); /* XXX */ 434 PS_ADD("cstime", "%d", 0); /* XXX */ 435 PS_ADD("counter", "%d", 0); /* XXX */ 436 PS_ADD("priority", "%d", 0); /* XXX */ 437 PS_ADD("timeout", "%u", 0); /* XXX */ 438 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 439 PS_ADD("starttime", "%d", 0); /* XXX */ 440 PS_ADD("vsize", "%u", kp.ki_size); 441 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 442 PS_ADD("rlim", "%u", 0); /* XXX */ 443 PS_ADD("startcode", "%u", (unsigned)0); 444 PS_ADD("endcode", "%u", 0); /* XXX */ 445 PS_ADD("startstack", "%u", 0); /* XXX */ 446 PS_ADD("esp", "%u", 0); /* XXX */ 447 PS_ADD("eip", "%u", 0); /* XXX */ 448 PS_ADD("signal", "%d", 0); /* XXX */ 449 PS_ADD("blocked", "%d", 0); /* XXX */ 450 PS_ADD("sigignore", "%d", 0); /* XXX */ 451 PS_ADD("sigcatch", "%d", 0); /* XXX */ 452 PS_ADD("wchan", "%u", 0); /* XXX */ 453 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 454 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 455 PS_ADD("exitsignal", "%d", 0); /* XXX */ 456 PS_ADD("processor", "%d", 0); /* XXX */ 457 #undef PS_ADD 458 sbuf_putc(sb, '\n'); 459 460 return (0); 461 } 462 463 /* 464 * Map process state to descriptive letter. Note that this does not 465 * quite correspond to what Linux outputs, but it's close enough. 466 */ 467 static char *state_str[] = { 468 "? (unknown)", 469 "I (idle)", 470 "R (running)", 471 "S (sleeping)", 472 "T (stopped)", 473 "Z (zombie)", 474 "W (waiting)", 475 "M (mutex)" 476 }; 477 478 /* 479 * Filler function for proc/pid/status 480 */ 481 static int 482 linprocfs_doprocstatus(PFS_FILL_ARGS) 483 { 484 struct kinfo_proc kp; 485 char *state; 486 segsz_t lsize; 487 int i; 488 489 mtx_lock_spin(&sched_lock); 490 if (p->p_stat > sizeof state_str / sizeof *state_str) 491 state = state_str[0]; 492 else 493 state = state_str[(int)p->p_stat]; 494 mtx_unlock_spin(&sched_lock); 495 496 fill_kinfo_proc(p, &kp); 497 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 498 sbuf_printf(sb, "State:\t%s\n", state); 499 500 /* 501 * Credentials 502 */ 503 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 504 PROC_LOCK(p); 505 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 506 p->p_pptr->p_pid : 0); 507 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 508 p->p_ucred->cr_uid, 509 p->p_ucred->cr_svuid, 510 /* FreeBSD doesn't have fsuid */ 511 p->p_ucred->cr_uid); 512 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 513 p->p_ucred->cr_gid, 514 p->p_ucred->cr_svgid, 515 /* FreeBSD doesn't have fsgid */ 516 p->p_ucred->cr_gid); 517 sbuf_cat(sb, "Groups:\t"); 518 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 519 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 520 PROC_UNLOCK(p); 521 sbuf_putc(sb, '\n'); 522 523 /* 524 * Memory 525 * 526 * While our approximation of VmLib may not be accurate (I 527 * don't know of a simple way to verify it, and I'm not sure 528 * it has much meaning anyway), I believe it's good enough. 529 * 530 * The same code that could (I think) accurately compute VmLib 531 * could also compute VmLck, but I don't really care enough to 532 * implement it. Submissions are welcome. 533 */ 534 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 535 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 536 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 537 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 538 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 539 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 540 lsize = B2P(kp.ki_size) - kp.ki_dsize - 541 kp.ki_ssize - kp.ki_tsize - 1; 542 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 543 544 /* 545 * Signal masks 546 * 547 * We support up to 128 signals, while Linux supports 32, 548 * but we only define 32 (the same 32 as Linux, to boot), so 549 * just show the lower 32 bits of each mask. XXX hack. 550 * 551 * NB: on certain platforms (Sparc at least) Linux actually 552 * supports 64 signals, but this code is a long way from 553 * running on anything but i386, so ignore that for now. 554 */ 555 PROC_LOCK(p); 556 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 557 /* 558 * I can't seem to find out where the signal mask is in 559 * relation to struct proc, so SigBlk is left unimplemented. 560 */ 561 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 562 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 563 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 564 PROC_UNLOCK(p); 565 566 /* 567 * Linux also prints the capability masks, but we don't have 568 * capabilities yet, and when we do get them they're likely to 569 * be meaningless to Linux programs, so we lie. XXX 570 */ 571 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 572 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 573 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 574 575 return (0); 576 } 577 578 /* 579 * Filler function for proc/self 580 */ 581 static int 582 linprocfs_doselflink(PFS_FILL_ARGS) 583 { 584 sbuf_printf(sb, "%ld", (long)curp->p_pid); 585 return (0); 586 } 587 588 /* 589 * Filler function for proc/pid/cmdline 590 */ 591 static int 592 linprocfs_doproccmdline(PFS_FILL_ARGS) 593 { 594 struct ps_strings pstr; 595 int error, i; 596 597 /* 598 * If we are using the ps/cmdline caching, use that. Otherwise 599 * revert back to the old way which only implements full cmdline 600 * for the currept process and just p->p_comm for all other 601 * processes. 602 * Note that if the argv is no longer available, we deliberately 603 * don't fall back on p->p_comm or return an error: the authentic 604 * Linux behaviour is to return zero-length in this case. 605 */ 606 607 if (p->p_args && (ps_argsopen || !p_cansee(curp, p))) { 608 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 609 } else if (p != curp) { 610 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 611 } else { 612 error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); 613 if (error) 614 return (error); 615 for (i = 0; i < pstr.ps_nargvstr; i++) { 616 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 617 sbuf_printf(sb, "%c", '\0'); 618 } 619 } 620 621 return (0); 622 } 623 624 /* 625 * Filler function for proc/pid/exe 626 */ 627 static int 628 linprocfs_doexelink(PFS_FILL_ARGS) 629 { 630 char *fullpath = "unknown"; 631 char *freepath = NULL; 632 633 textvp_fullpath(p, &fullpath, &freepath); 634 sbuf_printf(sb, "%s", fullpath); 635 if (freepath) 636 free(freepath, M_TEMP); 637 return (0); 638 } 639 640 /* 641 * Filler function for proc/net/dev 642 */ 643 static int 644 linprocfs_donetdev(PFS_FILL_ARGS) 645 { 646 struct ifnet *ifp; 647 int eth_index = 0; 648 649 sbuf_printf(sb, 650 "Inter-| Receive " 651 " | Transmit\n" 652 " face |bytes packets errs drop fifo frame compressed " 653 "multicast|bytes packets errs drop fifo colls carrier " 654 "compressed\n"); 655 656 TAILQ_FOREACH(ifp, &ifnet, if_link) { 657 if (strcmp(ifp->if_name, "lo") == 0) { 658 sbuf_printf(sb, "%6.6s:", ifp->if_name); 659 } else { 660 sbuf_printf(sb, "%5.5s%d:", "eth", eth_index); 661 eth_index++; 662 } 663 sbuf_printf(sb, 664 "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " 665 "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 666 0, 0, 0, 0, 0, 0, 0, 0, 667 0, 0, 0, 0, 0, 0, 0, 0); 668 } 669 670 return (0); 671 } 672 673 /* 674 * Filler function for proc/devices 675 */ 676 static int 677 linprocfs_dodevices(PFS_FILL_ARGS) 678 { 679 int i; 680 681 sbuf_printf(sb, "Character devices:\n"); 682 683 for (i = 0; i < NUMCDEVSW; i++) 684 if (cdevsw[i] != NULL) 685 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 686 687 sbuf_printf(sb, "\nBlock devices:\n"); 688 689 return (0); 690 } 691 692 /* 693 * Filler function for proc/cmdline 694 */ 695 static int 696 linprocfs_docmdline(PFS_FILL_ARGS) 697 { 698 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 699 sbuf_printf(sb, " ro root=302\n"); 700 return (0); 701 } 702 703 /* 704 * Directory structure 705 */ 706 707 static struct pfs_node linprocfs_proc_nodes[] = { 708 PFS_THIS, 709 PFS_PARENT, 710 /* name flags uid gid mode data */ 711 PFS_FILE( "cmdline", 0, 0, 0, 0444, linprocfs_doproccmdline), 712 PFS_SYMLINK("exe", 0, 0, 0, 0444, linprocfs_doexelink), 713 /* PFS_FILE( "mem", 0, 0, 0, 0444, procfs_domem), */ 714 PFS_FILE( "stat", 0, 0, 0, 0444, linprocfs_doprocstat), 715 PFS_FILE( "status", 0, 0, 0, 0444, linprocfs_doprocstatus), 716 PFS_LASTNODE 717 }; 718 719 static struct pfs_node linprocfs_net_nodes[] = { 720 PFS_THIS, 721 PFS_PARENT, 722 /* name flags uid gid mode data */ 723 PFS_FILE( "dev", 0, 0, 0, 0444, linprocfs_donetdev), 724 PFS_LASTNODE 725 }; 726 727 static struct pfs_node linprocfs_root_nodes[] = { 728 PFS_THIS, 729 PFS_PARENT, 730 /* name flags uid gid mode data */ 731 PFS_FILE( "cmdline", 0, 0, 0, 0444, linprocfs_docmdline), 732 PFS_FILE( "cpuinfo", 0, 0, 0, 0444, linprocfs_docpuinfo), 733 PFS_FILE( "devices", 0, 0, 0, 0444, linprocfs_dodevices), 734 PFS_FILE( "loadavg", 0, 0, 0, 0444, linprocfs_doloadavg), 735 PFS_FILE( "meminfo", 0, 0, 0, 0444, linprocfs_domeminfo), 736 PFS_FILE( "stat", 0, 0, 0, 0444, linprocfs_dostat), 737 PFS_FILE( "uptime", 0, 0, 0, 0444, linprocfs_douptime), 738 PFS_FILE( "version", 0, 0, 0, 0444, linprocfs_doversion), 739 PFS_DIR( "net", 0, 0, 0, 0555, linprocfs_net_nodes), 740 PFS_PROCDIR( 0, 0, 0, 0555, linprocfs_proc_nodes), 741 PFS_SYMLINK("self", 0, 0, 0, 0555, linprocfs_doselflink), 742 PFS_LASTNODE 743 }; 744 745 static struct pfs_node linprocfs_root = 746 PFS_ROOT(linprocfs_root_nodes); 747 748 PSEUDOFS(linprocfs, linprocfs_root); 749 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 750 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 751