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/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> 85 extern 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 */ 113 static int 114 linprocfs_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 */ 187 static int 188 linprocfs_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 */ 257 static int 258 linprocfs_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 */ 337 static int 338 linprocfs_domtab(PFS_FILL_ARGS) 339 { 340 struct nameidata nd; 341 struct mount *mp; 342 char *lep, *flep, *mntto, *mntfrom, *fstype; 343 size_t lep_len; 344 int error; 345 346 /* resolve symlinks etc. in the emulation tree prefix */ 347 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 348 flep = NULL; 349 if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1) 350 lep = linux_emul_path; 351 lep_len = strlen(lep); 352 353 mtx_lock(&mountlist_mtx); 354 error = 0; 355 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 356 error = VFS_STATFS(mp, &mp->mnt_stat, td); 357 if (error) 358 break; 359 360 /* determine device name */ 361 mntfrom = mp->mnt_stat.f_mntfromname; 362 363 /* determine mount point */ 364 mntto = mp->mnt_stat.f_mntonname; 365 if (strncmp(mntto, lep, lep_len) == 0 && 366 mntto[lep_len] == '/') 367 mntto += lep_len; 368 369 /* determine fs type */ 370 fstype = mp->mnt_stat.f_fstypename; 371 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 372 mntfrom = fstype = "proc"; 373 else if (strcmp(fstype, "procfs") == 0) 374 continue; 375 376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 377 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 378 #define ADD_OPTION(opt, name) \ 379 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 380 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 381 ADD_OPTION(MNT_NOEXEC, "noexec"); 382 ADD_OPTION(MNT_NOSUID, "nosuid"); 383 ADD_OPTION(MNT_NODEV, "nodev"); 384 ADD_OPTION(MNT_UNION, "union"); 385 ADD_OPTION(MNT_ASYNC, "async"); 386 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 387 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 388 ADD_OPTION(MNT_NOATIME, "noatime"); 389 #undef ADD_OPTION 390 /* a real Linux mtab will also show NFS options */ 391 sbuf_printf(sb, " 0 0\n"); 392 } 393 mtx_unlock(&mountlist_mtx); 394 if (flep != NULL) 395 free(flep, M_TEMP); 396 return (error); 397 } 398 399 /* 400 * Filler function for proc/stat 401 */ 402 static int 403 linprocfs_dostat(PFS_FILL_ARGS) 404 { 405 sbuf_printf(sb, 406 "cpu %ld %ld %ld %ld\n" 407 "disk 0 0 0 0\n" 408 "page %u %u\n" 409 "swap %u %u\n" 410 "intr %u\n" 411 "ctxt %u\n" 412 "btime %lld\n", 413 T2J(cp_time[CP_USER]), 414 T2J(cp_time[CP_NICE]), 415 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 416 T2J(cp_time[CP_IDLE]), 417 cnt.v_vnodepgsin, 418 cnt.v_vnodepgsout, 419 cnt.v_swappgsin, 420 cnt.v_swappgsout, 421 cnt.v_intr, 422 cnt.v_swtch, 423 (quad_t)boottime.tv_sec); 424 return (0); 425 } 426 427 /* 428 * Filler function for proc/uptime 429 */ 430 static int 431 linprocfs_douptime(PFS_FILL_ARGS) 432 { 433 struct timeval tv; 434 435 getmicrouptime(&tv); 436 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 437 (quad_t)tv.tv_sec, tv.tv_usec / 10000, 438 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 439 return (0); 440 } 441 442 /* 443 * Filler function for proc/version 444 */ 445 static int 446 linprocfs_doversion(PFS_FILL_ARGS) 447 { 448 char osname[LINUX_MAX_UTSNAME]; 449 char osrelease[LINUX_MAX_UTSNAME]; 450 451 linux_get_osname(td->td_proc, osname); 452 linux_get_osrelease(td->td_proc, osrelease); 453 454 sbuf_printf(sb, 455 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 456 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 457 return (0); 458 } 459 460 /* 461 * Filler function for proc/loadavg 462 */ 463 static int 464 linprocfs_doloadavg(PFS_FILL_ARGS) 465 { 466 sbuf_printf(sb, 467 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 468 (int)(averunnable.ldavg[0] / averunnable.fscale), 469 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 470 (int)(averunnable.ldavg[1] / averunnable.fscale), 471 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 472 (int)(averunnable.ldavg[2] / averunnable.fscale), 473 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 474 1, /* number of running tasks */ 475 nprocs, /* number of tasks */ 476 lastpid /* the last pid */ 477 ); 478 479 return (0); 480 } 481 482 /* 483 * Filler function for proc/pid/stat 484 */ 485 static int 486 linprocfs_doprocstat(PFS_FILL_ARGS) 487 { 488 struct kinfo_proc kp; 489 490 fill_kinfo_proc(p, &kp); 491 sbuf_printf(sb, "%d", p->p_pid); 492 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 493 PS_ADD("comm", "(%s)", p->p_comm); 494 PS_ADD("statr", "%c", '0'); /* XXX */ 495 PROC_LOCK(p); 496 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 497 PROC_UNLOCK(p); 498 PS_ADD("pgrp", "%d", p->p_pgid); 499 PS_ADD("session", "%d", p->p_session->s_sid); 500 PS_ADD("tty", "%d", 0); /* XXX */ 501 PS_ADD("tpgid", "%d", 0); /* XXX */ 502 PS_ADD("flags", "%u", 0); /* XXX */ 503 PS_ADD("minflt", "%u", 0); /* XXX */ 504 PS_ADD("cminflt", "%u", 0); /* XXX */ 505 PS_ADD("majflt", "%u", 0); /* XXX */ 506 PS_ADD("cminflt", "%u", 0); /* XXX */ 507 PS_ADD("utime", "%d", 0); /* XXX */ 508 PS_ADD("stime", "%d", 0); /* XXX */ 509 PS_ADD("cutime", "%d", 0); /* XXX */ 510 PS_ADD("cstime", "%d", 0); /* XXX */ 511 PS_ADD("counter", "%d", 0); /* XXX */ 512 PS_ADD("priority", "%d", 0); /* XXX */ 513 PS_ADD("timeout", "%u", 0); /* XXX */ 514 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 515 PS_ADD("starttime", "%d", 0); /* XXX */ 516 PS_ADD("vsize", "%u", kp.ki_size); 517 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 518 PS_ADD("rlim", "%u", 0); /* XXX */ 519 PS_ADD("startcode", "%u", (unsigned)0); 520 PS_ADD("endcode", "%u", 0); /* XXX */ 521 PS_ADD("startstack", "%u", 0); /* XXX */ 522 PS_ADD("esp", "%u", 0); /* XXX */ 523 PS_ADD("eip", "%u", 0); /* XXX */ 524 PS_ADD("signal", "%d", 0); /* XXX */ 525 PS_ADD("blocked", "%d", 0); /* XXX */ 526 PS_ADD("sigignore", "%d", 0); /* XXX */ 527 PS_ADD("sigcatch", "%d", 0); /* XXX */ 528 PS_ADD("wchan", "%u", 0); /* XXX */ 529 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 530 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 531 PS_ADD("exitsignal", "%d", 0); /* XXX */ 532 PS_ADD("processor", "%d", 0); /* XXX */ 533 #undef PS_ADD 534 sbuf_putc(sb, '\n'); 535 536 return (0); 537 } 538 539 /* 540 * Map process state to descriptive letter. Note that this does not 541 * quite correspond to what Linux outputs, but it's close enough. 542 */ 543 static char *state_str[] = { 544 "? (unknown)", 545 "I (idle)", 546 "R (running)", 547 "S (sleeping)", 548 "T (stopped)", 549 "Z (zombie)", 550 "W (waiting)", 551 "M (mutex)" 552 }; 553 554 /* 555 * Filler function for proc/pid/status 556 */ 557 static int 558 linprocfs_doprocstatus(PFS_FILL_ARGS) 559 { 560 struct kinfo_proc kp; 561 char *state; 562 segsz_t lsize; 563 int i; 564 565 mtx_lock_spin(&sched_lock); 566 if (p->p_stat > sizeof state_str / sizeof *state_str) 567 state = state_str[0]; 568 else 569 state = state_str[(int)p->p_stat]; 570 mtx_unlock_spin(&sched_lock); 571 572 fill_kinfo_proc(p, &kp); 573 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 574 sbuf_printf(sb, "State:\t%s\n", state); 575 576 /* 577 * Credentials 578 */ 579 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 580 PROC_LOCK(p); 581 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 582 p->p_pptr->p_pid : 0); 583 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 584 p->p_ucred->cr_uid, 585 p->p_ucred->cr_svuid, 586 /* FreeBSD doesn't have fsuid */ 587 p->p_ucred->cr_uid); 588 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 589 p->p_ucred->cr_gid, 590 p->p_ucred->cr_svgid, 591 /* FreeBSD doesn't have fsgid */ 592 p->p_ucred->cr_gid); 593 sbuf_cat(sb, "Groups:\t"); 594 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 595 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 596 PROC_UNLOCK(p); 597 sbuf_putc(sb, '\n'); 598 599 /* 600 * Memory 601 * 602 * While our approximation of VmLib may not be accurate (I 603 * don't know of a simple way to verify it, and I'm not sure 604 * it has much meaning anyway), I believe it's good enough. 605 * 606 * The same code that could (I think) accurately compute VmLib 607 * could also compute VmLck, but I don't really care enough to 608 * implement it. Submissions are welcome. 609 */ 610 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 611 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 612 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 613 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 614 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 615 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 616 lsize = B2P(kp.ki_size) - kp.ki_dsize - 617 kp.ki_ssize - kp.ki_tsize - 1; 618 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 619 620 /* 621 * Signal masks 622 * 623 * We support up to 128 signals, while Linux supports 32, 624 * but we only define 32 (the same 32 as Linux, to boot), so 625 * just show the lower 32 bits of each mask. XXX hack. 626 * 627 * NB: on certain platforms (Sparc at least) Linux actually 628 * supports 64 signals, but this code is a long way from 629 * running on anything but i386, so ignore that for now. 630 */ 631 PROC_LOCK(p); 632 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 633 /* 634 * I can't seem to find out where the signal mask is in 635 * relation to struct proc, so SigBlk is left unimplemented. 636 */ 637 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 638 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 639 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 640 PROC_UNLOCK(p); 641 642 /* 643 * Linux also prints the capability masks, but we don't have 644 * capabilities yet, and when we do get them they're likely to 645 * be meaningless to Linux programs, so we lie. XXX 646 */ 647 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 648 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 649 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 650 651 return (0); 652 } 653 654 /* 655 * Filler function for proc/pid/cmdline 656 */ 657 static int 658 linprocfs_doproccmdline(PFS_FILL_ARGS) 659 { 660 struct ps_strings pstr; 661 int error, i; 662 663 /* 664 * If we are using the ps/cmdline caching, use that. Otherwise 665 * revert back to the old way which only implements full cmdline 666 * for the currept process and just p->p_comm for all other 667 * processes. 668 * Note that if the argv is no longer available, we deliberately 669 * don't fall back on p->p_comm or return an error: the authentic 670 * Linux behaviour is to return zero-length in this case. 671 */ 672 673 if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) { 674 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 675 } else if (p != td->td_proc) { 676 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 677 } else { 678 error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); 679 if (error) 680 return (error); 681 for (i = 0; i < pstr.ps_nargvstr; i++) { 682 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 683 sbuf_printf(sb, "%c", '\0'); 684 } 685 } 686 687 return (0); 688 } 689 690 /* 691 * Filler function for proc/net/dev 692 */ 693 static int 694 linprocfs_donetdev(PFS_FILL_ARGS) 695 { 696 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 697 struct ifnet *ifp; 698 699 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 700 "Inter-", " Receive", " Transmit", " face", 701 "bytes packets errs drop fifo frame compressed", 702 "bytes packets errs drop fifo frame compressed"); 703 704 TAILQ_FOREACH(ifp, &ifnet, if_link) { 705 linux_ifname(ifp, ifname, sizeof ifname); 706 sbuf_printf(sb, "%6.6s:", ifname); 707 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 708 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 709 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 710 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 711 } 712 713 return (0); 714 } 715 716 #if 0 717 extern struct cdevsw *cdevsw[]; 718 719 /* 720 * Filler function for proc/devices 721 */ 722 static int 723 linprocfs_dodevices(PFS_FILL_ARGS) 724 { 725 int i; 726 727 sbuf_printf(sb, "Character devices:\n"); 728 729 for (i = 0; i < NUMCDEVSW; i++) 730 if (cdevsw[i] != NULL) 731 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 732 733 sbuf_printf(sb, "\nBlock devices:\n"); 734 735 return (0); 736 } 737 #endif 738 739 /* 740 * Filler function for proc/cmdline 741 */ 742 static int 743 linprocfs_docmdline(PFS_FILL_ARGS) 744 { 745 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 746 sbuf_printf(sb, " ro root=302\n"); 747 return (0); 748 } 749 750 #if 0 751 /* 752 * Filler function for proc/modules 753 */ 754 static int 755 linprocfs_domodules(PFS_FILL_ARGS) 756 { 757 struct linker_file *lf; 758 759 TAILQ_FOREACH(lf, &linker_files, link) { 760 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 761 (unsigned long)lf->size, lf->refs); 762 } 763 return (0); 764 } 765 #endif 766 767 /* 768 * Constructor 769 */ 770 static int 771 linprocfs_init(PFS_INIT_ARGS) 772 { 773 struct pfs_node *root; 774 struct pfs_node *dir; 775 776 root = pi->pi_root; 777 778 #define PFS_CREATE_FILE(name) \ 779 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 780 PFS_CREATE_FILE(cmdline); 781 PFS_CREATE_FILE(cpuinfo); 782 #if 0 783 PFS_CREATE_FILE(devices); 784 #endif 785 PFS_CREATE_FILE(loadavg); 786 PFS_CREATE_FILE(meminfo); 787 #if 0 788 PFS_CREATE_FILE(modules); 789 #endif 790 PFS_CREATE_FILE(mtab); 791 PFS_CREATE_FILE(stat); 792 PFS_CREATE_FILE(uptime); 793 PFS_CREATE_FILE(version); 794 #undef PFS_CREATE_FILE 795 pfs_create_link(root, "self", &procfs_docurproc, 796 NULL, NULL, 0); 797 798 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 799 pfs_create_file(dir, "dev", &linprocfs_donetdev, 800 NULL, NULL, PFS_RD); 801 802 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 803 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 804 NULL, NULL, PFS_RD); 805 pfs_create_link(dir, "exe", &procfs_doprocfile, 806 NULL, &procfs_notsystem, 0); 807 pfs_create_file(dir, "mem", &procfs_doprocmem, 808 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 809 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 810 NULL, NULL, PFS_RD); 811 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 812 NULL, NULL, PFS_RD); 813 814 return (0); 815 } 816 817 /* 818 * Destructor 819 */ 820 static int 821 linprocfs_uninit(PFS_INIT_ARGS) 822 { 823 824 /* nothing to do, pseudofs will GC */ 825 return (0); 826 } 827 828 PSEUDOFS(linprocfs, 1); 829 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 830 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 831