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