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