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