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 : %d\n" 222 "vendor_id : %.20s\n" 223 "cpu family : %d\n" 224 "model : %d\n" 225 "stepping : %d\n", 226 0, cpu_vendor, class, cpu, cpu_id & 0xf); 227 228 ps += sprintf(ps, 229 "flags :"); 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 : %d.%02d\n", 244 (tsc_freq + 4999) / 1000000, 245 ((tsc_freq + 4999) / 10000) % 100); 246 } 247 248 xlen = ps - psbuf; 249 xlen -= uio->uio_offset; 250 ps = psbuf + uio->uio_offset; 251 xlen = imin(xlen, uio->uio_resid); 252 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 253 } 254 255 int 256 linprocfs_dostat(curp, p, pfs, uio) 257 struct proc *curp; 258 struct proc *p; 259 struct pfsnode *pfs; 260 struct uio *uio; 261 { 262 char *ps; 263 char psbuf[512]; 264 int xlen; 265 266 ps = psbuf; 267 ps += sprintf(ps, 268 "cpu %ld %ld %ld %ld\n" 269 "disk 0 0 0 0\n" 270 "page %u %u\n" 271 "swap %u %u\n" 272 "intr %u\n" 273 "ctxt %u\n" 274 "btime %ld\n", 275 T2J(cp_time[CP_USER]), 276 T2J(cp_time[CP_NICE]), 277 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 278 T2J(cp_time[CP_IDLE]), 279 cnt.v_vnodepgsin, 280 cnt.v_vnodepgsout, 281 cnt.v_swappgsin, 282 cnt.v_swappgsout, 283 cnt.v_intr, 284 cnt.v_swtch, 285 boottime.tv_sec); 286 xlen = ps - psbuf; 287 xlen -= uio->uio_offset; 288 ps = psbuf + uio->uio_offset; 289 xlen = imin(xlen, uio->uio_resid); 290 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 291 } 292 293 int 294 linprocfs_douptime(curp, p, pfs, uio) 295 struct proc *curp; 296 struct proc *p; 297 struct pfsnode *pfs; 298 struct uio *uio; 299 { 300 char *ps; 301 int xlen; 302 char psbuf[64]; 303 struct timeval tv; 304 305 getmicrouptime(&tv); 306 ps = psbuf; 307 ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n", 308 tv.tv_sec, tv.tv_usec / 10000, 309 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 310 xlen = ps - psbuf; 311 xlen -= uio->uio_offset; 312 ps = psbuf + uio->uio_offset; 313 xlen = imin(xlen, uio->uio_resid); 314 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 315 } 316 317 int 318 linprocfs_doversion(curp, p, pfs, uio) 319 struct proc *curp; 320 struct proc *p; 321 struct pfsnode *pfs; 322 struct uio *uio; 323 { 324 char *ps; 325 int xlen; 326 327 ps = version; /* XXX not entirely correct */ 328 for (xlen = 0; ps[xlen] != '\n'; ++xlen) 329 /* nothing */ ; 330 ++xlen; 331 xlen -= uio->uio_offset; 332 ps += uio->uio_offset; 333 xlen = imin(xlen, uio->uio_resid); 334 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 335 } 336 337 int 338 linprocfs_doprocstat(curp, p, pfs, uio) 339 struct proc *curp; 340 struct proc *p; 341 struct pfsnode *pfs; 342 struct uio *uio; 343 { 344 char *ps, psbuf[1024]; 345 int xlen; 346 347 ps = psbuf; 348 ps += sprintf(ps, "%d", p->p_pid); 349 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg) 350 PS_ADD("comm", "(%s)", p->p_comm); 351 PS_ADD("statr", "%c", '0'); /* XXX */ 352 PS_ADD("ppid", "%d", p->p_pptr->p_pid); 353 PS_ADD("pgrp", "%d", p->p_pgid); 354 PS_ADD("session", "%d", p->p_session->s_sid); 355 PS_ADD("tty", "%d", 0); /* XXX */ 356 PS_ADD("tpgid", "%d", 0); /* XXX */ 357 PS_ADD("flags", "%u", 0); /* XXX */ 358 PS_ADD("minflt", "%u", 0); /* XXX */ 359 PS_ADD("cminflt", "%u", 0); /* XXX */ 360 PS_ADD("majflt", "%u", 0); /* XXX */ 361 PS_ADD("cminflt", "%u", 0); /* XXX */ 362 PS_ADD("utime", "%d", 0); /* XXX */ 363 PS_ADD("stime", "%d", 0); /* XXX */ 364 PS_ADD("cutime", "%d", 0); /* XXX */ 365 PS_ADD("cstime", "%d", 0); /* XXX */ 366 PS_ADD("counter", "%d", 0); /* XXX */ 367 PS_ADD("priority", "%d", 0); /* XXX */ 368 PS_ADD("timeout", "%u", 0); /* XXX */ 369 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 370 PS_ADD("starttime", "%d", 0); /* XXX */ 371 PS_ADD("vsize", "%u", 0); /* XXX */ 372 PS_ADD("rss", "%u", 0); /* XXX */ 373 PS_ADD("rlim", "%u", 0); /* XXX */ 374 PS_ADD("startcode", "%u", 0); /* XXX */ 375 PS_ADD("endcode", "%u", 0); /* XXX */ 376 PS_ADD("startstack", "%u", 0); /* XXX */ 377 PS_ADD("kstkesp", "%u", 0); /* XXX */ 378 PS_ADD("kstkeip", "%u", 0); /* XXX */ 379 PS_ADD("signal", "%d", 0); /* XXX */ 380 PS_ADD("blocked", "%d", 0); /* XXX */ 381 PS_ADD("sigignore", "%d", 0); /* XXX */ 382 PS_ADD("sigcatch", "%d", 0); /* XXX */ 383 PS_ADD("wchan", "%u", 0); /* XXX */ 384 #undef PS_ADD 385 ps += sprintf(ps, "\n"); 386 387 xlen = ps - psbuf; 388 xlen -= uio->uio_offset; 389 ps = psbuf + uio->uio_offset; 390 xlen = imin(xlen, uio->uio_resid); 391 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 392 } 393 394 /* 395 * Map process state to descriptive letter. Note that this does not 396 * quite correspond to what Linux outputs, but it's close enough. 397 */ 398 static char *state_str[] = { 399 "? (unknown)", 400 "I (idle)", 401 "R (running)", 402 "S (sleeping)", 403 "T (stopped)", 404 "Z (zombie)", 405 "W (waiting)", 406 "M (mutex)" 407 }; 408 409 int 410 linprocfs_doprocstatus(curp, p, pfs, uio) 411 struct proc *curp; 412 struct proc *p; 413 struct pfsnode *pfs; 414 struct uio *uio; 415 { 416 char *ps, psbuf[1024]; 417 char *state; 418 int i, xlen; 419 420 ps = psbuf; 421 422 if (p->p_stat > sizeof state_str / sizeof *state_str) 423 state = state_str[0]; 424 else 425 state = state_str[(int)p->p_stat]; 426 427 #define PS_ADD ps += sprintf 428 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */ 429 PS_ADD(ps, "State:\t%s\n", state); 430 431 /* 432 * Credentials 433 */ 434 PS_ADD(ps, "Pid:\t%d\n", p->p_pid); 435 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr->p_pid); 436 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid, 437 p->p_ucred->cr_uid, 438 p->p_cred->p_svuid, 439 /* FreeBSD doesn't have fsuid */ 440 p->p_ucred->cr_uid); 441 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid, 442 p->p_ucred->cr_gid, 443 p->p_cred->p_svgid, 444 /* FreeBSD doesn't have fsgid */ 445 p->p_ucred->cr_gid); 446 PS_ADD(ps, "Groups:\t"); 447 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 448 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]); 449 PS_ADD(ps, "\n"); 450 451 /* 452 * Memory 453 */ 454 PS_ADD(ps, "VmSize:\t%8u kB\n", B2K(p->p_vmspace->vm_map.size)); 455 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 456 /* XXX vm_rssize seems to always be zero, how can this be? */ 457 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize)); 458 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize)); 459 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize)); 460 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize)); 461 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */ 462 463 /* 464 * Signal masks 465 * 466 * We support up to 128 signals, while Linux supports 32, 467 * but we only define 32 (the same 32 as Linux, to boot), so 468 * just show the lower 32 bits of each mask. XXX hack. 469 * 470 * NB: on certain platforms (Sparc at least) Linux actually 471 * supports 64 signals, but this code is a long way from 472 * running on anything but i386, so ignore that for now. 473 */ 474 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 475 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */ 476 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 477 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 478 479 /* 480 * Linux also prints the capability masks, but we don't have 481 * capabilities yet, and when we do get them they're likely to 482 * be meaningless to Linux programs, so we lie. XXX 483 */ 484 PS_ADD(ps, "CapInh:\t%016x\n", 0); 485 PS_ADD(ps, "CapPrm:\t%016x\n", 0); 486 PS_ADD(ps, "CapEff:\t%016x\n", 0); 487 #undef PS_ADD 488 489 xlen = ps - psbuf; 490 xlen -= uio->uio_offset; 491 ps = psbuf + uio->uio_offset; 492 xlen = imin(xlen, uio->uio_resid); 493 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 494 } 495