linprocfs.c revision 73923
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 73923 2001-03-07 03:21:26Z jhb $ 42 */ 43 44#include <sys/param.h> 45#include <sys/blist.h> 46#include <sys/dkstat.h> 47#include <sys/kernel.h> 48#include <sys/proc.h> 49#include <sys/resourcevar.h> 50#include <sys/sbuf.h> 51#include <sys/systm.h> 52#include <sys/tty.h> 53#include <sys/vnode.h> 54#include <sys/jail.h> 55 56#include <vm/vm.h> 57#include <vm/pmap.h> 58#include <vm/vm_map.h> 59#include <vm/vm_param.h> 60#include <vm/vm_object.h> 61#include <vm/vm_zone.h> 62#include <vm/swap_pager.h> 63 64#include <sys/exec.h> 65#include <sys/user.h> 66#include <sys/vmmeter.h> 67 68#include <machine/clock.h> 69#include <machine/cputypes.h> 70#include <machine/md_var.h> 71 72#include <compat/linux/linux_mib.h> 73#include <compat/linprocfs/linprocfs.h> 74 75/* 76 * Various conversion macros 77 */ 78#define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */ 79#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 80#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 81#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 82#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 83#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 84 85int 86linprocfs_domeminfo(curp, p, pfs, uio) 87 struct proc *curp; 88 struct proc *p; 89 struct pfsnode *pfs; 90 struct uio *uio; 91{ 92 struct sbuf sb; 93 char *ps; 94 int r, xlen; 95 unsigned long memtotal; /* total memory in bytes */ 96 unsigned long memused; /* used memory in bytes */ 97 unsigned long memfree; /* free memory in bytes */ 98 unsigned long memshared; /* shared memory ??? */ 99 unsigned long buffers, cached; /* buffer / cache memory ??? */ 100 unsigned long swaptotal; /* total swap space in bytes */ 101 unsigned long swapused; /* used swap space in bytes */ 102 unsigned long swapfree; /* free swap space in bytes */ 103 vm_object_t object; 104 105 if (uio->uio_rw != UIO_READ) 106 return (EOPNOTSUPP); 107 108 memtotal = physmem * PAGE_SIZE; 109 /* 110 * The correct thing here would be: 111 * 112 memfree = cnt.v_free_count * PAGE_SIZE; 113 memused = memtotal - memfree; 114 * 115 * but it might mislead linux binaries into thinking there 116 * is very little memory left, so we cheat and tell them that 117 * all memory that isn't wired down is free. 118 */ 119 memused = cnt.v_wire_count * PAGE_SIZE; 120 memfree = memtotal - memused; 121 if (swapblist == NULL) { 122 swaptotal = 0; 123 swapfree = 0; 124 } else { 125 swaptotal = swapblist->bl_blocks * 1024; /* XXX why 1024? */ 126 swapfree = swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 127 } 128 swapused = swaptotal - swapfree; 129 memshared = 0; 130 TAILQ_FOREACH(object, &vm_object_list, object_list) 131 if (object->shadow_count > 1) 132 memshared += object->resident_page_count; 133 memshared *= PAGE_SIZE; 134 /* 135 * We'd love to be able to write: 136 * 137 buffers = bufspace; 138 * 139 * but bufspace is internal to vfs_bio.c and we don't feel 140 * like unstaticizing it just for linprocfs's sake. 141 */ 142 buffers = 0; 143 cached = cnt.v_cache_count * PAGE_SIZE; 144 145 sbuf_new(&sb, NULL, 512, 0); 146 sbuf_printf(&sb, 147 " total: used: free: shared: buffers: cached:\n" 148 "Mem: %lu %lu %lu %lu %lu %lu\n" 149 "Swap: %lu %lu %lu\n" 150 "MemTotal: %9lu kB\n" 151 "MemFree: %9lu kB\n" 152 "MemShared:%9lu kB\n" 153 "Buffers: %9lu kB\n" 154 "Cached: %9lu kB\n" 155 "SwapTotal:%9lu kB\n" 156 "SwapFree: %9lu kB\n", 157 memtotal, memused, memfree, memshared, buffers, cached, 158 swaptotal, swapused, swapfree, 159 B2K(memtotal), B2K(memfree), 160 B2K(memshared), B2K(buffers), B2K(cached), 161 B2K(swaptotal), B2K(swapfree)); 162 163 sbuf_finish(&sb); 164 ps = sbuf_data(&sb) + uio->uio_offset; 165 xlen = sbuf_len(&sb) - uio->uio_offset; 166 xlen = imin(xlen, uio->uio_resid); 167 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 168 sbuf_delete(&sb); 169 return r; 170} 171 172int 173linprocfs_docpuinfo(curp, p, pfs, uio) 174 struct proc *curp; 175 struct proc *p; 176 struct pfsnode *pfs; 177 struct uio *uio; 178{ 179 struct sbuf sb; 180 char *ps; 181 int r, xlen; 182 int class, i, fqmhz, fqkhz; 183 184 /* 185 * We default the flags to include all non-conflicting flags, 186 * and the Intel versions of conflicting flags. 187 */ 188 static char *flags[] = { 189 "fpu", "vme", "de", "pse", "tsc", 190 "msr", "pae", "mce", "cx8", "apic", 191 "sep", "sep", "mtrr", "pge", "mca", 192 "cmov", "pat", "pse36", "pn", "b19", 193 "b20", "b21", "mmxext", "mmx", "fxsr", 194 "xmm", "b26", "b27", "b28", "b29", 195 "3dnowext", "3dnow" 196 }; 197 198 if (uio->uio_rw != UIO_READ) 199 return (EOPNOTSUPP); 200 201 switch (cpu_class) { 202 case CPUCLASS_286: 203 class = 2; 204 break; 205 case CPUCLASS_386: 206 class = 3; 207 break; 208 case CPUCLASS_486: 209 class = 4; 210 break; 211 case CPUCLASS_586: 212 class = 5; 213 break; 214 case CPUCLASS_686: 215 class = 6; 216 break; 217 default: 218 class = 0; 219 break; 220 } 221 222 sbuf_new(&sb, NULL, 512, 0); 223 sbuf_printf(&sb, 224 "processor\t: %d\n" 225 "vendor_id\t: %.20s\n" 226 "cpu family\t: %d\n" 227 "model\t\t: %d\n" 228 "stepping\t: %d\n", 229 0, cpu_vendor, class, cpu, cpu_id & 0xf); 230 231 sbuf_cat(&sb, 232 "flags\t\t:"); 233 234 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 235 flags[16] = "fcmov"; 236 } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 237 flags[24] = "cxmmx"; 238 } 239 240 for (i = 0; i < 32; i++) 241 if (cpu_feature & (1 << i)) 242 sbuf_printf(&sb, " %s", flags[i]); 243 sbuf_cat(&sb, "\n"); 244 if (class >= 5) { 245 fqmhz = (tsc_freq + 4999) / 1000000; 246 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 247 sbuf_printf(&sb, 248 "cpu MHz\t\t: %d.%02d\n" 249 "bogomips\t: %d.%02d\n", 250 fqmhz, fqkhz, fqmhz, fqkhz); 251 } 252 253 sbuf_finish(&sb); 254 ps = sbuf_data(&sb) + uio->uio_offset; 255 xlen = sbuf_len(&sb) - uio->uio_offset; 256 xlen = imin(xlen, uio->uio_resid); 257 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 258 sbuf_delete(&sb); 259 return r; 260} 261 262int 263linprocfs_dostat(curp, p, pfs, uio) 264 struct proc *curp; 265 struct proc *p; 266 struct pfsnode *pfs; 267 struct uio *uio; 268{ 269 struct sbuf sb; 270 char *ps; 271 int r, xlen; 272 273 sbuf_new(&sb, NULL, 512, 0); 274 sbuf_printf(&sb, 275 "cpu %ld %ld %ld %ld\n" 276 "disk 0 0 0 0\n" 277 "page %u %u\n" 278 "swap %u %u\n" 279 "intr %u\n" 280 "ctxt %u\n" 281 "btime %ld\n", 282 T2J(cp_time[CP_USER]), 283 T2J(cp_time[CP_NICE]), 284 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 285 T2J(cp_time[CP_IDLE]), 286 cnt.v_vnodepgsin, 287 cnt.v_vnodepgsout, 288 cnt.v_swappgsin, 289 cnt.v_swappgsout, 290 cnt.v_intr, 291 cnt.v_swtch, 292 boottime.tv_sec); 293 294 sbuf_finish(&sb); 295 ps = sbuf_data(&sb) + uio->uio_offset; 296 xlen = sbuf_len(&sb) - uio->uio_offset; 297 xlen = imin(xlen, uio->uio_resid); 298 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 299 sbuf_delete(&sb); 300 return r; 301} 302 303int 304linprocfs_douptime(curp, p, pfs, uio) 305 struct proc *curp; 306 struct proc *p; 307 struct pfsnode *pfs; 308 struct uio *uio; 309{ 310 struct sbuf sb; 311 char *ps; 312 int r, xlen; 313 struct timeval tv; 314 315 getmicrouptime(&tv); 316 sbuf_new(&sb, NULL, 64, 0); 317 sbuf_printf(&sb, "%ld.%02ld %ld.%02ld\n", 318 tv.tv_sec, tv.tv_usec / 10000, 319 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 320 sbuf_finish(&sb); 321 ps = sbuf_data(&sb) + uio->uio_offset; 322 xlen = sbuf_len(&sb) - uio->uio_offset; 323 xlen = imin(xlen, uio->uio_resid); 324 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 325 sbuf_delete(&sb); 326 return r; 327} 328 329int 330linprocfs_doversion(curp, p, pfs, uio) 331 struct proc *curp; 332 struct proc *p; 333 struct pfsnode *pfs; 334 struct uio *uio; 335{ 336 struct sbuf sb; 337 char *ps; 338 int r, xlen; 339 340 sbuf_new(&sb, NULL, 128, 0); 341 sbuf_printf(&sb, 342 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 343 " #4 Sun Dec 18 04:30:00 CET 1977\n", 344 linux_get_osname(curp), 345 linux_get_osrelease(curp)); 346 sbuf_finish(&sb); 347 ps = sbuf_data(&sb) + uio->uio_offset; 348 xlen = sbuf_len(&sb) - uio->uio_offset; 349 xlen = imin(xlen, uio->uio_resid); 350 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 351 sbuf_delete(&sb); 352 return r; 353} 354 355int 356linprocfs_doprocstat(curp, p, pfs, uio) 357 struct proc *curp; 358 struct proc *p; 359 struct pfsnode *pfs; 360 struct uio *uio; 361{ 362 struct kinfo_proc kp; 363 struct sbuf sb; 364 char *ps; 365 int r, xlen; 366 367 fill_kinfo_proc(p, &kp); 368 sbuf_new(&sb, NULL, 1024, 0); 369 sbuf_printf(&sb, "%d", p->p_pid); 370#define PS_ADD(name, fmt, arg) sbuf_printf(&sb, " " fmt, arg) 371 PS_ADD("comm", "(%s)", p->p_comm); 372 PS_ADD("statr", "%c", '0'); /* XXX */ 373 PROC_LOCK(p); 374 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 375 PROC_UNLOCK(p); 376 PS_ADD("pgrp", "%d", p->p_pgid); 377 PS_ADD("session", "%d", p->p_session->s_sid); 378 PS_ADD("tty", "%d", 0); /* XXX */ 379 PS_ADD("tpgid", "%d", 0); /* XXX */ 380 PS_ADD("flags", "%u", 0); /* XXX */ 381 PS_ADD("minflt", "%u", 0); /* XXX */ 382 PS_ADD("cminflt", "%u", 0); /* XXX */ 383 PS_ADD("majflt", "%u", 0); /* XXX */ 384 PS_ADD("cminflt", "%u", 0); /* XXX */ 385 PS_ADD("utime", "%d", 0); /* XXX */ 386 PS_ADD("stime", "%d", 0); /* XXX */ 387 PS_ADD("cutime", "%d", 0); /* XXX */ 388 PS_ADD("cstime", "%d", 0); /* XXX */ 389 PS_ADD("counter", "%d", 0); /* XXX */ 390 PS_ADD("priority", "%d", 0); /* XXX */ 391 PS_ADD("timeout", "%u", 0); /* XXX */ 392 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 393 PS_ADD("starttime", "%d", 0); /* XXX */ 394 PS_ADD("vsize", "%u", kp.ki_size); 395 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 396 PS_ADD("rlim", "%u", 0); /* XXX */ 397 PS_ADD("startcode", "%u", (unsigned)0); 398 PS_ADD("endcode", "%u", 0); /* XXX */ 399 PS_ADD("startstack", "%u", 0); /* XXX */ 400 PS_ADD("esp", "%u", 0); /* XXX */ 401 PS_ADD("eip", "%u", 0); /* XXX */ 402 PS_ADD("signal", "%d", 0); /* XXX */ 403 PS_ADD("blocked", "%d", 0); /* XXX */ 404 PS_ADD("sigignore", "%d", 0); /* XXX */ 405 PS_ADD("sigcatch", "%d", 0); /* XXX */ 406 PS_ADD("wchan", "%u", 0); /* XXX */ 407 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 408 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 409 PS_ADD("exitsignal", "%d", 0); /* XXX */ 410 PS_ADD("processor", "%d", 0); /* XXX */ 411#undef PS_ADD 412 sbuf_putc(&sb, '\n'); 413 414 sbuf_finish(&sb); 415 ps = sbuf_data(&sb) + uio->uio_offset; 416 xlen = sbuf_len(&sb) - uio->uio_offset; 417 xlen = imin(xlen, uio->uio_resid); 418 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 419 sbuf_delete(&sb); 420 return r; 421} 422 423/* 424 * Map process state to descriptive letter. Note that this does not 425 * quite correspond to what Linux outputs, but it's close enough. 426 */ 427static char *state_str[] = { 428 "? (unknown)", 429 "I (idle)", 430 "R (running)", 431 "S (sleeping)", 432 "T (stopped)", 433 "Z (zombie)", 434 "W (waiting)", 435 "M (mutex)" 436}; 437 438int 439linprocfs_doprocstatus(curp, p, pfs, uio) 440 struct proc *curp; 441 struct proc *p; 442 struct pfsnode *pfs; 443 struct uio *uio; 444{ 445 struct kinfo_proc kp; 446 struct sbuf sb; 447 char *ps; 448 char *state; 449 int i, r, xlen; 450 segsz_t lsize; 451 452 sbuf_new(&sb, NULL, 1024, 0); 453 454 mtx_lock_spin(&sched_lock); 455 if (p->p_stat > sizeof state_str / sizeof *state_str) 456 state = state_str[0]; 457 else 458 state = state_str[(int)p->p_stat]; 459 mtx_unlock_spin(&sched_lock); 460 461 fill_kinfo_proc(p, &kp); 462 sbuf_printf(&sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 463 sbuf_printf(&sb, "State:\t%s\n", state); 464 465 /* 466 * Credentials 467 */ 468 sbuf_printf(&sb, "Pid:\t%d\n", p->p_pid); 469 PROC_LOCK(p); 470 sbuf_printf(&sb, "PPid:\t%d\n", p->p_pptr ? 471 p->p_pptr->p_pid : 0); 472 sbuf_printf(&sb, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid, 473 p->p_ucred->cr_uid, 474 p->p_cred->p_svuid, 475 /* FreeBSD doesn't have fsuid */ 476 p->p_ucred->cr_uid); 477 sbuf_printf(&sb, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid, 478 p->p_ucred->cr_gid, 479 p->p_cred->p_svgid, 480 /* FreeBSD doesn't have fsgid */ 481 p->p_ucred->cr_gid); 482 sbuf_cat(&sb, "Groups:\t"); 483 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 484 sbuf_printf(&sb, "%d ", p->p_ucred->cr_groups[i]); 485 PROC_UNLOCK(p); 486 sbuf_putc(&sb, '\n'); 487 488 /* 489 * Memory 490 * 491 * While our approximation of VmLib may not be accurate (I 492 * don't know of a simple way to verify it, and I'm not sure 493 * it has much meaning anyway), I believe it's good enough. 494 * 495 * The same code that could (I think) accurately compute VmLib 496 * could also compute VmLck, but I don't really care enough to 497 * implement it. Submissions are welcome. 498 */ 499 sbuf_printf(&sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 500 sbuf_printf(&sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 501 sbuf_printf(&sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 502 sbuf_printf(&sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 503 sbuf_printf(&sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 504 sbuf_printf(&sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 505 lsize = B2P(kp.ki_size) - kp.ki_dsize - 506 kp.ki_ssize - kp.ki_tsize - 1; 507 sbuf_printf(&sb, "VmLib:\t%8u kB\n", P2K(lsize)); 508 509 /* 510 * Signal masks 511 * 512 * We support up to 128 signals, while Linux supports 32, 513 * but we only define 32 (the same 32 as Linux, to boot), so 514 * just show the lower 32 bits of each mask. XXX hack. 515 * 516 * NB: on certain platforms (Sparc at least) Linux actually 517 * supports 64 signals, but this code is a long way from 518 * running on anything but i386, so ignore that for now. 519 */ 520 PROC_LOCK(p); 521 sbuf_printf(&sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 522 /* 523 * I can't seem to find out where the signal mask is in 524 * relation to struct proc, so SigBlk is left unimplemented. 525 */ 526 sbuf_printf(&sb, "SigBlk:\t%08x\n", 0); /* XXX */ 527 sbuf_printf(&sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 528 sbuf_printf(&sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 529 PROC_UNLOCK(p); 530 531 /* 532 * Linux also prints the capability masks, but we don't have 533 * capabilities yet, and when we do get them they're likely to 534 * be meaningless to Linux programs, so we lie. XXX 535 */ 536 sbuf_printf(&sb, "CapInh:\t%016x\n", 0); 537 sbuf_printf(&sb, "CapPrm:\t%016x\n", 0); 538 sbuf_printf(&sb, "CapEff:\t%016x\n", 0); 539 540 sbuf_finish(&sb); 541 ps = sbuf_data(&sb) + uio->uio_offset; 542 xlen = sbuf_len(&sb) - uio->uio_offset; 543 xlen = imin(xlen, uio->uio_resid); 544 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 545 sbuf_delete(&sb); 546 return r; 547} 548