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