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