6be0e01e9d5878f5f08205ec3363327f04a783ad
[dragonfly.git] / sys / emulation / linux / i386 / linprocfs / linprocfs_misc.c
blob6be0e01e9d5878f5f08205ec3363327f04a783ad
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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
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.
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.
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.19 2008/05/10 17:24:05 dillon Exp $
45 #include <sys/param.h>
46 #include <sys/blist.h>
47 #include <sys/kernel.h>
48 #include <sys/kinfo.h>
49 #include <sys/proc.h>
50 #include <sys/jail.h>
51 #include <sys/resourcevar.h>
52 #include <sys/systm.h>
53 #include <sys/tty.h>
54 #include <sys/vnode.h>
55 #include <sys/lock.h>
57 #include <vm/vm.h>
58 #include <vm/pmap.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>
64 #include <sys/exec.h>
66 #include <machine/clock.h>
67 #include <machine/cputypes.h>
68 #include <machine/inttypes.h>
69 #include <machine/md_var.h>
71 #include "linprocfs.h"
74 * Various conversion macros
76 #define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */
77 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
78 #define B2K(x) ((unsigned long)((x) >> 10)) /* bytes to kbytes */
79 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
80 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
82 int
83 linprocfs_domeminfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
84 struct uio *uio)
86 char *ps;
87 char psbuf[512]; /* XXX - conservative */
88 unsigned long memtotal; /* total memory in bytes */
89 unsigned long memused; /* used memory in bytes */
90 unsigned long memfree; /* free memory in bytes */
91 unsigned long memshared; /* shared memory ??? */
92 unsigned long buffers, cached; /* buffer / cache memory ??? */
93 unsigned long long swaptotal; /* total swap space in bytes */
94 unsigned long long swapused; /* used swap space in bytes */
95 unsigned long long swapfree; /* free swap space in bytes */
96 vm_object_t object;
98 if (uio->uio_rw != UIO_READ)
99 return (EOPNOTSUPP);
101 memtotal = Maxmem * PAGE_SIZE;
103 * The correct thing here would be:
105 memfree = vmstats.v_free_count * PAGE_SIZE;
106 memused = memtotal - memfree;
108 * but it might mislead linux binaries into thinking there
109 * is very little memory left, so we cheat and tell them that
110 * all memory that isn't wired down is free.
112 memused = vmstats.v_wire_count * PAGE_SIZE;
113 memfree = memtotal - memused;
114 if (swapblist == NULL) {
115 swaptotal = 0;
116 swapfree = 0;
117 } else {
118 swaptotal = swapblist->bl_blocks * 1024LL; /* XXX why 1024? */
119 swapfree = (unsigned long long)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
121 swapused = swaptotal - swapfree;
122 memshared = 0;
123 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
124 object = TAILQ_NEXT(object, object_list)) {
125 if (object->type == OBJT_MARKER)
126 continue;
127 if (object->shadow_count > 1)
128 memshared += object->resident_page_count;
130 memshared *= PAGE_SIZE;
132 * We'd love to be able to write:
134 buffers = bufspace;
136 * but bufspace is internal to vfs_bio.c and we don't feel
137 * like unstaticizing it just for linprocfs's sake.
139 buffers = 0;
140 cached = vmstats.v_cache_count * PAGE_SIZE;
142 ps = psbuf;
143 ps += ksprintf(ps,
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"
148 "MemFree: %9lu kB\n"
149 "MemShared:%9lu kB\n"
150 "Buffers: %9lu kB\n"
151 "Cached: %9lu kB\n"
152 "SwapTotal:%9lu kB\n"
153 "SwapFree: %9lu 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));
160 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
164 linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
165 struct uio *uio)
167 char *ps;
168 char psbuf[512]; /* XXX - conservative */
169 int class;
170 int i;
171 #if 0
172 extern char *cpu_model; /* Yuck */
173 #endif
174 /* We default the flags to include all non-conflicting flags,
175 and the Intel versions of conflicting flags. Note the space
176 before each name; that is significant, and should be
177 preserved. */
179 static char *flags[] = {
180 "fpu", "vme", "de", "pse", "tsc",
181 "msr", "pae", "mce", "cx8", "apic",
182 "sep", "sep", "mtrr", "pge", "mca",
183 "cmov", "pat", "pse36", "pn", "b19",
184 "b20", "b21", "mmxext", "mmx", "fxsr",
185 "xmm", "b26", "b27", "b28", "b29",
186 "3dnowext", "3dnow"
189 if (uio->uio_rw != UIO_READ)
190 return (EOPNOTSUPP);
192 switch (cpu_class) {
193 case CPUCLASS_286:
194 class = 2;
195 break;
196 case CPUCLASS_386:
197 class = 3;
198 break;
199 case CPUCLASS_486:
200 class = 4;
201 break;
202 case CPUCLASS_586:
203 class = 5;
204 break;
205 case CPUCLASS_686:
206 class = 6;
207 break;
208 default:
209 class = 0;
210 break;
213 ps = psbuf;
214 ps += ksprintf(ps,
215 "processor\t: %d\n"
216 "vendor_id\t: %.20s\n"
217 "cpu family\t: %d\n"
218 "model\t\t: %d\n"
219 "stepping\t: %d\n",
220 0, cpu_vendor, class, cpu, cpu_id & 0xf);
222 ps += ksprintf(ps,
223 "flags\t\t:");
225 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
226 flags[16] = "fcmov";
227 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
228 flags[24] = "cxmmx";
231 for (i = 0; i < 32; i++)
232 if (cpu_feature & (1 << i))
233 ps += ksprintf(ps, " %s", flags[i]);
234 ps += ksprintf(ps, "\n");
235 if (class >= 5) {
236 ps += ksprintf(ps,
237 "cpu MHz\t\t: %d.%02d\n"
238 "bogomips\t: %d.%02d\n",
239 (int)((tsc_frequency + 4999) / 1000000),
240 (int)((tsc_frequency + 4999) / 10000) % 100,
241 (int)((tsc_frequency + 4999) / 1000000),
242 (int)((tsc_frequency + 4999) / 10000) % 100);
245 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
248 static unsigned int
249 cpucnt(int offset)
251 int i;
252 int count = 0;
254 for (i = 0; i < ncpus; ++i) {
255 struct globaldata *gd = globaldata_find(i);
256 count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
258 return(count);
262 linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
263 struct uio *uio)
265 char *ps;
266 char psbuf[512];
268 ps = psbuf;
269 ps += ksprintf(ps,
270 "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n"
271 "disk 0 0 0 0\n"
272 "page %u %u\n"
273 "swap %u %u\n"
274 "intr %u\n"
275 "ctxt %u\n"
276 "btime %ld\n",
277 T2J(cpu_time.cp_user),
278 T2J(cpu_time.cp_nice),
279 T2J(cpu_time.cp_sys /*+ cpu_time[CP_INTR]*/),
280 T2J(cpu_time.cp_idle),
281 cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
282 cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
283 cpucnt(offsetof(struct vmmeter, v_swappgsin)),
284 cpucnt(offsetof(struct vmmeter, v_swappgsout)),
285 cpucnt(offsetof(struct vmmeter, v_intr)),
286 cpucnt(offsetof(struct vmmeter, v_swtch)),
287 boottime.tv_sec);
288 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
292 linprocfs_douptime(struct proc *curp, struct proc *p, struct pfsnode *pfs,
293 struct uio *uio)
295 char *ps;
296 char psbuf[64];
297 struct timeval tv;
299 getmicrouptime(&tv);
300 ps = psbuf;
301 ps += ksprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
302 tv.tv_sec, tv.tv_usec / 10000,
303 T2S(cpu_time.cp_idle), T2J(cpu_time.cp_idle) % 100);
304 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
308 linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
309 struct uio *uio)
311 char *ps;
312 size_t xlen;
314 ps = version; /* XXX not entirely correct */
315 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
316 /* nothing */ ;
317 ++xlen;
318 return (uiomove_frombuf(ps, xlen, uio));
322 linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
323 struct uio *uio)
325 char *ps, psbuf[1024];
327 ps = psbuf;
328 ps += ksprintf(ps, "%d", p->p_pid);
329 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
330 PS_ADD("comm", "(%s)", p->p_comm);
331 PS_ADD("statr", "%c", '0'); /* XXX */
332 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
333 PS_ADD("pgrp", "%d", p->p_pgid);
334 PS_ADD("session", "%d", p->p_session->s_sid);
335 PS_ADD("tty", "%d", 0); /* XXX */
336 PS_ADD("tpgid", "%d", 0); /* XXX */
337 PS_ADD("flags", "%u", 0); /* XXX */
338 PS_ADD("minflt", "%u", 0); /* XXX */
339 PS_ADD("cminflt", "%u", 0); /* XXX */
340 PS_ADD("majflt", "%u", 0); /* XXX */
341 PS_ADD("cminflt", "%u", 0); /* XXX */
342 PS_ADD("utime", "%d", 0); /* XXX */
343 PS_ADD("stime", "%d", 0); /* XXX */
344 PS_ADD("cutime", "%d", 0); /* XXX */
345 PS_ADD("cstime", "%d", 0); /* XXX */
346 PS_ADD("counter", "%d", 0); /* XXX */
347 PS_ADD("priority", "%d", 0); /* XXX */
348 PS_ADD("timeout", "%u", 0); /* XXX */
349 PS_ADD("itrealvalue", "%u", 0); /* XXX */
350 PS_ADD("starttime", "%d", 0); /* XXX */
351 PS_ADD("vsize", "%u", 0); /* XXX */
352 PS_ADD("rss", "%u", 0); /* XXX */
353 PS_ADD("rlim", "%u", 0); /* XXX */
354 PS_ADD("startcode", "%u", 0); /* XXX */
355 PS_ADD("endcode", "%u", 0); /* XXX */
356 PS_ADD("startstack", "%u", 0); /* XXX */
357 PS_ADD("kstkesp", "%u", 0); /* XXX */
358 PS_ADD("kstkeip", "%u", 0); /* XXX */
359 PS_ADD("signal", "%d", 0); /* XXX */
360 PS_ADD("blocked", "%d", 0); /* XXX */
361 PS_ADD("sigignore", "%d", 0); /* XXX */
362 PS_ADD("sigcatch", "%d", 0); /* XXX */
363 PS_ADD("wchan", "%u", 0); /* XXX */
364 #undef PS_ADD
365 ps += ksprintf(ps, "\n");
367 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
371 * Map process state to descriptive letter. Note that this does not
372 * quite correspond to what Linux outputs, but it's close enough.
374 static char *state_str[] = {
375 "? (unknown)",
376 "I (idle)",
377 "R (running)",
378 "T (stopped)",
379 "Z (zombie)",
380 "S (sleeping)",
381 "W (waiting)",
382 "M (mutex)"
386 linprocfs_doprocstatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
387 struct uio *uio)
389 char *ps, psbuf[1024];
390 char *state;
391 int i;
393 ps = psbuf;
395 if (p->p_stat > sizeof state_str / sizeof *state_str)
396 state = state_str[0];
397 else
398 state = state_str[(int)p->p_stat];
400 #define PS_ADD ps += ksprintf
401 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
402 PS_ADD(ps, "State:\t%s\n", state);
405 * Credentials
407 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
408 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
409 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
410 p->p_ucred->cr_uid,
411 p->p_ucred->cr_svuid,
412 /* FreeBSD doesn't have fsuid */
413 p->p_ucred->cr_uid);
414 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
415 p->p_ucred->cr_gid,
416 p->p_ucred->cr_svgid,
417 /* FreeBSD doesn't have fsgid */
418 p->p_ucred->cr_gid);
419 PS_ADD(ps, "Groups:\t");
420 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
421 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
422 PS_ADD(ps, "\n");
425 * Memory
427 PS_ADD(ps, "VmSize:\t%8lu kB\n", B2K(p->p_vmspace->vm_map.size));
428 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
429 /* XXX vm_rssize seems to always be zero, how can this be? */
430 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
431 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
432 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
433 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
434 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
437 * Signal masks
439 * We support up to 128 signals, while Linux supports 32,
440 * but we only define 32 (the same 32 as Linux, to boot), so
441 * just show the lower 32 bits of each mask. XXX hack.
443 * NB: on certain platforms (Sparc at least) Linux actually
444 * supports 64 signals, but this code is a long way from
445 * running on anything but i386, so ignore that for now.
447 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
448 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
449 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
450 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
453 * Linux also prints the capability masks, but we don't have
454 * capabilities yet, and when we do get them they're likely to
455 * be meaningless to Linux programs, so we lie. XXX
457 PS_ADD(ps, "CapInh:\t%016x\n", 0);
458 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
459 PS_ADD(ps, "CapEff:\t%016x\n", 0);
460 #undef PS_ADD
462 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
466 linprocfs_doloadavg(struct proc *curp, struct proc *p,
467 struct pfsnode *pfs, struct uio *uio)
469 char *ps, psbuf[512];
471 ps = psbuf;
472 ps += ksprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
473 (int)(averunnable.ldavg[0] / averunnable.fscale),
474 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
475 (int)(averunnable.ldavg[1] / averunnable.fscale),
476 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
477 (int)(averunnable.ldavg[2] / averunnable.fscale),
478 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
479 1, /* number of running tasks */
480 -1, /* number of tasks */
481 1 /* The last pid, just kidding */
483 return(uiomove_frombuf(psbuf, ps - psbuf, uio));