linprocfs.c revision 67589
159412Smsmith/*
265577Sdes * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
365577Sdes * Copyright (c) 1999 Pierre Beyssac
459412Smsmith * Copyright (c) 1993 Jan-Simon Pendry
559412Smsmith * Copyright (c) 1993
659412Smsmith *	The Regents of the University of California.  All rights reserved.
759412Smsmith *
859412Smsmith * This code is derived from software contributed to Berkeley by
959412Smsmith * Jan-Simon Pendry.
1059412Smsmith *
1159412Smsmith * Redistribution and use in source and binary forms, with or without
1259412Smsmith * modification, are permitted provided that the following conditions
1359412Smsmith * are met:
1459412Smsmith * 1. Redistributions of source code must retain the above copyright
1559412Smsmith *    notice, this list of conditions and the following disclaimer.
1659412Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1759412Smsmith *    notice, this list of conditions and the following disclaimer in the
1859412Smsmith *    documentation and/or other materials provided with the distribution.
1959412Smsmith * 3. All advertising materials mentioning features or use of this software
2059412Smsmith *    must display the following acknowledgement:
2159412Smsmith *	This product includes software developed by the University of
2259412Smsmith *	California, Berkeley and its contributors.
2359412Smsmith * 4. Neither the name of the University nor the names of its contributors
2459412Smsmith *    may be used to endorse or promote products derived from this software
2559412Smsmith *    without specific prior written permission.
2659412Smsmith *
2759412Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2859412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2959412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3059412Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3159412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3259412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3359412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3459412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3559412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3659412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3759412Smsmith * SUCH DAMAGE.
3859412Smsmith *
3959412Smsmith *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
4059412Smsmith *
4159412Smsmith * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 67589 2000-10-25 22:38:23Z des $
4259412Smsmith */
4359412Smsmith
4459412Smsmith#include <sys/param.h>
4565633Sdes#include <sys/blist.h>
4665633Sdes#include <sys/dkstat.h>
4765633Sdes#include <sys/jail.h>
4865633Sdes#include <sys/kernel.h>
4965633Sdes#include <sys/proc.h>
5065633Sdes#include <sys/resourcevar.h>
5159412Smsmith#include <sys/systm.h>
5265633Sdes#include <sys/tty.h>
5359412Smsmith#include <sys/vnode.h>
5459412Smsmith
5559412Smsmith#include <vm/vm.h>
5659412Smsmith#include <vm/pmap.h>
5767588Sdes#include <vm/vm_map.h>
5859412Smsmith#include <vm/vm_param.h>
5960860Sdes#include <vm/vm_object.h>
6059412Smsmith#include <vm/swap_pager.h>
6159412Smsmith#include <sys/vmmeter.h>
6259412Smsmith#include <sys/exec.h>
6359412Smsmith
6467589Sdes#include <machine/clock.h>
6567589Sdes#include <machine/cputypes.h>
6659412Smsmith#include <machine/md_var.h>
6759412Smsmith
6865633Sdes#include <i386/linux/linprocfs/linprocfs.h>
6959412Smsmith
7067588Sdes/*
7167588Sdes * Various conversion macros
7267588Sdes */
7367588Sdes#define T2J(x) (((x) * 100) / (stathz ? stathz : hz))	/* ticks to jiffies */
7467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
7567588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
7667588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
7767588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
7865633Sdes
7959412Smsmithint
8059412Smsmithlinprocfs_domeminfo(curp, p, pfs, uio)
8159412Smsmith	struct proc *curp;
8259412Smsmith	struct proc *p;
8359412Smsmith	struct pfsnode *pfs;
8459412Smsmith	struct uio *uio;
8559412Smsmith{
8659412Smsmith	char *ps;
8759412Smsmith	int xlen;
8859412Smsmith	char psbuf[512];		/* XXX - conservative */
8959412Smsmith	unsigned long memtotal;		/* total memory in bytes */
9059412Smsmith	unsigned long memused;		/* used memory in bytes */
9159412Smsmith	unsigned long memfree;		/* free memory in bytes */
9259412Smsmith	unsigned long memshared;	/* shared memory ??? */
9359412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
9459412Smsmith	unsigned long swaptotal;	/* total swap space in bytes */
9559412Smsmith	unsigned long swapused;		/* used swap space in bytes */
9659412Smsmith	unsigned long swapfree;		/* free swap space in bytes */
9760860Sdes	vm_object_t object;
9859412Smsmith
9959412Smsmith	if (uio->uio_rw != UIO_READ)
10059412Smsmith		return (EOPNOTSUPP);
10159412Smsmith
10259412Smsmith	memtotal = physmem * PAGE_SIZE;
10359412Smsmith	/*
10459412Smsmith	 * The correct thing here would be:
10559412Smsmith	 *
10659412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
10759412Smsmith	memused = memtotal - memfree;
10859412Smsmith	 *
10959412Smsmith	 * but it might mislead linux binaries into thinking there
11059412Smsmith	 * is very little memory left, so we cheat and tell them that
11159412Smsmith	 * all memory that isn't wired down is free.
11259412Smsmith	 */
11359412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
11459412Smsmith	memfree = memtotal - memused;
11564560Sbde	if (swapblist == NULL) {
11664560Sbde		swaptotal = 0;
11764560Sbde		swapfree = 0;
11864560Sbde	} else {
11964560Sbde		swaptotal = swapblist->bl_blocks * 1024; /* XXX why 1024? */
12064560Sbde		swapfree = swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
12164560Sbde	}
12259412Smsmith	swapused = swaptotal - swapfree;
12360860Sdes	memshared = 0;
12460860Sdes	for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
12560860Sdes	    object = TAILQ_NEXT(object, object_list))
12660860Sdes		if (object->shadow_count > 1)
12760860Sdes			memshared += object->resident_page_count;
12860860Sdes	memshared *= PAGE_SIZE;
12959412Smsmith	/*
13059412Smsmith	 * We'd love to be able to write:
13159412Smsmith	 *
13259412Smsmith	buffers = bufspace;
13359412Smsmith	 *
13459412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
13559412Smsmith	 * like unstaticizing it just for linprocfs's sake.
13659412Smsmith	 */
13759412Smsmith	buffers = 0;
13859412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
13959412Smsmith
14059412Smsmith	ps = psbuf;
14159412Smsmith	ps += sprintf(ps,
14259412Smsmith		"        total:    used:    free:  shared: buffers:  cached:\n"
14359412Smsmith		"Mem:  %lu %lu %lu %lu %lu %lu\n"
14459412Smsmith		"Swap: %lu %lu %lu\n"
14559412Smsmith		"MemTotal: %9lu kB\n"
14659412Smsmith		"MemFree:  %9lu kB\n"
14759412Smsmith		"MemShared:%9lu kB\n"
14859412Smsmith		"Buffers:  %9lu kB\n"
14959412Smsmith		"Cached:   %9lu kB\n"
15059412Smsmith		"SwapTotal:%9lu kB\n"
15159412Smsmith		"SwapFree: %9lu kB\n",
15259412Smsmith		memtotal, memused, memfree, memshared, buffers, cached,
15359412Smsmith		swaptotal, swapused, swapfree,
15467588Sdes		B2K(memtotal), B2K(memfree),
15567588Sdes		B2K(memshared), B2K(buffers), B2K(cached),
15667588Sdes		B2K(swaptotal), B2K(swapfree));
15759412Smsmith
15859412Smsmith	xlen = ps - psbuf;
15959412Smsmith	xlen -= uio->uio_offset;
16059412Smsmith	ps = psbuf + uio->uio_offset;
16159412Smsmith	xlen = imin(xlen, uio->uio_resid);
16265633Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
16359412Smsmith}
16459412Smsmith
16559412Smsmithint
16659412Smsmithlinprocfs_docpuinfo(curp, p, pfs, uio)
16759412Smsmith	struct proc *curp;
16859412Smsmith	struct proc *p;
16959412Smsmith	struct pfsnode *pfs;
17059412Smsmith	struct uio *uio;
17159412Smsmith{
17259412Smsmith	char *ps;
17359412Smsmith	int xlen;
17459412Smsmith	char psbuf[512];		/* XXX - conservative */
17567589Sdes	int class;
17667589Sdes        int i;
17759412Smsmith#if 0
17859412Smsmith	extern char *cpu_model;		/* Yuck */
17959412Smsmith#endif
18067589Sdes        /* We default the flags to include all non-conflicting flags,
18167589Sdes           and the Intel versions of conflicting flags.  Note the space
18267589Sdes           before each name; that is significant, and should be
18367589Sdes           preserved. */
18459412Smsmith
18567589Sdes        static char *flags[] = {
18667589Sdes		"fpu",      "vme",     "de",       "pse",      "tsc",
18767589Sdes		"msr",      "pae",     "mce",      "cx8",      "apic",
18867589Sdes		"sep",      "sep",     "mtrr",     "pge",      "mca",
18967589Sdes		"cmov",     "pat",     "pse36",    "pn",       "b19",
19067589Sdes		"b20",      "b21",     "mmxext",   "mmx",      "fxsr",
19167589Sdes		"xmm",      "b26",     "b27",      "b28",      "b29",
19267589Sdes		"3dnowext", "3dnow"
19367589Sdes	};
19467589Sdes
19559412Smsmith	if (uio->uio_rw != UIO_READ)
19659412Smsmith		return (EOPNOTSUPP);
19759412Smsmith
19859412Smsmith	switch (cpu_class) {
19959412Smsmith	case CPUCLASS_286:
20067589Sdes		class = 2;
20159412Smsmith		break;
20259412Smsmith	case CPUCLASS_386:
20367589Sdes		class = 3;
20459412Smsmith		break;
20559412Smsmith	case CPUCLASS_486:
20667589Sdes		class = 4;
20759412Smsmith		break;
20859412Smsmith	case CPUCLASS_586:
20967589Sdes		class = 5;
21059412Smsmith		break;
21159412Smsmith	case CPUCLASS_686:
21267589Sdes		class = 6;
21359412Smsmith		break;
21459412Smsmith	default:
21567589Sdes                class = 0;
21659412Smsmith		break;
21759412Smsmith	}
21859412Smsmith
21959412Smsmith	ps = psbuf;
22059412Smsmith	ps += sprintf(ps,
22159412Smsmith			"processor       : %d\n"
22259412Smsmith			"vendor_id       : %.20s\n"
22367589Sdes			"cpu family      : %d\n"
22467589Sdes			"model           : %d\n"
22559412Smsmith			"stepping        : %d\n",
22667589Sdes			0, cpu_vendor, class, cpu, cpu_id & 0xf);
22759412Smsmith
22867589Sdes        ps += sprintf(ps,
22967589Sdes                        "flags           :");
23067589Sdes
23167589Sdes        if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
23267589Sdes		flags[16] = "fcmov";
23367589Sdes        } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
23467589Sdes		flags[24] = "cxmmx";
23567589Sdes        }
23667589Sdes
23767589Sdes        for (i = 0; i < 32; i++)
23867589Sdes		if (cpu_feature & (1 << i))
23967589Sdes			ps += sprintf(ps, " %s", flags[i]);
24067589Sdes	ps += sprintf(ps, "\n");
24167589Sdes        if (class >= 5) {
24267589Sdes		ps += sprintf(ps,
24367589Sdes			"cpu MHz         : %d.%02d\n",
24467589Sdes                        (tsc_freq + 4999) / 1000000,
24567589Sdes                        ((tsc_freq + 4999) / 10000) % 100);
24667589Sdes        }
24767589Sdes
24859412Smsmith	xlen = ps - psbuf;
24959412Smsmith	xlen -= uio->uio_offset;
25059412Smsmith	ps = psbuf + uio->uio_offset;
25159412Smsmith	xlen = imin(xlen, uio->uio_resid);
25265633Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
25359412Smsmith}
25465633Sdes
25565633Sdesint
25665633Sdeslinprocfs_dostat(curp, p, pfs, uio)
25765633Sdes	struct proc *curp;
25865633Sdes	struct proc *p;
25965633Sdes	struct pfsnode *pfs;
26065633Sdes	struct uio *uio;
26165633Sdes{
26265633Sdes        char *ps;
26365633Sdes	char psbuf[512];
26465633Sdes	int xlen;
26565633Sdes
26665633Sdes	ps = psbuf;
26765633Sdes	ps += sprintf(ps,
26865633Sdes		      "cpu %ld %ld %ld %ld\n"
26965633Sdes		      "disk 0 0 0 0\n"
27065633Sdes		      "page %u %u\n"
27165633Sdes		      "swap %u %u\n"
27265633Sdes		      "intr %u\n"
27365633Sdes		      "ctxt %u\n"
27465633Sdes		      "btime %ld\n",
27565633Sdes		      T2J(cp_time[CP_USER]),
27665633Sdes		      T2J(cp_time[CP_NICE]),
27765633Sdes		      T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
27865633Sdes		      T2J(cp_time[CP_IDLE]),
27965633Sdes		      cnt.v_vnodepgsin,
28065633Sdes		      cnt.v_vnodepgsout,
28165633Sdes		      cnt.v_swappgsin,
28265633Sdes		      cnt.v_swappgsout,
28365633Sdes		      cnt.v_intr,
28465633Sdes		      cnt.v_swtch,
28565633Sdes		      boottime.tv_sec);
28665633Sdes	xlen = ps - psbuf;
28765633Sdes	xlen -= uio->uio_offset;
28865633Sdes	ps = psbuf + uio->uio_offset;
28965633Sdes	xlen = imin(xlen, uio->uio_resid);
29065633Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
29165633Sdes}
29265633Sdes
29365633Sdesint
29465633Sdeslinprocfs_douptime(curp, p, pfs, uio)
29565633Sdes	struct proc *curp;
29665633Sdes	struct proc *p;
29765633Sdes	struct pfsnode *pfs;
29865633Sdes	struct uio *uio;
29965633Sdes{
30065633Sdes	char *ps;
30165633Sdes	int xlen;
30265633Sdes	char psbuf[64];
30365633Sdes	struct timeval tv;
30465633Sdes
30565633Sdes	getmicrouptime(&tv);
30665633Sdes	ps = psbuf;
30765633Sdes	ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n",
30865633Sdes		      tv.tv_sec, tv.tv_usec / 10000,
30965633Sdes		      T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
31065633Sdes	xlen = ps - psbuf;
31165633Sdes	xlen -= uio->uio_offset;
31265633Sdes	ps = psbuf + uio->uio_offset;
31365633Sdes	xlen = imin(xlen, uio->uio_resid);
31465633Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
31565633Sdes}
31665633Sdes
31765633Sdesint
31865633Sdeslinprocfs_doversion(curp, p, pfs, uio)
31965633Sdes	struct proc *curp;
32065633Sdes	struct proc *p;
32165633Sdes	struct pfsnode *pfs;
32265633Sdes	struct uio *uio;
32365633Sdes{
32465633Sdes        char *ps;
32565633Sdes	int xlen;
32665633Sdes
32765633Sdes	ps = version; /* XXX not entirely correct */
32865633Sdes	for (xlen = 0; ps[xlen] != '\n'; ++xlen)
32965633Sdes		/* nothing */ ;
33065633Sdes	++xlen;
33165633Sdes	xlen -= uio->uio_offset;
33265633Sdes	ps += uio->uio_offset;
33365633Sdes	xlen = imin(xlen, uio->uio_resid);
33465633Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
33565633Sdes}
33665633Sdes
33767588Sdesint
33867588Sdeslinprocfs_doprocstat(curp, p, pfs, uio)
33967588Sdes    	struct proc *curp;
34067588Sdes	struct proc *p;
34167588Sdes	struct pfsnode *pfs;
34267588Sdes	struct uio *uio;
34367588Sdes{
34467588Sdes	char *ps, psbuf[1024];
34567588Sdes	int xlen;
34667588Sdes
34767588Sdes	ps = psbuf;
34867588Sdes	ps += sprintf(ps, "%d", p->p_pid);
34967588Sdes#define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
35067588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
35167588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
35267588Sdes	PS_ADD("ppid",		"%d",	p->p_pptr->p_pid);
35367588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
35467588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
35567588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
35667588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
35767588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
35867588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
35967588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
36067588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
36167588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
36267588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
36367588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
36467588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
36567588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
36667588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
36767588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
36867588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
36967588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
37067588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
37167588Sdes	PS_ADD("vsize",		"%u",	0); /* XXX */
37267588Sdes	PS_ADD("rss",		"%u",	0); /* XXX */
37367588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
37467588Sdes	PS_ADD("startcode",	"%u",	0); /* XXX */
37567588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
37667588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
37767588Sdes	PS_ADD("kstkesp",	"%u",	0); /* XXX */
37867588Sdes	PS_ADD("kstkeip",	"%u",	0); /* XXX */
37967588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
38067588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
38167588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
38267588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
38367588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
38467588Sdes#undef PS_ADD
38567588Sdes	ps += sprintf(ps, "\n");
38667588Sdes
38767588Sdes	xlen = ps - psbuf;
38867588Sdes	xlen -= uio->uio_offset;
38967588Sdes	ps = psbuf + uio->uio_offset;
39067588Sdes	xlen = imin(xlen, uio->uio_resid);
39167588Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
39267588Sdes}
39367588Sdes
39467588Sdes/*
39567588Sdes * Map process state to descriptive letter. Note that this does not
39667588Sdes * quite correspond to what Linux outputs, but it's close enough.
39767588Sdes */
39867588Sdesstatic char *state_str[] = {
39967588Sdes	"? (unknown)",
40067588Sdes	"I (idle)",
40167588Sdes	"R (running)",
40267588Sdes	"S (sleeping)",
40367588Sdes	"T (stopped)",
40467588Sdes	"Z (zombie)",
40567588Sdes	"W (waiting)",
40667588Sdes	"M (mutex)"
40767588Sdes};
40867588Sdes
40967588Sdesint
41067588Sdeslinprocfs_doprocstatus(curp, p, pfs, uio)
41167588Sdes    	struct proc *curp;
41267588Sdes	struct proc *p;
41367588Sdes	struct pfsnode *pfs;
41467588Sdes	struct uio *uio;
41567588Sdes{
41667588Sdes	char *ps, psbuf[1024];
41767588Sdes	char *state;
41867588Sdes	int i, xlen;
41967588Sdes
42067588Sdes	ps = psbuf;
42167588Sdes
42267588Sdes	if (p->p_stat > sizeof state_str / sizeof *state_str)
42367588Sdes		state = state_str[0];
42467588Sdes	else
42567588Sdes		state = state_str[(int)p->p_stat];
42667588Sdes
42767588Sdes#define PS_ADD ps += sprintf
42867588Sdes	PS_ADD(ps, "Name:\t%s\n",	  p->p_comm); /* XXX escape */
42967588Sdes	PS_ADD(ps, "State:\t%s\n",	  state);
43067588Sdes
43167588Sdes	/*
43267588Sdes	 * Credentials
43367588Sdes	 */
43467588Sdes	PS_ADD(ps, "Pid:\t%d\n",	  p->p_pid);
43567588Sdes	PS_ADD(ps, "PPid:\t%d\n",	  p->p_pptr->p_pid);
43667588Sdes	PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid,
43767588Sdes		                          p->p_ucred->cr_uid,
43867588Sdes		                          p->p_cred->p_svuid,
43967588Sdes		                          /* FreeBSD doesn't have fsuid */
44067588Sdes		                          p->p_ucred->cr_uid);
44167588Sdes	PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid,
44267588Sdes		                          p->p_ucred->cr_gid,
44367588Sdes		                          p->p_cred->p_svgid,
44467588Sdes		                          /* FreeBSD doesn't have fsgid */
44567588Sdes		                          p->p_ucred->cr_gid);
44667588Sdes	PS_ADD(ps, "Groups:\t");
44767588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
44867588Sdes		PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
44967588Sdes	PS_ADD(ps, "\n");
45067588Sdes
45167588Sdes	/*
45267588Sdes	 * Memory
45367588Sdes	 */
45467588Sdes	PS_ADD(ps, "VmSize:\t%8u kB\n",	  B2K(p->p_vmspace->vm_map.size));
45567588Sdes	PS_ADD(ps, "VmLck:\t%8u kB\n",    P2K(0)); /* XXX */
45667588Sdes	/* XXX vm_rssize seems to always be zero, how can this be? */
45767588Sdes	PS_ADD(ps, "VmRss:\t%8u kB\n",    P2K(p->p_vmspace->vm_rssize));
45867588Sdes	PS_ADD(ps, "VmData:\t%8u kB\n",   P2K(p->p_vmspace->vm_dsize));
45967588Sdes	PS_ADD(ps, "VmStk:\t%8u kB\n",    P2K(p->p_vmspace->vm_ssize));
46067588Sdes	PS_ADD(ps, "VmExe:\t%8u kB\n",    P2K(p->p_vmspace->vm_tsize));
46167588Sdes	PS_ADD(ps, "VmLib:\t%8u kB\n",    P2K(0)); /* XXX */
46267588Sdes
46367588Sdes	/*
46467588Sdes	 * Signal masks
46567588Sdes	 *
46667588Sdes	 * We support up to 128 signals, while Linux supports 32,
46767588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
46867588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
46967588Sdes	 *
47067588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
47167588Sdes	 * supports 64 signals, but this code is a long way from
47267588Sdes	 * running on anything but i386, so ignore that for now.
47367588Sdes	 */
47467588Sdes	PS_ADD(ps, "SigPnd:\t%08x\n",	  p->p_siglist.__bits[0]);
47567588Sdes	PS_ADD(ps, "SigBlk:\t%08x\n",	  0); /* XXX */
47667588Sdes	PS_ADD(ps, "SigIgn:\t%08x\n",	  p->p_sigignore.__bits[0]);
47767588Sdes	PS_ADD(ps, "SigCgt:\t%08x\n",	  p->p_sigcatch.__bits[0]);
47867588Sdes
47967588Sdes	/*
48067588Sdes	 * Linux also prints the capability masks, but we don't have
48167588Sdes	 * capabilities yet, and when we do get them they're likely to
48267588Sdes	 * be meaningless to Linux programs, so we lie. XXX
48367588Sdes	 */
48467588Sdes	PS_ADD(ps, "CapInh:\t%016x\n",	  0);
48567588Sdes	PS_ADD(ps, "CapPrm:\t%016x\n",	  0);
48667588Sdes	PS_ADD(ps, "CapEff:\t%016x\n",	  0);
48767588Sdes#undef PS_ADD
48867588Sdes
48967588Sdes	xlen = ps - psbuf;
49067588Sdes	xlen -= uio->uio_offset;
49167588Sdes	ps = psbuf + uio->uio_offset;
49267588Sdes	xlen = imin(xlen, uio->uio_resid);
49367588Sdes	return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
49467588Sdes}
495