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