2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
41 * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_misc.c,v 1.3.2.8 2001/06/25 19:46:47 pirzyk Exp $
42 * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_misc.c,v 1.5 2003/08/07 21:17:19 dillon Exp $
45 #include <sys/param.h>
46 #include <sys/blist.h>
47 #include <sys/dkstat.h>
49 #include <sys/kernel.h>
51 #include <sys/resourcevar.h>
52 #include <sys/systm.h>
54 #include <sys/vnode.h>
59 #include <vm/vm_map.h>
60 #include <vm/vm_param.h>
61 #include <vm/vm_object.h>
62 #include <vm/swap_pager.h>
63 #include <sys/vmmeter.h>
66 #include <machine/clock.h>
67 #include <machine/cputypes.h>
68 #include <machine/md_var.h>
70 #include "linprocfs.h"
73 * Various conversion macros
75 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
76 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
77 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
78 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
79 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
82 linprocfs_domeminfo(curp, p, pfs, uio)
90 char psbuf[512]; /* XXX - conservative */
91 unsigned long memtotal; /* total memory in bytes */
92 unsigned long memused; /* used memory in bytes */
93 unsigned long memfree; /* free memory in bytes */
94 unsigned long memshared; /* shared memory ??? */
95 unsigned long buffers, cached; /* buffer / cache memory ??? */
96 unsigned long long swaptotal; /* total swap space in bytes */
97 unsigned long long swapused; /* used swap space in bytes */
98 unsigned long long swapfree; /* free swap space in bytes */
101 if (uio->uio_rw != UIO_READ)
104 memtotal = physmem * PAGE_SIZE;
106 * The correct thing here would be:
108 memfree = vmstats.v_free_count * PAGE_SIZE;
109 memused = memtotal - memfree;
111 * but it might mislead linux binaries into thinking there
112 * is very little memory left, so we cheat and tell them that
113 * all memory that isn't wired down is free.
115 memused = vmstats.v_wire_count * PAGE_SIZE;
116 memfree = memtotal - memused;
117 if (swapblist == NULL) {
121 swaptotal = (unsigned long long) swapblist->bl_blocks * 1024ULL; /* XXX why 1024? */
122 swapfree = (unsigned long long) swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
124 swapused = swaptotal - swapfree;
126 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
127 object = TAILQ_NEXT(object, object_list))
128 if (object->shadow_count > 1)
129 memshared += object->resident_page_count;
130 memshared *= PAGE_SIZE;
132 * We'd love to be able to write:
136 * but bufspace is internal to vfs_bio.c and we don't feel
137 * like unstaticizing it just for linprocfs's sake.
140 cached = vmstats.v_cache_count * PAGE_SIZE;
144 " total: used: free: shared: buffers: cached:\n"
145 "Mem: %lu %lu %lu %lu %lu %lu\n"
146 "Swap: %llu %llu %llu\n"
147 "MemTotal: %9lu kB\n"
149 "MemShared:%9lu kB\n"
152 "SwapTotal:%9llu kB\n"
153 "SwapFree: %9llu kB\n",
154 memtotal, memused, memfree, memshared, buffers, cached,
155 swaptotal, swapused, swapfree,
156 B2K(memtotal), B2K(memfree),
157 B2K(memshared), B2K(buffers), B2K(cached),
158 B2K(swaptotal), B2K(swapfree));
161 xlen -= uio->uio_offset;
162 ps = psbuf + uio->uio_offset;
163 xlen = imin(xlen, uio->uio_resid);
164 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
168 linprocfs_docpuinfo(curp, p, pfs, uio)
176 char psbuf[512]; /* XXX - conservative */
180 extern char *cpu_model; /* Yuck */
182 /* We default the flags to include all non-conflicting flags,
183 and the Intel versions of conflicting flags. Note the space
184 before each name; that is significant, and should be
187 static char *flags[] = {
188 "fpu", "vme", "de", "pse", "tsc",
189 "msr", "pae", "mce", "cx8", "apic",
190 "sep", "sep", "mtrr", "pge", "mca",
191 "cmov", "pat", "pse36", "pn", "b19",
192 "b20", "b21", "mmxext", "mmx", "fxsr",
193 "xmm", "b26", "b27", "b28", "b29",
197 if (uio->uio_rw != UIO_READ)
224 "vendor_id\t: %.20s\n"
228 0, cpu_vendor, class, cpu, cpu_id & 0xf);
233 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
235 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
239 for (i = 0; i < 32; i++)
240 if (cpu_feature & (1 << i))
241 ps += sprintf(ps, " %s", flags[i]);
242 ps += sprintf(ps, "\n");
245 "cpu MHz\t\t: %d.%02d\n"
246 "bogomips\t: %d.%02d\n",
247 (tsc_freq + 4999) / 1000000,
248 ((tsc_freq + 4999) / 10000) % 100,
249 (tsc_freq + 4999) / 1000000,
250 ((tsc_freq + 4999) / 10000) % 100);
254 xlen -= uio->uio_offset;
255 ps = psbuf + uio->uio_offset;
256 xlen = imin(xlen, uio->uio_resid);
257 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
266 for (i = 0; i < ncpus; ++i) {
267 struct globaldata *gd = globaldata_find(i);
268 count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
274 linprocfs_dostat(curp, p, pfs, uio)
286 "cpu %ld %ld %ld %ld\n"
293 T2J(cp_time[CP_USER]),
294 T2J(cp_time[CP_NICE]),
295 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
296 T2J(cp_time[CP_IDLE]),
297 cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
298 cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
299 cpucnt(offsetof(struct vmmeter, v_swappgsin)),
300 cpucnt(offsetof(struct vmmeter, v_swappgsout)),
301 cpucnt(offsetof(struct vmmeter, v_intr)),
302 cpucnt(offsetof(struct vmmeter, v_swtch)),
305 xlen -= uio->uio_offset;
306 ps = psbuf + uio->uio_offset;
307 xlen = imin(xlen, uio->uio_resid);
308 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
312 linprocfs_douptime(curp, p, pfs, uio)
325 ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n",
326 tv.tv_sec, tv.tv_usec / 10000,
327 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
329 xlen -= uio->uio_offset;
330 ps = psbuf + uio->uio_offset;
331 xlen = imin(xlen, uio->uio_resid);
332 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
336 linprocfs_doversion(curp, p, pfs, uio)
345 ps = version; /* XXX not entirely correct */
346 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
349 xlen -= uio->uio_offset;
350 ps += uio->uio_offset;
351 xlen = imin(xlen, uio->uio_resid);
352 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
356 linprocfs_doprocstat(curp, p, pfs, uio)
362 char *ps, psbuf[1024];
366 ps += sprintf(ps, "%d", p->p_pid);
367 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
368 PS_ADD("comm", "(%s)", p->p_comm);
369 PS_ADD("statr", "%c", '0'); /* XXX */
370 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
371 PS_ADD("pgrp", "%d", p->p_pgid);
372 PS_ADD("session", "%d", p->p_session->s_sid);
373 PS_ADD("tty", "%d", 0); /* XXX */
374 PS_ADD("tpgid", "%d", 0); /* XXX */
375 PS_ADD("flags", "%u", 0); /* XXX */
376 PS_ADD("minflt", "%u", 0); /* XXX */
377 PS_ADD("cminflt", "%u", 0); /* XXX */
378 PS_ADD("majflt", "%u", 0); /* XXX */
379 PS_ADD("cminflt", "%u", 0); /* XXX */
380 PS_ADD("utime", "%d", 0); /* XXX */
381 PS_ADD("stime", "%d", 0); /* XXX */
382 PS_ADD("cutime", "%d", 0); /* XXX */
383 PS_ADD("cstime", "%d", 0); /* XXX */
384 PS_ADD("counter", "%d", 0); /* XXX */
385 PS_ADD("priority", "%d", 0); /* XXX */
386 PS_ADD("timeout", "%u", 0); /* XXX */
387 PS_ADD("itrealvalue", "%u", 0); /* XXX */
388 PS_ADD("starttime", "%d", 0); /* XXX */
389 PS_ADD("vsize", "%u", 0); /* XXX */
390 PS_ADD("rss", "%u", 0); /* XXX */
391 PS_ADD("rlim", "%u", 0); /* XXX */
392 PS_ADD("startcode", "%u", 0); /* XXX */
393 PS_ADD("endcode", "%u", 0); /* XXX */
394 PS_ADD("startstack", "%u", 0); /* XXX */
395 PS_ADD("kstkesp", "%u", 0); /* XXX */
396 PS_ADD("kstkeip", "%u", 0); /* XXX */
397 PS_ADD("signal", "%d", 0); /* XXX */
398 PS_ADD("blocked", "%d", 0); /* XXX */
399 PS_ADD("sigignore", "%d", 0); /* XXX */
400 PS_ADD("sigcatch", "%d", 0); /* XXX */
401 PS_ADD("wchan", "%u", 0); /* XXX */
403 ps += sprintf(ps, "\n");
406 xlen -= uio->uio_offset;
407 ps = psbuf + uio->uio_offset;
408 xlen = imin(xlen, uio->uio_resid);
409 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
413 * Map process state to descriptive letter. Note that this does not
414 * quite correspond to what Linux outputs, but it's close enough.
416 static char *state_str[] = {
428 linprocfs_doprocstatus(curp, p, pfs, uio)
434 char *ps, psbuf[1024];
440 if (p->p_stat > sizeof state_str / sizeof *state_str)
441 state = state_str[0];
443 state = state_str[(int)p->p_stat];
445 #define PS_ADD ps += sprintf
446 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
447 PS_ADD(ps, "State:\t%s\n", state);
452 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
453 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
454 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
456 p->p_ucred->cr_svuid,
457 /* FreeBSD doesn't have fsuid */
459 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
461 p->p_ucred->cr_svgid,
462 /* FreeBSD doesn't have fsgid */
464 PS_ADD(ps, "Groups:\t");
465 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
466 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
472 PS_ADD(ps, "VmSize:\t%8u kB\n", B2K(p->p_vmspace->vm_map.size));
473 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
474 /* XXX vm_rssize seems to always be zero, how can this be? */
475 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
476 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
477 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
478 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
479 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
484 * We support up to 128 signals, while Linux supports 32,
485 * but we only define 32 (the same 32 as Linux, to boot), so
486 * just show the lower 32 bits of each mask. XXX hack.
488 * NB: on certain platforms (Sparc at least) Linux actually
489 * supports 64 signals, but this code is a long way from
490 * running on anything but i386, so ignore that for now.
492 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
493 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
494 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
495 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
498 * Linux also prints the capability masks, but we don't have
499 * capabilities yet, and when we do get them they're likely to
500 * be meaningless to Linux programs, so we lie. XXX
502 PS_ADD(ps, "CapInh:\t%016x\n", 0);
503 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
504 PS_ADD(ps, "CapEff:\t%016x\n", 0);
508 xlen -= uio->uio_offset;
509 ps = psbuf + uio->uio_offset;
510 xlen = imin(xlen, uio->uio_resid);
511 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
517 linprocfs_doloadavg(curp, p, pfs, uio)
523 char *ps, psbuf[512];
529 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
530 (int)(averunnable.ldavg[0] / averunnable.fscale),
531 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
532 (int)(averunnable.ldavg[1] / averunnable.fscale),
533 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
534 (int)(averunnable.ldavg[2] / averunnable.fscale),
535 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
536 1, /* number of running tasks */
537 -1, /* number of tasks */
538 nextpid /* The last pid */
542 xlen -= uio->uio_offset;
543 ps = psbuf + uio->uio_offset;
544 xlen = imin(xlen, uio->uio_resid);
545 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));