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