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 $
44 #include <sys/param.h>
45 #include <sys/blist.h>
46 #include <sys/dkstat.h>
48 #include <sys/kernel.h>
50 #include <sys/resourcevar.h>
51 #include <sys/systm.h>
53 #include <sys/vnode.h>
58 #include <vm/vm_map.h>
59 #include <vm/vm_param.h>
60 #include <vm/vm_object.h>
61 #include <vm/swap_pager.h>
62 #include <sys/vmmeter.h>
65 #include <machine/clock.h>
66 #include <machine/cputypes.h>
67 #include <machine/md_var.h>
69 #include <i386/linux/linprocfs/linprocfs.h>
72 * Various conversion macros
74 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
75 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
76 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
77 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
78 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
81 linprocfs_domeminfo(curp, p, pfs, uio)
89 char psbuf[512]; /* XXX - conservative */
90 unsigned long memtotal; /* total memory in bytes */
91 unsigned long memused; /* used memory in bytes */
92 unsigned long memfree; /* free memory in bytes */
93 unsigned long memshared; /* shared memory ??? */
94 unsigned long buffers, cached; /* buffer / cache memory ??? */
95 unsigned long long swaptotal; /* total swap space in bytes */
96 unsigned long long swapused; /* used swap space in bytes */
97 unsigned long long swapfree; /* free swap space in bytes */
100 if (uio->uio_rw != UIO_READ)
103 memtotal = physmem * PAGE_SIZE;
105 * The correct thing here would be:
107 memfree = cnt.v_free_count * PAGE_SIZE;
108 memused = memtotal - memfree;
110 * but it might mislead linux binaries into thinking there
111 * is very little memory left, so we cheat and tell them that
112 * all memory that isn't wired down is free.
114 memused = cnt.v_wire_count * PAGE_SIZE;
115 memfree = memtotal - memused;
116 if (swapblist == NULL) {
120 swaptotal = (unsigned long long) swapblist->bl_blocks * 1024ULL; /* XXX why 1024? */
121 swapfree = (unsigned long long) swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
123 swapused = swaptotal - swapfree;
125 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
126 object = TAILQ_NEXT(object, object_list))
127 if (object->shadow_count > 1)
128 memshared += object->resident_page_count;
129 memshared *= PAGE_SIZE;
131 * We'd love to be able to write:
135 * but bufspace is internal to vfs_bio.c and we don't feel
136 * like unstaticizing it just for linprocfs's sake.
139 cached = cnt.v_cache_count * PAGE_SIZE;
143 " total: used: free: shared: buffers: cached:\n"
144 "Mem: %lu %lu %lu %lu %lu %lu\n"
145 "Swap: %llu %llu %llu\n"
146 "MemTotal: %9lu kB\n"
148 "MemShared:%9lu kB\n"
151 "SwapTotal:%9llu kB\n"
152 "SwapFree: %9llu kB\n",
153 memtotal, memused, memfree, memshared, buffers, cached,
154 swaptotal, swapused, swapfree,
155 B2K(memtotal), B2K(memfree),
156 B2K(memshared), B2K(buffers), B2K(cached),
157 B2K(swaptotal), B2K(swapfree));
160 xlen -= uio->uio_offset;
161 ps = psbuf + uio->uio_offset;
162 xlen = imin(xlen, uio->uio_resid);
163 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
167 linprocfs_docpuinfo(curp, p, pfs, uio)
175 char psbuf[512]; /* XXX - conservative */
179 extern char *cpu_model; /* Yuck */
181 /* We default the flags to include all non-conflicting flags,
182 and the Intel versions of conflicting flags. Note the space
183 before each name; that is significant, and should be
186 static char *flags[] = {
187 "fpu", "vme", "de", "pse", "tsc",
188 "msr", "pae", "mce", "cx8", "apic",
189 "sep", "sep", "mtrr", "pge", "mca",
190 "cmov", "pat", "pse36", "pn", "b19",
191 "b20", "b21", "mmxext", "mmx", "fxsr",
192 "xmm", "b26", "b27", "b28", "b29",
196 if (uio->uio_rw != UIO_READ)
223 "vendor_id\t: %.20s\n"
227 0, cpu_vendor, class, cpu, cpu_id & 0xf);
232 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
234 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
238 for (i = 0; i < 32; i++)
239 if (cpu_feature & (1 << i))
240 ps += sprintf(ps, " %s", flags[i]);
241 ps += sprintf(ps, "\n");
244 "cpu MHz\t\t: %d.%02d\n"
245 "bogomips\t: %d.%02d\n",
246 (tsc_freq + 4999) / 1000000,
247 ((tsc_freq + 4999) / 10000) % 100,
248 (tsc_freq + 4999) / 1000000,
249 ((tsc_freq + 4999) / 10000) % 100);
253 xlen -= uio->uio_offset;
254 ps = psbuf + uio->uio_offset;
255 xlen = imin(xlen, uio->uio_resid);
256 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
260 linprocfs_dostat(curp, p, pfs, uio)
272 "cpu %ld %ld %ld %ld\n"
279 T2J(cp_time[CP_USER]),
280 T2J(cp_time[CP_NICE]),
281 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
282 T2J(cp_time[CP_IDLE]),
291 xlen -= uio->uio_offset;
292 ps = psbuf + uio->uio_offset;
293 xlen = imin(xlen, uio->uio_resid);
294 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
298 linprocfs_douptime(curp, p, pfs, uio)
311 ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n",
312 tv.tv_sec, tv.tv_usec / 10000,
313 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
315 xlen -= uio->uio_offset;
316 ps = psbuf + uio->uio_offset;
317 xlen = imin(xlen, uio->uio_resid);
318 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
322 linprocfs_doversion(curp, p, pfs, uio)
331 ps = version; /* XXX not entirely correct */
332 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
335 xlen -= uio->uio_offset;
336 ps += uio->uio_offset;
337 xlen = imin(xlen, uio->uio_resid);
338 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
342 linprocfs_doprocstat(curp, p, pfs, uio)
348 char *ps, psbuf[1024];
352 ps += sprintf(ps, "%d", p->p_pid);
353 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
354 PS_ADD("comm", "(%s)", p->p_comm);
355 PS_ADD("statr", "%c", '0'); /* XXX */
356 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
357 PS_ADD("pgrp", "%d", p->p_pgid);
358 PS_ADD("session", "%d", p->p_session->s_sid);
359 PS_ADD("tty", "%d", 0); /* XXX */
360 PS_ADD("tpgid", "%d", 0); /* XXX */
361 PS_ADD("flags", "%u", 0); /* XXX */
362 PS_ADD("minflt", "%u", 0); /* XXX */
363 PS_ADD("cminflt", "%u", 0); /* XXX */
364 PS_ADD("majflt", "%u", 0); /* XXX */
365 PS_ADD("cminflt", "%u", 0); /* XXX */
366 PS_ADD("utime", "%d", 0); /* XXX */
367 PS_ADD("stime", "%d", 0); /* XXX */
368 PS_ADD("cutime", "%d", 0); /* XXX */
369 PS_ADD("cstime", "%d", 0); /* XXX */
370 PS_ADD("counter", "%d", 0); /* XXX */
371 PS_ADD("priority", "%d", 0); /* XXX */
372 PS_ADD("timeout", "%u", 0); /* XXX */
373 PS_ADD("itrealvalue", "%u", 0); /* XXX */
374 PS_ADD("starttime", "%d", 0); /* XXX */
375 PS_ADD("vsize", "%u", 0); /* XXX */
376 PS_ADD("rss", "%u", 0); /* XXX */
377 PS_ADD("rlim", "%u", 0); /* XXX */
378 PS_ADD("startcode", "%u", 0); /* XXX */
379 PS_ADD("endcode", "%u", 0); /* XXX */
380 PS_ADD("startstack", "%u", 0); /* XXX */
381 PS_ADD("kstkesp", "%u", 0); /* XXX */
382 PS_ADD("kstkeip", "%u", 0); /* XXX */
383 PS_ADD("signal", "%d", 0); /* XXX */
384 PS_ADD("blocked", "%d", 0); /* XXX */
385 PS_ADD("sigignore", "%d", 0); /* XXX */
386 PS_ADD("sigcatch", "%d", 0); /* XXX */
387 PS_ADD("wchan", "%u", 0); /* XXX */
389 ps += sprintf(ps, "\n");
392 xlen -= uio->uio_offset;
393 ps = psbuf + uio->uio_offset;
394 xlen = imin(xlen, uio->uio_resid);
395 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
399 * Map process state to descriptive letter. Note that this does not
400 * quite correspond to what Linux outputs, but it's close enough.
402 static char *state_str[] = {
414 linprocfs_doprocstatus(curp, p, pfs, uio)
420 char *ps, psbuf[1024];
426 if (p->p_stat > sizeof state_str / sizeof *state_str)
427 state = state_str[0];
429 state = state_str[(int)p->p_stat];
431 #define PS_ADD ps += sprintf
432 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
433 PS_ADD(ps, "State:\t%s\n", state);
438 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
439 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
440 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid,
443 /* FreeBSD doesn't have fsuid */
445 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid,
448 /* FreeBSD doesn't have fsgid */
450 PS_ADD(ps, "Groups:\t");
451 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
452 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
458 PS_ADD(ps, "VmSize:\t%8u kB\n", B2K(p->p_vmspace->vm_map.size));
459 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
460 /* XXX vm_rssize seems to always be zero, how can this be? */
461 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
462 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
463 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
464 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
465 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
470 * We support up to 128 signals, while Linux supports 32,
471 * but we only define 32 (the same 32 as Linux, to boot), so
472 * just show the lower 32 bits of each mask. XXX hack.
474 * NB: on certain platforms (Sparc at least) Linux actually
475 * supports 64 signals, but this code is a long way from
476 * running on anything but i386, so ignore that for now.
478 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
479 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
480 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
481 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
484 * Linux also prints the capability masks, but we don't have
485 * capabilities yet, and when we do get them they're likely to
486 * be meaningless to Linux programs, so we lie. XXX
488 PS_ADD(ps, "CapInh:\t%016x\n", 0);
489 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
490 PS_ADD(ps, "CapEff:\t%016x\n", 0);
494 xlen -= uio->uio_offset;
495 ps = psbuf + uio->uio_offset;
496 xlen = imin(xlen, uio->uio_resid);
497 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
501 linprocfs_doloadavg(curp, p, pfs, uio)
507 char *ps, psbuf[512];
514 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
515 (int)(averunnable.ldavg[0] / averunnable.fscale),
516 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
517 (int)(averunnable.ldavg[1] / averunnable.fscale),
518 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
519 (int)(averunnable.ldavg[2] / averunnable.fscale),
520 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
521 1, /* number of running tasks */
522 -1, /* number of tasks */
523 nextpid /* The last pid */
527 xlen -= uio->uio_offset;
528 ps = psbuf + uio->uio_offset;
529 xlen = imin(xlen, uio->uio_resid);
530 return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));