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