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