linprocfs.c revision 119923
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
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 119923 2003-09-09 19:22:55Z des $");
44
45#include <sys/param.h>
46#include <sys/queue.h>
47#include <sys/blist.h>
48#include <sys/conf.h>
49#include <sys/exec.h>
50#include <sys/filedesc.h>
51#include <sys/jail.h>
52#include <sys/kernel.h>
53#include <sys/linker.h>
54#include <sys/lock.h>
55#include <sys/malloc.h>
56#include <sys/mount.h>
57#include <sys/mutex.h>
58#include <sys/namei.h>
59#include <sys/proc.h>
60#include <sys/resourcevar.h>
61#include <sys/sbuf.h>
62#include <sys/socket.h>
63#include <sys/sysctl.h>
64#include <sys/systm.h>
65#include <sys/tty.h>
66#include <sys/user.h>
67#include <sys/vmmeter.h>
68#include <sys/vnode.h>
69
70#include <net/if.h>
71
72#include <vm/vm.h>
73#include <vm/pmap.h>
74#include <vm/vm_map.h>
75#include <vm/vm_param.h>
76#include <vm/vm_object.h>
77#include <vm/swap_pager.h>
78
79#include <machine/clock.h>
80
81#ifdef __alpha__
82#include <machine/alpha_cpu.h>
83#include <machine/cpuconf.h>
84#include <machine/rpb.h>
85extern int ncpus;
86#endif /* __alpha__ */
87
88#ifdef __i386__
89#include <machine/cputypes.h>
90#include <machine/md_var.h>
91#endif /* __i386__ */
92
93#include <machine/../linux/linux.h>
94#include <compat/linux/linux_ioctl.h>
95#include <compat/linux/linux_mib.h>
96#include <compat/linux/linux_util.h>
97#include <fs/pseudofs/pseudofs.h>
98#include <fs/procfs/procfs.h>
99
100/*
101 * Various conversion macros
102 */
103#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
104#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
105#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
106#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
107#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
108#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
109
110/*
111 * Filler function for proc/meminfo
112 */
113static int
114linprocfs_domeminfo(PFS_FILL_ARGS)
115{
116	unsigned long memtotal;		/* total memory in bytes */
117	unsigned long memused;		/* used memory in bytes */
118	unsigned long memfree;		/* free memory in bytes */
119	unsigned long memshared;	/* shared memory ??? */
120	unsigned long buffers, cached;	/* buffer / cache memory ??? */
121	unsigned long long swaptotal;	/* total swap space in bytes */
122	unsigned long long swapused;	/* used swap space in bytes */
123	unsigned long long swapfree;	/* free swap space in bytes */
124	vm_object_t object;
125	int i, j;
126
127	memtotal = physmem * PAGE_SIZE;
128	/*
129	 * The correct thing here would be:
130	 *
131	memfree = cnt.v_free_count * PAGE_SIZE;
132	memused = memtotal - memfree;
133	 *
134	 * but it might mislead linux binaries into thinking there
135	 * is very little memory left, so we cheat and tell them that
136	 * all memory that isn't wired down is free.
137	 */
138	memused = cnt.v_wire_count * PAGE_SIZE;
139	memfree = memtotal - memused;
140	swap_pager_status(&i, &j);
141	swaptotal = i * PAGE_SIZE;
142	swapused = j * PAGE_SIZE;
143	swapfree = swaptotal - swapused;
144	memshared = 0;
145	TAILQ_FOREACH(object, &vm_object_list, object_list)
146		if (object->shadow_count > 1)
147			memshared += object->resident_page_count;
148	memshared *= PAGE_SIZE;
149	/*
150	 * We'd love to be able to write:
151	 *
152	buffers = bufspace;
153	 *
154	 * but bufspace is internal to vfs_bio.c and we don't feel
155	 * like unstaticizing it just for linprocfs's sake.
156	 */
157	buffers = 0;
158	cached = cnt.v_cache_count * PAGE_SIZE;
159
160	sbuf_printf(sb,
161	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
162	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
163	    "Swap: %llu %llu %llu\n"
164	    "MemTotal: %9lu kB\n"
165	    "MemFree:  %9lu kB\n"
166	    "MemShared:%9lu kB\n"
167	    "Buffers:  %9lu kB\n"
168	    "Cached:   %9lu kB\n"
169	    "SwapTotal:%9llu kB\n"
170	    "SwapFree: %9llu kB\n",
171	    memtotal, memused, memfree, memshared, buffers, cached,
172	    swaptotal, swapused, swapfree,
173	    B2K(memtotal), B2K(memfree),
174	    B2K(memshared), B2K(buffers), B2K(cached),
175	    B2K(swaptotal), B2K(swapfree));
176
177	return (0);
178}
179
180#ifdef __alpha__
181extern struct rpb *hwrpb;
182/*
183 * Filler function for proc/cpuinfo (Alpha version)
184 */
185static int
186linprocfs_docpuinfo(PFS_FILL_ARGS)
187{
188	u_int64_t type, major;
189	struct pcs *pcsp;
190	const char *model, *sysname;
191
192	static const char *cpuname[] = {
193		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
194		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
195	};
196
197	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
198	type = pcsp->pcs_proc_type;
199	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
200	if (major < sizeof(cpuname)/sizeof(char *)) {
201		model = cpuname[major - 1];
202	} else {
203		model = "unknown";
204	}
205
206	sysname = alpha_dsr_sysname();
207
208	sbuf_printf(sb,
209	    "cpu\t\t\t: Alpha\n"
210	    "cpu model\t\t: %s\n"
211	    "cpu variation\t\t: %ld\n"
212	    "cpu revision\t\t: %d\n"
213	    "cpu serial number\t: %s\n"
214	    "system type\t\t: %s\n"
215	    "system variation\t: %s\n"
216	    "system revision\t\t: %d\n"
217	    "system serial number\t: %s\n"
218	    "cycle frequency [Hz]\t: %lu\n"
219	    "timer frequency [Hz]\t: %u\n"
220	    "page size [bytes]\t: %ld\n"
221	    "phys. address bits\t: %ld\n"
222	    "max. addr. space #\t: %ld\n"
223	    "BogoMIPS\t\t: %u.%02u\n"
224	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
225	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
226	    "platform string\t\t: %s\n"
227	    "cpus detected\t\t: %d\n"
228	    ,
229	    model,
230	    pcsp->pcs_proc_var,
231	    *(int *)hwrpb->rpb_revision,
232	    " ",
233	    " ",
234	    "0",
235	    0,
236	    " ",
237	    hwrpb->rpb_cc_freq,
238	    hz,
239	    hwrpb->rpb_page_size,
240	    hwrpb->rpb_phys_addr_size,
241	    hwrpb->rpb_max_asn,
242	    0, 0,
243	    0, 0, 0,
244	    0, 0, 0,
245	    sysname,
246	    ncpus);
247	return (0);
248}
249#endif /* __alpha__ */
250
251#ifdef __i386__
252/*
253 * Filler function for proc/cpuinfo (i386 version)
254 */
255static int
256linprocfs_docpuinfo(PFS_FILL_ARGS)
257{
258	int class, fqmhz, fqkhz, ncpu;
259	int name[2], olen, plen;
260	int i;
261
262	name[0] = CTL_HW;
263	name[1] = HW_NCPU;
264	if (kernel_sysctl(td, name, 2, &ncpu, &olen, NULL, 0, &plen) != 0)
265		ncpu = 1;
266
267	/*
268	 * We default the flags to include all non-conflicting flags,
269	 * and the Intel versions of conflicting flags.
270	 */
271	static char *flags[] = {
272		"fpu",	    "vme",     "de",	   "pse",      "tsc",
273		"msr",	    "pae",     "mce",	   "cx8",      "apic",
274		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
275		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
276		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
277		"xmm",	    "b26",     "b27",	   "b28",      "b29",
278		"3dnowext", "3dnow"
279	};
280
281	switch (cpu_class) {
282	case CPUCLASS_286:
283		class = 2;
284		break;
285	case CPUCLASS_386:
286		class = 3;
287		break;
288	case CPUCLASS_486:
289		class = 4;
290		break;
291	case CPUCLASS_586:
292		class = 5;
293		break;
294	case CPUCLASS_686:
295		class = 6;
296		break;
297	default:
298		class = 0;
299		break;
300	}
301
302	for (i = 0; i < ncpu; ++i) {
303		sbuf_printf(sb,
304		    "processor\t: %d\n"
305		    "vendor_id\t: %.20s\n"
306		    "cpu family\t: %d\n"
307		    "model\t\t: %d\n"
308		    "stepping\t: %d\n",
309		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
310		/* XXX per-cpu vendor / class / id? */
311	}
312
313	sbuf_cat(sb,
314	    "flags\t\t:");
315
316	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
317		flags[16] = "fcmov";
318	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
319		flags[24] = "cxmmx";
320	}
321
322	for (i = 0; i < 32; i++)
323		if (cpu_feature & (1 << i))
324			sbuf_printf(sb, " %s", flags[i]);
325	sbuf_cat(sb, "\n");
326	if (class >= 5) {
327		fqmhz = (tsc_freq + 4999) / 1000000;
328		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
329		sbuf_printf(sb,
330		    "cpu MHz\t\t: %d.%02d\n"
331		    "bogomips\t: %d.%02d\n",
332		    fqmhz, fqkhz, fqmhz, fqkhz);
333	}
334
335	return (0);
336}
337#endif /* __i386__ */
338
339/*
340 * Filler function for proc/mtab
341 *
342 * This file doesn't exist in Linux' procfs, but is included here so
343 * users can symlink /compat/linux/etc/mtab to /proc/mtab
344 */
345static int
346linprocfs_domtab(PFS_FILL_ARGS)
347{
348	struct nameidata nd;
349	struct mount *mp;
350	const char *lep;
351	char *dlep, *flep, *mntto, *mntfrom, *fstype;
352	size_t lep_len;
353	int error;
354
355	/* resolve symlinks etc. in the emulation tree prefix */
356	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
357	flep = NULL;
358	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
359		lep = linux_emul_path;
360	else
361		lep = dlep;
362	lep_len = strlen(lep);
363
364	mtx_lock(&mountlist_mtx);
365	error = 0;
366	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
367		error = VFS_STATFS(mp, &mp->mnt_stat, td);
368		if (error)
369			break;
370
371		/* determine device name */
372		mntfrom = mp->mnt_stat.f_mntfromname;
373
374		/* determine mount point */
375		mntto = mp->mnt_stat.f_mntonname;
376		if (strncmp(mntto, lep, lep_len) == 0 &&
377		    mntto[lep_len] == '/')
378			mntto += lep_len;
379
380		/* determine fs type */
381		fstype = mp->mnt_stat.f_fstypename;
382		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
383			mntfrom = fstype = "proc";
384		else if (strcmp(fstype, "procfs") == 0)
385			continue;
386
387		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
388		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
389#define ADD_OPTION(opt, name) \
390	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
391		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
392		ADD_OPTION(MNT_NOEXEC,		"noexec");
393		ADD_OPTION(MNT_NOSUID,		"nosuid");
394		ADD_OPTION(MNT_NODEV,		"nodev");
395		ADD_OPTION(MNT_UNION,		"union");
396		ADD_OPTION(MNT_ASYNC,		"async");
397		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
398		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
399		ADD_OPTION(MNT_NOATIME,		"noatime");
400#undef ADD_OPTION
401		/* a real Linux mtab will also show NFS options */
402		sbuf_printf(sb, " 0 0\n");
403	}
404	mtx_unlock(&mountlist_mtx);
405	if (flep != NULL)
406		free(flep, M_TEMP);
407	return (error);
408}
409
410/*
411 * Filler function for proc/stat
412 */
413static int
414linprocfs_dostat(PFS_FILL_ARGS)
415{
416	sbuf_printf(sb,
417	    "cpu %ld %ld %ld %ld\n"
418	    "disk 0 0 0 0\n"
419	    "page %u %u\n"
420	    "swap %u %u\n"
421	    "intr %u\n"
422	    "ctxt %u\n"
423	    "btime %lld\n",
424	    T2J(cp_time[CP_USER]),
425	    T2J(cp_time[CP_NICE]),
426	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
427	    T2J(cp_time[CP_IDLE]),
428	    cnt.v_vnodepgsin,
429	    cnt.v_vnodepgsout,
430	    cnt.v_swappgsin,
431	    cnt.v_swappgsout,
432	    cnt.v_intr,
433	    cnt.v_swtch,
434	    (long long)boottime.tv_sec);
435	return (0);
436}
437
438/*
439 * Filler function for proc/uptime
440 */
441static int
442linprocfs_douptime(PFS_FILL_ARGS)
443{
444	struct timeval tv;
445
446	getmicrouptime(&tv);
447	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
448	    (long long)tv.tv_sec, tv.tv_usec / 10000,
449	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
450	return (0);
451}
452
453/*
454 * Filler function for proc/version
455 */
456static int
457linprocfs_doversion(PFS_FILL_ARGS)
458{
459	char osname[LINUX_MAX_UTSNAME];
460	char osrelease[LINUX_MAX_UTSNAME];
461
462	linux_get_osname(td, osname);
463	linux_get_osrelease(td, osrelease);
464
465	sbuf_printf(sb,
466	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
467	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
468	return (0);
469}
470
471/*
472 * Filler function for proc/loadavg
473 */
474static int
475linprocfs_doloadavg(PFS_FILL_ARGS)
476{
477	sbuf_printf(sb,
478	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
479	    (int)(averunnable.ldavg[0] / averunnable.fscale),
480	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
481	    (int)(averunnable.ldavg[1] / averunnable.fscale),
482	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
483	    (int)(averunnable.ldavg[2] / averunnable.fscale),
484	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
485	    1,				/* number of running tasks */
486	    nprocs,			/* number of tasks */
487	    lastpid			/* the last pid */
488	);
489
490	return (0);
491}
492
493/*
494 * Filler function for proc/pid/stat
495 */
496static int
497linprocfs_doprocstat(PFS_FILL_ARGS)
498{
499	struct kinfo_proc kp;
500
501	PROC_LOCK(p);
502	fill_kinfo_proc(p, &kp);
503	sbuf_printf(sb, "%d", p->p_pid);
504#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
505	PS_ADD("comm",		"(%s)",	p->p_comm);
506	PS_ADD("statr",		"%c",	'0'); /* XXX */
507	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
508	PS_ADD("pgrp",		"%d",	p->p_pgid);
509	PS_ADD("session",	"%d",	p->p_session->s_sid);
510	PROC_UNLOCK(p);
511	PS_ADD("tty",		"%d",	0); /* XXX */
512	PS_ADD("tpgid",		"%d",	0); /* XXX */
513	PS_ADD("flags",		"%u",	0); /* XXX */
514	PS_ADD("minflt",	"%u",	0); /* XXX */
515	PS_ADD("cminflt",	"%u",	0); /* XXX */
516	PS_ADD("majflt",	"%u",	0); /* XXX */
517	PS_ADD("cminflt",	"%u",	0); /* XXX */
518	PS_ADD("utime",		"%d",	0); /* XXX */
519	PS_ADD("stime",		"%d",	0); /* XXX */
520	PS_ADD("cutime",	"%d",	0); /* XXX */
521	PS_ADD("cstime",	"%d",	0); /* XXX */
522	PS_ADD("counter",	"%d",	0); /* XXX */
523	PS_ADD("priority",	"%d",	0); /* XXX */
524	PS_ADD("timeout",	"%u",	0); /* XXX */
525	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
526	PS_ADD("starttime",	"%d",	0); /* XXX */
527	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
528	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
529	PS_ADD("rlim",		"%u",	0); /* XXX */
530	PS_ADD("startcode",	"%u",	(unsigned)0);
531	PS_ADD("endcode",	"%u",	0); /* XXX */
532	PS_ADD("startstack",	"%u",	0); /* XXX */
533	PS_ADD("esp",		"%u",	0); /* XXX */
534	PS_ADD("eip",		"%u",	0); /* XXX */
535	PS_ADD("signal",	"%d",	0); /* XXX */
536	PS_ADD("blocked",	"%d",	0); /* XXX */
537	PS_ADD("sigignore",	"%d",	0); /* XXX */
538	PS_ADD("sigcatch",	"%d",	0); /* XXX */
539	PS_ADD("wchan",		"%u",	0); /* XXX */
540	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
541	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
542	PS_ADD("exitsignal",	"%d",	0); /* XXX */
543	PS_ADD("processor",	"%d",	0); /* XXX */
544#undef PS_ADD
545	sbuf_putc(sb, '\n');
546
547	return (0);
548}
549
550/*
551 * Filler function for proc/pid/statm
552 */
553static int
554linprocfs_doprocstatm(PFS_FILL_ARGS)
555{
556	struct kinfo_proc kp;
557	segsz_t lsize;
558
559	PROC_LOCK(p);
560	fill_kinfo_proc(p, &kp);
561	PROC_UNLOCK(p);
562
563	/*
564	 * See comments in linprocfs_doprocstatus() regarding the
565	 * computation of lsize.
566	 */
567	/* size resident share trs drs lrs dt */
568	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
569	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
570	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
571	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
572	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
573	lsize = B2P(kp.ki_size) - kp.ki_dsize -
574	    kp.ki_ssize - kp.ki_tsize - 1;
575	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
576	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
577
578	return (0);
579}
580
581/*
582 * Filler function for proc/pid/status
583 */
584static int
585linprocfs_doprocstatus(PFS_FILL_ARGS)
586{
587	struct kinfo_proc kp;
588	char *state;
589	segsz_t lsize;
590	struct thread *td2;
591	struct sigacts *ps;
592	int i;
593
594	PROC_LOCK(p);
595	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
596
597	if (P_SHOULDSTOP(p)) {
598		state = "T (stopped)";
599	} else {
600		mtx_lock_spin(&sched_lock);
601		switch(p->p_state) {
602		case PRS_NEW:
603			state = "I (idle)";
604			break;
605		case PRS_NORMAL:
606			if (p->p_flag & P_WEXIT) {
607				state = "X (exiting)";
608				break;
609			}
610			switch(td2->td_state) {
611			case TDS_INHIBITED:
612				state = "S (sleeping)";
613				break;
614			case TDS_RUNQ:
615			case TDS_RUNNING:
616				state = "R (running)";
617				break;
618			default:
619				state = "? (unknown)";
620				break;
621			}
622			break;
623		case PRS_ZOMBIE:
624			state = "Z (zombie)";
625			break;
626		default:
627			state = "? (unknown)";
628			break;
629		}
630		mtx_unlock_spin(&sched_lock);
631	}
632
633	fill_kinfo_proc(p, &kp);
634	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
635	sbuf_printf(sb, "State:\t%s\n",		state);
636
637	/*
638	 * Credentials
639	 */
640	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
641	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
642						p->p_pptr->p_pid : 0);
643	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
644						p->p_ucred->cr_uid,
645						p->p_ucred->cr_svuid,
646						/* FreeBSD doesn't have fsuid */
647						p->p_ucred->cr_uid);
648	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
649						p->p_ucred->cr_gid,
650						p->p_ucred->cr_svgid,
651						/* FreeBSD doesn't have fsgid */
652						p->p_ucred->cr_gid);
653	sbuf_cat(sb, "Groups:\t");
654	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
655		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
656	PROC_UNLOCK(p);
657	sbuf_putc(sb, '\n');
658
659	/*
660	 * Memory
661	 *
662	 * While our approximation of VmLib may not be accurate (I
663	 * don't know of a simple way to verify it, and I'm not sure
664	 * it has much meaning anyway), I believe it's good enough.
665	 *
666	 * The same code that could (I think) accurately compute VmLib
667	 * could also compute VmLck, but I don't really care enough to
668	 * implement it. Submissions are welcome.
669	 */
670	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
671	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
672	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
673	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
674	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
675	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
676	lsize = B2P(kp.ki_size) - kp.ki_dsize -
677	    kp.ki_ssize - kp.ki_tsize - 1;
678	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
679
680	/*
681	 * Signal masks
682	 *
683	 * We support up to 128 signals, while Linux supports 32,
684	 * but we only define 32 (the same 32 as Linux, to boot), so
685	 * just show the lower 32 bits of each mask. XXX hack.
686	 *
687	 * NB: on certain platforms (Sparc at least) Linux actually
688	 * supports 64 signals, but this code is a long way from
689	 * running on anything but i386, so ignore that for now.
690	 */
691	PROC_LOCK(p);
692	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
693	/*
694	 * I can't seem to find out where the signal mask is in
695	 * relation to struct proc, so SigBlk is left unimplemented.
696	 */
697	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
698	ps = p->p_sigacts;
699	mtx_lock(&ps->ps_mtx);
700	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
701	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
702	mtx_unlock(&ps->ps_mtx);
703	PROC_UNLOCK(p);
704
705	/*
706	 * Linux also prints the capability masks, but we don't have
707	 * capabilities yet, and when we do get them they're likely to
708	 * be meaningless to Linux programs, so we lie. XXX
709	 */
710	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
711	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
712	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
713
714	return (0);
715}
716
717
718/*
719 * Filler function for proc/pid/cwd
720 */
721static int
722linprocfs_doproccwd(PFS_FILL_ARGS)
723{
724	char *fullpath = "unknown";
725	char *freepath = NULL;
726
727	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
728	sbuf_printf(sb, "%s", fullpath);
729	if (freepath)
730		free(freepath, M_TEMP);
731	return (0);
732}
733
734/*
735 * Filler function for proc/pid/root
736 */
737static int
738linprocfs_doprocroot(PFS_FILL_ARGS)
739{
740	struct vnode *rvp;
741	char *fullpath = "unknown";
742	char *freepath = NULL;
743
744	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
745	vn_fullpath(td, rvp, &fullpath, &freepath);
746	sbuf_printf(sb, "%s", fullpath);
747	if (freepath)
748		free(freepath, M_TEMP);
749	return (0);
750}
751
752/*
753 * Filler function for proc/pid/cmdline
754 */
755static int
756linprocfs_doproccmdline(PFS_FILL_ARGS)
757{
758	struct ps_strings pstr;
759	int error, i;
760
761	/*
762	 * If we are using the ps/cmdline caching, use that.  Otherwise
763	 * revert back to the old way which only implements full cmdline
764	 * for the currept process and just p->p_comm for all other
765	 * processes.
766	 * Note that if the argv is no longer available, we deliberately
767	 * don't fall back on p->p_comm or return an error: the authentic
768	 * Linux behaviour is to return zero-length in this case.
769	 */
770
771	PROC_LOCK(p);
772	if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
773		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
774		PROC_UNLOCK(p);
775	} else if (p != td->td_proc) {
776		PROC_UNLOCK(p);
777		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
778	} else {
779		PROC_UNLOCK(p);
780		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
781		    sizeof(pstr));
782		if (error)
783			return (error);
784		for (i = 0; i < pstr.ps_nargvstr; i++) {
785			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
786			sbuf_printf(sb, "%c", '\0');
787		}
788	}
789
790	return (0);
791}
792
793/*
794 * Filler function for proc/pid/environ
795 */
796static int
797linprocfs_doprocenviron(PFS_FILL_ARGS)
798{
799	sbuf_printf(sb, "doprocenviron\n%c", '\0');
800
801	return (0);
802}
803
804/*
805 * Filler function for proc/pid/maps
806 */
807static int
808linprocfs_doprocmaps(PFS_FILL_ARGS)
809{
810	sbuf_printf(sb, "doprocmaps\n%c", '\0');
811
812	return (0);
813}
814
815/*
816 * Filler function for proc/net/dev
817 */
818static int
819linprocfs_donetdev(PFS_FILL_ARGS)
820{
821	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
822	struct ifnet *ifp;
823
824	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
825	    "Inter-", "   Receive", "  Transmit", " face",
826	    "bytes    packets errs drop fifo frame compressed",
827	    "bytes    packets errs drop fifo frame compressed");
828
829	IFNET_RLOCK();
830	TAILQ_FOREACH(ifp, &ifnet, if_link) {
831		linux_ifname(ifp, ifname, sizeof ifname);
832			sbuf_printf(sb, "%6.6s:", ifname);
833		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
834		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
835		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
836		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
837	}
838	IFNET_RUNLOCK();
839
840	return (0);
841}
842
843#if 0
844extern struct cdevsw *cdevsw[];
845
846/*
847 * Filler function for proc/devices
848 */
849static int
850linprocfs_dodevices(PFS_FILL_ARGS)
851{
852	int i;
853
854	sbuf_printf(sb, "Character devices:\n");
855
856	for (i = 0; i < NUMCDEVSW; i++)
857		if (cdevsw[i] != NULL)
858			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
859
860	sbuf_printf(sb, "\nBlock devices:\n");
861
862	return (0);
863}
864#endif
865
866/*
867 * Filler function for proc/cmdline
868 */
869static int
870linprocfs_docmdline(PFS_FILL_ARGS)
871{
872	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
873	sbuf_printf(sb, " ro root=302\n");
874	return (0);
875}
876
877#if 0
878/*
879 * Filler function for proc/modules
880 */
881static int
882linprocfs_domodules(PFS_FILL_ARGS)
883{
884	struct linker_file *lf;
885
886	TAILQ_FOREACH(lf, &linker_files, link) {
887		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
888		    (unsigned long)lf->size, lf->refs);
889	}
890	return (0);
891}
892#endif
893
894/*
895 * Constructor
896 */
897static int
898linprocfs_init(PFS_INIT_ARGS)
899{
900	struct pfs_node *root;
901	struct pfs_node *dir;
902
903	root = pi->pi_root;
904
905	/* /proc/... */
906	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
907	    NULL, NULL, PFS_RD);
908	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
909	    NULL, NULL, PFS_RD);
910#if 0
911	pfs_create_file(root, "devices", &linprocfs_dodevices,
912	    NULL, NULL, PFS_RD);
913#endif
914	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
915	    NULL, NULL, PFS_RD);
916	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
917	    NULL, NULL, PFS_RD);
918#if 0
919	pfs_create_file(root, "modules", &linprocfs_domodules,
920	    NULL, NULL, PFS_RD);
921#endif
922	pfs_create_file(root, "mtab", &linprocfs_domtab,
923	    NULL, NULL, PFS_RD);
924	pfs_create_link(root, "self", &procfs_docurproc,
925	    NULL, NULL, 0);
926	pfs_create_file(root, "stat", &linprocfs_dostat,
927	    NULL, NULL, PFS_RD);
928	pfs_create_file(root, "uptime", &linprocfs_douptime,
929	    NULL, NULL, PFS_RD);
930	pfs_create_file(root, "version", &linprocfs_doversion,
931	    NULL, NULL, PFS_RD);
932
933	/* /proc/net/... */
934	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
935	pfs_create_file(dir, "dev", &linprocfs_donetdev,
936	    NULL, NULL, PFS_RD);
937
938	/* /proc/<pid>/... */
939	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
940	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
941	    NULL, NULL, PFS_RD);
942	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
943	    NULL, NULL, 0);
944	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
945	    NULL, NULL, PFS_RD);
946	pfs_create_link(dir, "exe", &procfs_doprocfile,
947	    NULL, &procfs_notsystem, 0);
948	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
949	    NULL, NULL, PFS_RD);
950	pfs_create_file(dir, "mem", &procfs_doprocmem,
951	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
952	pfs_create_link(dir, "root", &linprocfs_doprocroot,
953	    NULL, NULL, 0);
954	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
955	    NULL, NULL, PFS_RD);
956	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
957	    NULL, NULL, PFS_RD);
958	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
959	    NULL, NULL, PFS_RD);
960
961	return (0);
962}
963
964/*
965 * Destructor
966 */
967static int
968linprocfs_uninit(PFS_INIT_ARGS)
969{
970
971	/* nothing to do, pseudofs will GC */
972	return (0);
973}
974
975PSEUDOFS(linprocfs, 1);
976MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
977MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
978