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