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