linprocfs.c revision 85538
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 85538 2001-10-26 15:30:44Z phk $ 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 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 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 */ 186static int 187linprocfs_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 */ 256static int 257linprocfs_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 */ 336static int 337linprocfs_domtab(PFS_FILL_ARGS) 338{ 339 struct nameidata nd; 340 struct mount *mp; 341 char *lep, *flep, *mntto, *mntfrom, *fstype; 342 size_t lep_len; 343 int error; 344 345 /* resolve symlinks etc. in the emulation tree prefix */ 346 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 347 flep = NULL; 348 if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1) 349 lep = linux_emul_path; 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 %ld\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 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, "%ld.%02ld %ld.%02ld\n", 436 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 sbuf_printf(sb, 448 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 449 " #4 Sun Dec 18 04:30:00 CET 1977\n", 450 linux_get_osname(td->td_proc), 451 linux_get_osrelease(td->td_proc)); 452 return (0); 453} 454 455/* 456 * Filler function for proc/loadavg 457 */ 458static int 459linprocfs_doloadavg(PFS_FILL_ARGS) 460{ 461 sbuf_printf(sb, 462 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 463 (int)(averunnable.ldavg[0] / averunnable.fscale), 464 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 465 (int)(averunnable.ldavg[1] / averunnable.fscale), 466 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 467 (int)(averunnable.ldavg[2] / averunnable.fscale), 468 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 469 1, /* number of running tasks */ 470 nprocs, /* number of tasks */ 471 lastpid /* the last pid */ 472 ); 473 474 return (0); 475} 476 477/* 478 * Filler function for proc/pid/stat 479 */ 480static int 481linprocfs_doprocstat(PFS_FILL_ARGS) 482{ 483 struct kinfo_proc kp; 484 485 fill_kinfo_proc(p, &kp); 486 sbuf_printf(sb, "%d", p->p_pid); 487#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 488 PS_ADD("comm", "(%s)", p->p_comm); 489 PS_ADD("statr", "%c", '0'); /* XXX */ 490 PROC_LOCK(p); 491 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 492 PROC_UNLOCK(p); 493 PS_ADD("pgrp", "%d", p->p_pgid); 494 PS_ADD("session", "%d", p->p_session->s_sid); 495 PS_ADD("tty", "%d", 0); /* XXX */ 496 PS_ADD("tpgid", "%d", 0); /* XXX */ 497 PS_ADD("flags", "%u", 0); /* XXX */ 498 PS_ADD("minflt", "%u", 0); /* XXX */ 499 PS_ADD("cminflt", "%u", 0); /* XXX */ 500 PS_ADD("majflt", "%u", 0); /* XXX */ 501 PS_ADD("cminflt", "%u", 0); /* XXX */ 502 PS_ADD("utime", "%d", 0); /* XXX */ 503 PS_ADD("stime", "%d", 0); /* XXX */ 504 PS_ADD("cutime", "%d", 0); /* XXX */ 505 PS_ADD("cstime", "%d", 0); /* XXX */ 506 PS_ADD("counter", "%d", 0); /* XXX */ 507 PS_ADD("priority", "%d", 0); /* XXX */ 508 PS_ADD("timeout", "%u", 0); /* XXX */ 509 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 510 PS_ADD("starttime", "%d", 0); /* XXX */ 511 PS_ADD("vsize", "%u", kp.ki_size); 512 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 513 PS_ADD("rlim", "%u", 0); /* XXX */ 514 PS_ADD("startcode", "%u", (unsigned)0); 515 PS_ADD("endcode", "%u", 0); /* XXX */ 516 PS_ADD("startstack", "%u", 0); /* XXX */ 517 PS_ADD("esp", "%u", 0); /* XXX */ 518 PS_ADD("eip", "%u", 0); /* XXX */ 519 PS_ADD("signal", "%d", 0); /* XXX */ 520 PS_ADD("blocked", "%d", 0); /* XXX */ 521 PS_ADD("sigignore", "%d", 0); /* XXX */ 522 PS_ADD("sigcatch", "%d", 0); /* XXX */ 523 PS_ADD("wchan", "%u", 0); /* XXX */ 524 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 525 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 526 PS_ADD("exitsignal", "%d", 0); /* XXX */ 527 PS_ADD("processor", "%d", 0); /* XXX */ 528#undef PS_ADD 529 sbuf_putc(sb, '\n'); 530 531 return (0); 532} 533 534/* 535 * Map process state to descriptive letter. Note that this does not 536 * quite correspond to what Linux outputs, but it's close enough. 537 */ 538static char *state_str[] = { 539 "? (unknown)", 540 "I (idle)", 541 "R (running)", 542 "S (sleeping)", 543 "T (stopped)", 544 "Z (zombie)", 545 "W (waiting)", 546 "M (mutex)" 547}; 548 549/* 550 * Filler function for proc/pid/status 551 */ 552static int 553linprocfs_doprocstatus(PFS_FILL_ARGS) 554{ 555 struct kinfo_proc kp; 556 char *state; 557 segsz_t lsize; 558 int i; 559 560 mtx_lock_spin(&sched_lock); 561 if (p->p_stat > sizeof state_str / sizeof *state_str) 562 state = state_str[0]; 563 else 564 state = state_str[(int)p->p_stat]; 565 mtx_unlock_spin(&sched_lock); 566 567 fill_kinfo_proc(p, &kp); 568 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 569 sbuf_printf(sb, "State:\t%s\n", state); 570 571 /* 572 * Credentials 573 */ 574 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 575 PROC_LOCK(p); 576 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 577 p->p_pptr->p_pid : 0); 578 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 579 p->p_ucred->cr_uid, 580 p->p_ucred->cr_svuid, 581 /* FreeBSD doesn't have fsuid */ 582 p->p_ucred->cr_uid); 583 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 584 p->p_ucred->cr_gid, 585 p->p_ucred->cr_svgid, 586 /* FreeBSD doesn't have fsgid */ 587 p->p_ucred->cr_gid); 588 sbuf_cat(sb, "Groups:\t"); 589 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 590 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 591 PROC_UNLOCK(p); 592 sbuf_putc(sb, '\n'); 593 594 /* 595 * Memory 596 * 597 * While our approximation of VmLib may not be accurate (I 598 * don't know of a simple way to verify it, and I'm not sure 599 * it has much meaning anyway), I believe it's good enough. 600 * 601 * The same code that could (I think) accurately compute VmLib 602 * could also compute VmLck, but I don't really care enough to 603 * implement it. Submissions are welcome. 604 */ 605 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 606 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 607 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 608 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 609 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 610 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 611 lsize = B2P(kp.ki_size) - kp.ki_dsize - 612 kp.ki_ssize - kp.ki_tsize - 1; 613 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 614 615 /* 616 * Signal masks 617 * 618 * We support up to 128 signals, while Linux supports 32, 619 * but we only define 32 (the same 32 as Linux, to boot), so 620 * just show the lower 32 bits of each mask. XXX hack. 621 * 622 * NB: on certain platforms (Sparc at least) Linux actually 623 * supports 64 signals, but this code is a long way from 624 * running on anything but i386, so ignore that for now. 625 */ 626 PROC_LOCK(p); 627 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 628 /* 629 * I can't seem to find out where the signal mask is in 630 * relation to struct proc, so SigBlk is left unimplemented. 631 */ 632 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 633 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 634 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 635 PROC_UNLOCK(p); 636 637 /* 638 * Linux also prints the capability masks, but we don't have 639 * capabilities yet, and when we do get them they're likely to 640 * be meaningless to Linux programs, so we lie. XXX 641 */ 642 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 643 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 644 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 645 646 return (0); 647} 648 649/* 650 * Filler function for proc/self 651 */ 652static int 653linprocfs_doselflink(PFS_FILL_ARGS) 654{ 655 sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid); 656 return (0); 657} 658 659/* 660 * Filler function for proc/pid/cmdline 661 */ 662static int 663linprocfs_doproccmdline(PFS_FILL_ARGS) 664{ 665 struct ps_strings pstr; 666 int error, i; 667 668 /* 669 * If we are using the ps/cmdline caching, use that. Otherwise 670 * revert back to the old way which only implements full cmdline 671 * for the currept process and just p->p_comm for all other 672 * processes. 673 * Note that if the argv is no longer available, we deliberately 674 * don't fall back on p->p_comm or return an error: the authentic 675 * Linux behaviour is to return zero-length in this case. 676 */ 677 678 if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) { 679 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 680 } else if (p != td->td_proc) { 681 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 682 } else { 683 error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); 684 if (error) 685 return (error); 686 for (i = 0; i < pstr.ps_nargvstr; i++) { 687 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 688 sbuf_printf(sb, "%c", '\0'); 689 } 690 } 691 692 return (0); 693} 694 695/* 696 * Filler function for proc/pid/exe 697 */ 698static int 699linprocfs_doprocexe(PFS_FILL_ARGS) 700{ 701 char *fullpath = "unknown"; 702 char *freepath = NULL; 703 704 vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath); 705 sbuf_printf(sb, "%s", fullpath); 706 if (freepath) 707 free(freepath, M_TEMP); 708 return (0); 709} 710 711/* 712 * Filler function for proc/net/dev 713 */ 714static int 715linprocfs_donetdev(PFS_FILL_ARGS) 716{ 717 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 718 struct ifnet *ifp; 719 720 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 721 "Inter-", " Receive", " Transmit", " face", 722 "bytes packets errs drop fifo frame compressed", 723 "bytes packets errs drop fifo frame compressed"); 724 725 TAILQ_FOREACH(ifp, &ifnet, if_link) { 726 linux_ifname(ifp, ifname, sizeof ifname); 727 sbuf_printf(sb, "%6.6s:", ifname); 728 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 729 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 730 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 731 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 732 } 733 734 return (0); 735} 736 737#if 0 738extern struct cdevsw *cdevsw[]; 739 740/* 741 * Filler function for proc/devices 742 */ 743static int 744linprocfs_dodevices(PFS_FILL_ARGS) 745{ 746 int i; 747 748 sbuf_printf(sb, "Character devices:\n"); 749 750 for (i = 0; i < NUMCDEVSW; i++) 751 if (cdevsw[i] != NULL) 752 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 753 754 sbuf_printf(sb, "\nBlock devices:\n"); 755 756 return (0); 757} 758#endif 759 760/* 761 * Filler function for proc/cmdline 762 */ 763static int 764linprocfs_docmdline(PFS_FILL_ARGS) 765{ 766 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 767 sbuf_printf(sb, " ro root=302\n"); 768 return (0); 769} 770 771#if 0 772/* 773 * Filler function for proc/modules 774 */ 775static int 776linprocfs_domodules(PFS_FILL_ARGS) 777{ 778 struct linker_file *lf; 779 780 TAILQ_FOREACH(lf, &linker_files, link) { 781 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 782 (unsigned long)lf->size, lf->refs); 783 } 784 return (0); 785} 786#endif 787 788/* 789 * Constructor 790 */ 791static int 792linprocfs_init(PFS_INIT_ARGS) 793{ 794 struct pfs_node *root; 795 struct pfs_node *dir; 796 797 root = pi->pi_root; 798 799#define PFS_CREATE_FILE(name) \ 800 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 801 PFS_CREATE_FILE(cmdline); 802 PFS_CREATE_FILE(cpuinfo); 803#if 0 804 PFS_CREATE_FILE(devices); 805#endif 806 PFS_CREATE_FILE(loadavg); 807 PFS_CREATE_FILE(meminfo); 808#if 0 809 PFS_CREATE_FILE(modules); 810#endif 811 PFS_CREATE_FILE(mtab); 812 PFS_CREATE_FILE(stat); 813 PFS_CREATE_FILE(uptime); 814 PFS_CREATE_FILE(version); 815#undef PFS_CREATE_FILE 816 pfs_create_link(root, "self", &linprocfs_doselflink, 817 NULL, NULL, 0); 818 819 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 820 pfs_create_file(dir, "dev", &linprocfs_donetdev, 821 NULL, NULL, PFS_RD); 822 823 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 824 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 825 NULL, NULL, PFS_RD); 826 pfs_create_link(dir, "exe", &linprocfs_doprocexe, 827 NULL, NULL, 0); 828#if 0 829 pfs_create_file(dir, "mem", &procfs_doprocmem, 830 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 831#endif 832 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 833 NULL, NULL, PFS_RD); 834 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 835 NULL, NULL, PFS_RD); 836 837 return (0); 838} 839 840/* 841 * Destructor 842 */ 843static int 844linprocfs_uninit(PFS_INIT_ARGS) 845{ 846 847 /* nothing to do, pseudofs will GC */ 848 return (0); 849} 850 851PSEUDOFS(linprocfs, 1); 852MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 853MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 854