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 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 172 int 173 linprocfs_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 262 int 263 linprocfs_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 303 int 304 linprocfs_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 329 int 330 linprocfs_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 355 int 356 linprocfs_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 pid_t ppid; 367 368 PROCTREE_LOCK(PT_SHARED); 369 ppid = p->p_pptr ? p->p_pptr->p_pid : 0; 370 PROCTREE_LOCK(PT_RELEASE); 371 fill_kinfo_proc(p, &kp); 372 sbuf_new(&sb, NULL, 1024, 0); 373 sbuf_printf(&sb, "%d", p->p_pid); 374 #define PS_ADD(name, fmt, arg) sbuf_printf(&sb, " " fmt, arg) 375 PS_ADD("comm", "(%s)", p->p_comm); 376 PS_ADD("statr", "%c", '0'); /* XXX */ 377 PS_ADD("ppid", "%d", ppid); 378 PS_ADD("pgrp", "%d", p->p_pgid); 379 PS_ADD("session", "%d", p->p_session->s_sid); 380 PS_ADD("tty", "%d", 0); /* XXX */ 381 PS_ADD("tpgid", "%d", 0); /* XXX */ 382 PS_ADD("flags", "%u", 0); /* XXX */ 383 PS_ADD("minflt", "%u", 0); /* XXX */ 384 PS_ADD("cminflt", "%u", 0); /* XXX */ 385 PS_ADD("majflt", "%u", 0); /* XXX */ 386 PS_ADD("cminflt", "%u", 0); /* XXX */ 387 PS_ADD("utime", "%d", 0); /* XXX */ 388 PS_ADD("stime", "%d", 0); /* XXX */ 389 PS_ADD("cutime", "%d", 0); /* XXX */ 390 PS_ADD("cstime", "%d", 0); /* XXX */ 391 PS_ADD("counter", "%d", 0); /* XXX */ 392 PS_ADD("priority", "%d", 0); /* XXX */ 393 PS_ADD("timeout", "%u", 0); /* XXX */ 394 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 395 PS_ADD("starttime", "%d", 0); /* XXX */ 396 PS_ADD("vsize", "%u", kp.ki_size); 397 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 398 PS_ADD("rlim", "%u", 0); /* XXX */ 399 PS_ADD("startcode", "%u", (unsigned)0); 400 PS_ADD("endcode", "%u", 0); /* XXX */ 401 PS_ADD("startstack", "%u", 0); /* XXX */ 402 PS_ADD("esp", "%u", 0); /* XXX */ 403 PS_ADD("eip", "%u", 0); /* XXX */ 404 PS_ADD("signal", "%d", 0); /* XXX */ 405 PS_ADD("blocked", "%d", 0); /* XXX */ 406 PS_ADD("sigignore", "%d", 0); /* XXX */ 407 PS_ADD("sigcatch", "%d", 0); /* XXX */ 408 PS_ADD("wchan", "%u", 0); /* XXX */ 409 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 410 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 411 PS_ADD("exitsignal", "%d", 0); /* XXX */ 412 PS_ADD("processor", "%d", 0); /* XXX */ 413 #undef PS_ADD 414 sbuf_putc(&sb, '\n'); 415 416 sbuf_finish(&sb); 417 ps = sbuf_data(&sb) + uio->uio_offset; 418 xlen = sbuf_len(&sb) - uio->uio_offset; 419 xlen = imin(xlen, uio->uio_resid); 420 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 421 sbuf_delete(&sb); 422 return r; 423 } 424 425 /* 426 * Map process state to descriptive letter. Note that this does not 427 * quite correspond to what Linux outputs, but it's close enough. 428 */ 429 static char *state_str[] = { 430 "? (unknown)", 431 "I (idle)", 432 "R (running)", 433 "S (sleeping)", 434 "T (stopped)", 435 "Z (zombie)", 436 "W (waiting)", 437 "M (mutex)" 438 }; 439 440 int 441 linprocfs_doprocstatus(curp, p, pfs, uio) 442 struct proc *curp; 443 struct proc *p; 444 struct pfsnode *pfs; 445 struct uio *uio; 446 { 447 struct kinfo_proc kp; 448 struct sbuf sb; 449 char *ps; 450 char *state; 451 int i, r, xlen; 452 segsz_t lsize; 453 pid_t ppid; 454 455 sbuf_new(&sb, NULL, 1024, 0); 456 457 mtx_enter(&sched_lock, MTX_SPIN); 458 if (p->p_stat > sizeof state_str / sizeof *state_str) 459 state = state_str[0]; 460 else 461 state = state_str[(int)p->p_stat]; 462 mtx_exit(&sched_lock, MTX_SPIN); 463 464 PROCTREE_LOCK(PT_SHARED); 465 ppid = p->p_pptr ? p->p_pptr->p_pid : 0; 466 PROCTREE_LOCK(PT_RELEASE); 467 fill_kinfo_proc(p, &kp); 468 sbuf_printf(&sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 469 sbuf_printf(&sb, "State:\t%s\n", state); 470 471 /* 472 * Credentials 473 */ 474 sbuf_printf(&sb, "Pid:\t%d\n", p->p_pid); 475 sbuf_printf(&sb, "PPid:\t%d\n", ppid); 476 PROC_LOCK(p); 477 sbuf_printf(&sb, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid, 478 p->p_ucred->cr_uid, 479 p->p_cred->p_svuid, 480 /* FreeBSD doesn't have fsuid */ 481 p->p_ucred->cr_uid); 482 sbuf_printf(&sb, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid, 483 p->p_ucred->cr_gid, 484 p->p_cred->p_svgid, 485 /* FreeBSD doesn't have fsgid */ 486 p->p_ucred->cr_gid); 487 sbuf_cat(&sb, "Groups:\t"); 488 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 489 sbuf_printf(&sb, "%d ", p->p_ucred->cr_groups[i]); 490 PROC_UNLOCK(p); 491 sbuf_putc(&sb, '\n'); 492 493 /* 494 * Memory 495 * 496 * While our approximation of VmLib may not be accurate (I 497 * don't know of a simple way to verify it, and I'm not sure 498 * it has much meaning anyway), I believe it's good enough. 499 * 500 * The same code that could (I think) accurately compute VmLib 501 * could also compute VmLck, but I don't really care enough to 502 * implement it. Submissions are welcome. 503 */ 504 sbuf_printf(&sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 505 sbuf_printf(&sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 506 sbuf_printf(&sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 507 sbuf_printf(&sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 508 sbuf_printf(&sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 509 sbuf_printf(&sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 510 lsize = B2P(kp.ki_size) - kp.ki_dsize - 511 kp.ki_ssize - kp.ki_tsize - 1; 512 sbuf_printf(&sb, "VmLib:\t%8u kB\n", P2K(lsize)); 513 514 /* 515 * Signal masks 516 * 517 * We support up to 128 signals, while Linux supports 32, 518 * but we only define 32 (the same 32 as Linux, to boot), so 519 * just show the lower 32 bits of each mask. XXX hack. 520 * 521 * NB: on certain platforms (Sparc at least) Linux actually 522 * supports 64 signals, but this code is a long way from 523 * running on anything but i386, so ignore that for now. 524 */ 525 PROC_LOCK(p); 526 sbuf_printf(&sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 527 /* 528 * I can't seem to find out where the signal mask is in 529 * relation to struct proc, so SigBlk is left unimplemented. 530 */ 531 sbuf_printf(&sb, "SigBlk:\t%08x\n", 0); /* XXX */ 532 sbuf_printf(&sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 533 sbuf_printf(&sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 534 PROC_UNLOCK(p); 535 536 /* 537 * Linux also prints the capability masks, but we don't have 538 * capabilities yet, and when we do get them they're likely to 539 * be meaningless to Linux programs, so we lie. XXX 540 */ 541 sbuf_printf(&sb, "CapInh:\t%016x\n", 0); 542 sbuf_printf(&sb, "CapPrm:\t%016x\n", 0); 543 sbuf_printf(&sb, "CapEff:\t%016x\n", 0); 544 545 sbuf_finish(&sb); 546 ps = sbuf_data(&sb) + uio->uio_offset; 547 xlen = sbuf_len(&sb) - uio->uio_offset; 548 xlen = imin(xlen, uio->uio_resid); 549 r = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 550 sbuf_delete(&sb); 551 return r; 552 } 553