linprocfs.c revision 189106
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 "opt_route.h"
43#include "opt_compat.h"
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 189106 2009-02-27 14:12:05Z bz $");
47
48#include <sys/param.h>
49#include <sys/queue.h>
50#include <sys/blist.h>
51#include <sys/conf.h>
52#include <sys/exec.h>
53#include <sys/fcntl.h>
54#include <sys/filedesc.h>
55#include <sys/jail.h>
56#include <sys/kernel.h>
57#include <sys/linker.h>
58#include <sys/lock.h>
59#include <sys/malloc.h>
60#include <sys/mount.h>
61#include <sys/msg.h>
62#include <sys/mutex.h>
63#include <sys/namei.h>
64#include <sys/proc.h>
65#include <sys/resourcevar.h>
66#include <sys/sbuf.h>
67#include <sys/sem.h>
68#include <sys/smp.h>
69#include <sys/socket.h>
70#include <sys/sysctl.h>
71#include <sys/systm.h>
72#include <sys/time.h>
73#include <sys/tty.h>
74#include <sys/user.h>
75#include <sys/vmmeter.h>
76#include <sys/vnode.h>
77#include <sys/vimage.h>
78
79#include <net/if.h>
80#include <net/route.h>
81#include <net/vnet.h>
82
83#include <vm/vm.h>
84#include <vm/vm_extern.h>
85#include <vm/pmap.h>
86#include <vm/vm_map.h>
87#include <vm/vm_param.h>
88#include <vm/vm_object.h>
89#include <vm/swap_pager.h>
90
91#include <machine/clock.h>
92
93#if defined(__i386__) || defined(__amd64__)
94#include <machine/cputypes.h>
95#include <machine/md_var.h>
96#endif /* __i386__ || __amd64__ */
97
98#ifdef COMPAT_LINUX32				/* XXX */
99#include <machine/../linux32/linux.h>
100#else
101#include <machine/../linux/linux.h>
102#endif
103#include <compat/linux/linux_ioctl.h>
104#include <compat/linux/linux_mib.h>
105#include <compat/linux/linux_util.h>
106#include <fs/pseudofs/pseudofs.h>
107#include <fs/procfs/procfs.h>
108
109/*
110 * Various conversion macros
111 */
112#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
113#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
114#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
115#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
116#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
117#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
118
119/**
120 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
121 *
122 * The linux procfs state field displays one of the characters RSDZTW to
123 * denote running, sleeping in an interruptible wait, waiting in an
124 * uninterruptible disk sleep, a zombie process, process is being traced
125 * or stopped, or process is paging respectively.
126 *
127 * Our struct kinfo_proc contains the variable ki_stat which contains a
128 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
129 *
130 * This character array is used with ki_stati-1 as an index and tries to
131 * map our states to suitable linux states.
132 */
133static char linux_state[] = "RRSTZDD";
134
135/*
136 * Filler function for proc/meminfo
137 */
138static int
139linprocfs_domeminfo(PFS_FILL_ARGS)
140{
141	unsigned long memtotal;		/* total memory in bytes */
142	unsigned long memused;		/* used memory in bytes */
143	unsigned long memfree;		/* free memory in bytes */
144	unsigned long memshared;	/* shared memory ??? */
145	unsigned long buffers, cached;	/* buffer / cache memory ??? */
146	unsigned long long swaptotal;	/* total swap space in bytes */
147	unsigned long long swapused;	/* used swap space in bytes */
148	unsigned long long swapfree;	/* free swap space in bytes */
149	vm_object_t object;
150	int i, j;
151
152	memtotal = physmem * PAGE_SIZE;
153	/*
154	 * The correct thing here would be:
155	 *
156	memfree = cnt.v_free_count * PAGE_SIZE;
157	memused = memtotal - memfree;
158	 *
159	 * but it might mislead linux binaries into thinking there
160	 * is very little memory left, so we cheat and tell them that
161	 * all memory that isn't wired down is free.
162	 */
163	memused = cnt.v_wire_count * PAGE_SIZE;
164	memfree = memtotal - memused;
165	swap_pager_status(&i, &j);
166	swaptotal = (unsigned long long)i * PAGE_SIZE;
167	swapused = (unsigned long long)j * PAGE_SIZE;
168	swapfree = swaptotal - swapused;
169	memshared = 0;
170	mtx_lock(&vm_object_list_mtx);
171	TAILQ_FOREACH(object, &vm_object_list, object_list)
172		if (object->shadow_count > 1)
173			memshared += object->resident_page_count;
174	mtx_unlock(&vm_object_list_mtx);
175	memshared *= PAGE_SIZE;
176	/*
177	 * We'd love to be able to write:
178	 *
179	buffers = bufspace;
180	 *
181	 * but bufspace is internal to vfs_bio.c and we don't feel
182	 * like unstaticizing it just for linprocfs's sake.
183	 */
184	buffers = 0;
185	cached = cnt.v_cache_count * PAGE_SIZE;
186
187	sbuf_printf(sb,
188	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
189	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
190	    "Swap: %llu %llu %llu\n"
191	    "MemTotal: %9lu kB\n"
192	    "MemFree:  %9lu kB\n"
193	    "MemShared:%9lu kB\n"
194	    "Buffers:  %9lu kB\n"
195	    "Cached:   %9lu kB\n"
196	    "SwapTotal:%9llu kB\n"
197	    "SwapFree: %9llu kB\n",
198	    memtotal, memused, memfree, memshared, buffers, cached,
199	    swaptotal, swapused, swapfree,
200	    B2K(memtotal), B2K(memfree),
201	    B2K(memshared), B2K(buffers), B2K(cached),
202	    B2K(swaptotal), B2K(swapfree));
203
204	return (0);
205}
206
207#if defined(__i386__) || defined(__amd64__)
208/*
209 * Filler function for proc/cpuinfo (i386 & amd64 version)
210 */
211static int
212linprocfs_docpuinfo(PFS_FILL_ARGS)
213{
214	int hw_model[2];
215	char model[128];
216	size_t size;
217	int class, fqmhz, fqkhz;
218	int i;
219
220	/*
221	 * We default the flags to include all non-conflicting flags,
222	 * and the Intel versions of conflicting flags.
223	 */
224	static char *flags[] = {
225		"fpu",	    "vme",     "de",	   "pse",      "tsc",
226		"msr",	    "pae",     "mce",	   "cx8",      "apic",
227		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
228		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
229		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
230		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
231		"3dnowext", "3dnow"
232	};
233
234	switch (cpu_class) {
235#ifdef __i386__
236	case CPUCLASS_286:
237		class = 2;
238		break;
239	case CPUCLASS_386:
240		class = 3;
241		break;
242	case CPUCLASS_486:
243		class = 4;
244		break;
245	case CPUCLASS_586:
246		class = 5;
247		break;
248	case CPUCLASS_686:
249		class = 6;
250		break;
251	default:
252		class = 0;
253		break;
254#else /* __amd64__ */
255	default:
256		class = 15;
257		break;
258#endif
259	}
260
261	hw_model[0] = CTL_HW;
262	hw_model[1] = HW_MODEL;
263	model[0] = '\0';
264	size = sizeof(model);
265	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
266		strcpy(model, "unknown");
267	for (i = 0; i < mp_ncpus; ++i) {
268		sbuf_printf(sb,
269		    "processor\t: %d\n"
270		    "vendor_id\t: %.20s\n"
271		    "cpu family\t: %d\n"
272		    "model\t\t: %d\n"
273		    "model name\t: %s\n"
274		    "stepping\t: %d\n",
275		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
276		/* XXX per-cpu vendor / class / model / id? */
277	}
278
279	sbuf_cat(sb, "flags\t\t:");
280
281#ifdef __i386__
282	switch (cpu_vendor_id) {
283	case CPU_VENDOR_AMD:
284		if (class < 6)
285			flags[16] = "fcmov";
286		break;
287	case CPU_VENDOR_CYRIX:
288		flags[24] = "cxmmx";
289		break;
290	}
291#endif
292
293	for (i = 0; i < 32; i++)
294		if (cpu_feature & (1 << i))
295			sbuf_printf(sb, " %s", flags[i]);
296	sbuf_cat(sb, "\n");
297	if (class >= 5) {
298		fqmhz = (tsc_freq + 4999) / 1000000;
299		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
300		sbuf_printf(sb,
301		    "cpu MHz\t\t: %d.%02d\n"
302		    "bogomips\t: %d.%02d\n",
303		    fqmhz, fqkhz, fqmhz, fqkhz);
304	}
305
306	return (0);
307}
308#endif /* __i386__ || __amd64__ */
309
310/*
311 * Filler function for proc/mtab
312 *
313 * This file doesn't exist in Linux' procfs, but is included here so
314 * users can symlink /compat/linux/etc/mtab to /proc/mtab
315 */
316static int
317linprocfs_domtab(PFS_FILL_ARGS)
318{
319	struct nameidata nd;
320	struct mount *mp;
321	const char *lep;
322	char *dlep, *flep, *mntto, *mntfrom, *fstype;
323	size_t lep_len;
324	int error;
325
326	/* resolve symlinks etc. in the emulation tree prefix */
327	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
328	flep = NULL;
329	error = namei(&nd);
330	lep = linux_emul_path;
331	if (error == 0) {
332		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
333			lep = dlep;
334		vrele(nd.ni_vp);
335		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
336	}
337	lep_len = strlen(lep);
338
339	mtx_lock(&mountlist_mtx);
340	error = 0;
341	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
342		/* determine device name */
343		mntfrom = mp->mnt_stat.f_mntfromname;
344
345		/* determine mount point */
346		mntto = mp->mnt_stat.f_mntonname;
347		if (strncmp(mntto, lep, lep_len) == 0 &&
348		    mntto[lep_len] == '/')
349			mntto += lep_len;
350
351		/* determine fs type */
352		fstype = mp->mnt_stat.f_fstypename;
353		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
354			mntfrom = fstype = "proc";
355		else if (strcmp(fstype, "procfs") == 0)
356			continue;
357
358		if (strcmp(fstype, "linsysfs") == 0) {
359			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
360			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
361		} else {
362			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
363			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
364		}
365#define ADD_OPTION(opt, name) \
366	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
367		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
368		ADD_OPTION(MNT_NOEXEC,		"noexec");
369		ADD_OPTION(MNT_NOSUID,		"nosuid");
370		ADD_OPTION(MNT_UNION,		"union");
371		ADD_OPTION(MNT_ASYNC,		"async");
372		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
373		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
374		ADD_OPTION(MNT_NOATIME,		"noatime");
375#undef ADD_OPTION
376		/* a real Linux mtab will also show NFS options */
377		sbuf_printf(sb, " 0 0\n");
378	}
379	mtx_unlock(&mountlist_mtx);
380	if (flep != NULL)
381		free(flep, M_TEMP);
382	return (error);
383}
384
385/*
386 * Filler function for proc/stat
387 */
388static int
389linprocfs_dostat(PFS_FILL_ARGS)
390{
391	struct pcpu *pcpu;
392	long cp_time[CPUSTATES];
393	long *cp;
394	int i;
395
396	read_cpu_time(cp_time);
397	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
398	    T2J(cp_time[CP_USER]),
399	    T2J(cp_time[CP_NICE]),
400	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
401	    T2J(cp_time[CP_IDLE]));
402	for (i = 0; i <= mp_maxid; ++i) {
403		if (CPU_ABSENT(i))
404			continue;
405		pcpu = pcpu_find(i);
406		cp = pcpu->pc_cp_time;
407		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
408		    T2J(cp[CP_USER]),
409		    T2J(cp[CP_NICE]),
410		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
411		    T2J(cp[CP_IDLE]));
412	}
413	sbuf_printf(sb,
414	    "disk 0 0 0 0\n"
415	    "page %u %u\n"
416	    "swap %u %u\n"
417	    "intr %u\n"
418	    "ctxt %u\n"
419	    "btime %lld\n",
420	    cnt.v_vnodepgsin,
421	    cnt.v_vnodepgsout,
422	    cnt.v_swappgsin,
423	    cnt.v_swappgsout,
424	    cnt.v_intr,
425	    cnt.v_swtch,
426	    (long long)boottime.tv_sec);
427	return (0);
428}
429
430/*
431 * Filler function for proc/uptime
432 */
433static int
434linprocfs_douptime(PFS_FILL_ARGS)
435{
436	long cp_time[CPUSTATES];
437	struct timeval tv;
438
439	getmicrouptime(&tv);
440	read_cpu_time(cp_time);
441	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
442	    (long long)tv.tv_sec, tv.tv_usec / 10000,
443	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
444	return (0);
445}
446
447/*
448 * Get OS build date
449 */
450static void
451linprocfs_osbuild(struct thread *td, struct sbuf *sb)
452{
453#if 0
454	char osbuild[256];
455	char *cp1, *cp2;
456
457	strncpy(osbuild, version, 256);
458	osbuild[255] = '\0';
459	cp1 = strstr(osbuild, "\n");
460	cp2 = strstr(osbuild, ":");
461	if (cp1 && cp2) {
462		*cp1 = *cp2 = '\0';
463		cp1 = strstr(osbuild, "#");
464	} else
465		cp1 = NULL;
466	if (cp1)
467		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
468	else
469#endif
470		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
471}
472
473/*
474 * Get OS builder
475 */
476static void
477linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
478{
479#if 0
480	char builder[256];
481	char *cp;
482
483	cp = strstr(version, "\n    ");
484	if (cp) {
485		strncpy(builder, cp + 5, 256);
486		builder[255] = '\0';
487		cp = strstr(builder, ":");
488		if (cp)
489			*cp = '\0';
490	}
491	if (cp)
492		sbuf_cat(sb, builder);
493	else
494#endif
495		sbuf_cat(sb, "des@freebsd.org");
496}
497
498/*
499 * Filler function for proc/version
500 */
501static int
502linprocfs_doversion(PFS_FILL_ARGS)
503{
504	char osname[LINUX_MAX_UTSNAME];
505	char osrelease[LINUX_MAX_UTSNAME];
506
507	linux_get_osname(td, osname);
508	linux_get_osrelease(td, osrelease);
509	sbuf_printf(sb, "%s version %s (", osname, osrelease);
510	linprocfs_osbuilder(td, sb);
511	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
512	linprocfs_osbuild(td, sb);
513	sbuf_cat(sb, "\n");
514
515	return (0);
516}
517
518/*
519 * Filler function for proc/loadavg
520 */
521static int
522linprocfs_doloadavg(PFS_FILL_ARGS)
523{
524
525	sbuf_printf(sb,
526	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
527	    (int)(averunnable.ldavg[0] / averunnable.fscale),
528	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
529	    (int)(averunnable.ldavg[1] / averunnable.fscale),
530	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
531	    (int)(averunnable.ldavg[2] / averunnable.fscale),
532	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
533	    1,				/* number of running tasks */
534	    nprocs,			/* number of tasks */
535	    lastpid			/* the last pid */
536	);
537	return (0);
538}
539
540/*
541 * Filler function for proc/pid/stat
542 */
543static int
544linprocfs_doprocstat(PFS_FILL_ARGS)
545{
546	struct kinfo_proc kp;
547	char state;
548	static int ratelimit = 0;
549
550	PROC_LOCK(p);
551	fill_kinfo_proc(p, &kp);
552	sbuf_printf(sb, "%d", p->p_pid);
553#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
554	PS_ADD("comm",		"(%s)",	p->p_comm);
555	if (kp.ki_stat > sizeof(linux_state)) {
556		state = 'R';
557
558		if (ratelimit == 0) {
559			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
560			    kp.ki_stat, sizeof(linux_state));
561			++ratelimit;
562		}
563	} else
564		state = linux_state[kp.ki_stat - 1];
565	PS_ADD("state",		"%c",	state);
566	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
567	PS_ADD("pgrp",		"%d",	p->p_pgid);
568	PS_ADD("session",	"%d",	p->p_session->s_sid);
569	PROC_UNLOCK(p);
570	PS_ADD("tty",		"%d",	0); /* XXX */
571	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
572	PS_ADD("flags",		"%u",	0); /* XXX */
573	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
574	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
575	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
576	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
577	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
578	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
579	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
580	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
581	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
582	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
583	PS_ADD("0",		"%d",	0); /* removed field */
584	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
585	/* XXX: starttime is not right, it is the _same_ for _every_ process.
586	   It should be the number of jiffies between system boot and process
587	   start. */
588	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
589	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
590	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
591	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
592	PS_ADD("startcode",	"%u",	(unsigned)0);
593	PS_ADD("endcode",	"%u",	0); /* XXX */
594	PS_ADD("startstack",	"%u",	0); /* XXX */
595	PS_ADD("kstkesp",	"%u",	0); /* XXX */
596	PS_ADD("kstkeip",	"%u",	0); /* XXX */
597	PS_ADD("signal",	"%u",	0); /* XXX */
598	PS_ADD("blocked",	"%u",	0); /* XXX */
599	PS_ADD("sigignore",	"%u",	0); /* XXX */
600	PS_ADD("sigcatch",	"%u",	0); /* XXX */
601	PS_ADD("wchan",		"%u",	0); /* XXX */
602	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
603	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
604	PS_ADD("exitsignal",	"%d",	0); /* XXX */
605	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
606	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
607	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
608#undef PS_ADD
609	sbuf_putc(sb, '\n');
610
611	return (0);
612}
613
614/*
615 * Filler function for proc/pid/statm
616 */
617static int
618linprocfs_doprocstatm(PFS_FILL_ARGS)
619{
620	struct kinfo_proc kp;
621	segsz_t lsize;
622
623	PROC_LOCK(p);
624	fill_kinfo_proc(p, &kp);
625	PROC_UNLOCK(p);
626
627	/*
628	 * See comments in linprocfs_doprocstatus() regarding the
629	 * computation of lsize.
630	 */
631	/* size resident share trs drs lrs dt */
632	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
633	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
634	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
635	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
636	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
637	lsize = B2P(kp.ki_size) - kp.ki_dsize -
638	    kp.ki_ssize - kp.ki_tsize - 1;
639	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
640	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
641
642	return (0);
643}
644
645/*
646 * Filler function for proc/pid/status
647 */
648static int
649linprocfs_doprocstatus(PFS_FILL_ARGS)
650{
651	struct kinfo_proc kp;
652	char *state;
653	segsz_t lsize;
654	struct thread *td2;
655	struct sigacts *ps;
656	int i;
657
658	PROC_LOCK(p);
659	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
660
661	if (P_SHOULDSTOP(p)) {
662		state = "T (stopped)";
663	} else {
664		PROC_SLOCK(p);
665		switch(p->p_state) {
666		case PRS_NEW:
667			state = "I (idle)";
668			break;
669		case PRS_NORMAL:
670			if (p->p_flag & P_WEXIT) {
671				state = "X (exiting)";
672				break;
673			}
674			switch(td2->td_state) {
675			case TDS_INHIBITED:
676				state = "S (sleeping)";
677				break;
678			case TDS_RUNQ:
679			case TDS_RUNNING:
680				state = "R (running)";
681				break;
682			default:
683				state = "? (unknown)";
684				break;
685			}
686			break;
687		case PRS_ZOMBIE:
688			state = "Z (zombie)";
689			break;
690		default:
691			state = "? (unknown)";
692			break;
693		}
694		PROC_SUNLOCK(p);
695	}
696
697	fill_kinfo_proc(p, &kp);
698	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
699	sbuf_printf(sb, "State:\t%s\n",		state);
700
701	/*
702	 * Credentials
703	 */
704	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
705	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
706						p->p_pptr->p_pid : 0);
707	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
708						p->p_ucred->cr_uid,
709						p->p_ucred->cr_svuid,
710						/* FreeBSD doesn't have fsuid */
711						p->p_ucred->cr_uid);
712	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
713						p->p_ucred->cr_gid,
714						p->p_ucred->cr_svgid,
715						/* FreeBSD doesn't have fsgid */
716						p->p_ucred->cr_gid);
717	sbuf_cat(sb, "Groups:\t");
718	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
719		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
720	PROC_UNLOCK(p);
721	sbuf_putc(sb, '\n');
722
723	/*
724	 * Memory
725	 *
726	 * While our approximation of VmLib may not be accurate (I
727	 * don't know of a simple way to verify it, and I'm not sure
728	 * it has much meaning anyway), I believe it's good enough.
729	 *
730	 * The same code that could (I think) accurately compute VmLib
731	 * could also compute VmLck, but I don't really care enough to
732	 * implement it. Submissions are welcome.
733	 */
734	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
735	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
736	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
737	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
738	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
739	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
740	lsize = B2P(kp.ki_size) - kp.ki_dsize -
741	    kp.ki_ssize - kp.ki_tsize - 1;
742	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
743
744	/*
745	 * Signal masks
746	 *
747	 * We support up to 128 signals, while Linux supports 32,
748	 * but we only define 32 (the same 32 as Linux, to boot), so
749	 * just show the lower 32 bits of each mask. XXX hack.
750	 *
751	 * NB: on certain platforms (Sparc at least) Linux actually
752	 * supports 64 signals, but this code is a long way from
753	 * running on anything but i386, so ignore that for now.
754	 */
755	PROC_LOCK(p);
756	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
757	/*
758	 * I can't seem to find out where the signal mask is in
759	 * relation to struct proc, so SigBlk is left unimplemented.
760	 */
761	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
762	ps = p->p_sigacts;
763	mtx_lock(&ps->ps_mtx);
764	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
765	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
766	mtx_unlock(&ps->ps_mtx);
767	PROC_UNLOCK(p);
768
769	/*
770	 * Linux also prints the capability masks, but we don't have
771	 * capabilities yet, and when we do get them they're likely to
772	 * be meaningless to Linux programs, so we lie. XXX
773	 */
774	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
775	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
776	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
777
778	return (0);
779}
780
781
782/*
783 * Filler function for proc/pid/cwd
784 */
785static int
786linprocfs_doproccwd(PFS_FILL_ARGS)
787{
788	char *fullpath = "unknown";
789	char *freepath = NULL;
790
791	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
792	sbuf_printf(sb, "%s", fullpath);
793	if (freepath)
794		free(freepath, M_TEMP);
795	return (0);
796}
797
798/*
799 * Filler function for proc/pid/root
800 */
801static int
802linprocfs_doprocroot(PFS_FILL_ARGS)
803{
804	struct vnode *rvp;
805	char *fullpath = "unknown";
806	char *freepath = NULL;
807
808	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
809	vn_fullpath(td, rvp, &fullpath, &freepath);
810	sbuf_printf(sb, "%s", fullpath);
811	if (freepath)
812		free(freepath, M_TEMP);
813	return (0);
814}
815
816/*
817 * Filler function for proc/pid/cmdline
818 */
819static int
820linprocfs_doproccmdline(PFS_FILL_ARGS)
821{
822	struct ps_strings pstr;
823	char **ps_argvstr;
824	int error, i;
825
826	/*
827	 * If we are using the ps/cmdline caching, use that.  Otherwise
828	 * revert back to the old way which only implements full cmdline
829	 * for the currept process and just p->p_comm for all other
830	 * processes.
831	 * Note that if the argv is no longer available, we deliberately
832	 * don't fall back on p->p_comm or return an error: the authentic
833	 * Linux behaviour is to return zero-length in this case.
834	 */
835
836	PROC_LOCK(p);
837	if (p->p_args && p_cansee(td, p) == 0) {
838		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
839		PROC_UNLOCK(p);
840	} else if (p != td->td_proc) {
841		PROC_UNLOCK(p);
842		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
843	} else {
844		PROC_UNLOCK(p);
845		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
846		    sizeof(pstr));
847		if (error)
848			return (error);
849		if (pstr.ps_nargvstr > ARG_MAX)
850			return (E2BIG);
851		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
852		    M_TEMP, M_WAITOK);
853		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
854		    pstr.ps_nargvstr * sizeof(char *));
855		if (error) {
856			free(ps_argvstr, M_TEMP);
857			return (error);
858		}
859		for (i = 0; i < pstr.ps_nargvstr; i++) {
860			sbuf_copyin(sb, ps_argvstr[i], 0);
861			sbuf_printf(sb, "%c", '\0');
862		}
863		free(ps_argvstr, M_TEMP);
864	}
865
866	return (0);
867}
868
869/*
870 * Filler function for proc/pid/environ
871 */
872static int
873linprocfs_doprocenviron(PFS_FILL_ARGS)
874{
875
876	sbuf_printf(sb, "doprocenviron\n%c", '\0');
877	return (0);
878}
879
880/*
881 * Filler function for proc/pid/maps
882 */
883static int
884linprocfs_doprocmaps(PFS_FILL_ARGS)
885{
886	struct vmspace *vm;
887	vm_map_t map;
888	vm_map_entry_t entry, tmp_entry;
889	vm_object_t obj, tobj, lobj;
890	vm_offset_t e_start, e_end;
891	vm_ooffset_t off = 0;
892	vm_prot_t e_prot;
893	unsigned int last_timestamp;
894	char *name = "", *freename = NULL;
895	ino_t ino;
896	int ref_count, shadow_count, flags;
897	int error;
898	struct vnode *vp;
899	struct vattr vat;
900	int locked;
901
902	PROC_LOCK(p);
903	error = p_candebug(td, p);
904	PROC_UNLOCK(p);
905	if (error)
906		return (error);
907
908	if (uio->uio_rw != UIO_READ)
909		return (EOPNOTSUPP);
910
911	error = 0;
912	vm = vmspace_acquire_ref(p);
913	if (vm == NULL)
914		return (ESRCH);
915	map = &vm->vm_map;
916	vm_map_lock_read(map);
917	for (entry = map->header.next; entry != &map->header;
918	    entry = entry->next) {
919		name = "";
920		freename = NULL;
921		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
922			continue;
923		e_prot = entry->protection;
924		e_start = entry->start;
925		e_end = entry->end;
926		obj = entry->object.vm_object;
927		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
928			VM_OBJECT_LOCK(tobj);
929			if (lobj != obj)
930				VM_OBJECT_UNLOCK(lobj);
931			lobj = tobj;
932		}
933		last_timestamp = map->timestamp;
934		vm_map_unlock_read(map);
935		ino = 0;
936		if (lobj) {
937			off = IDX_TO_OFF(lobj->size);
938			if (lobj->type == OBJT_VNODE) {
939				vp = lobj->handle;
940				if (vp)
941					vref(vp);
942			}
943			else
944				vp = NULL;
945			if (lobj != obj)
946				VM_OBJECT_UNLOCK(lobj);
947			flags = obj->flags;
948			ref_count = obj->ref_count;
949			shadow_count = obj->shadow_count;
950			VM_OBJECT_UNLOCK(obj);
951			if (vp) {
952				vn_fullpath(td, vp, &name, &freename);
953				locked = VFS_LOCK_GIANT(vp->v_mount);
954				vn_lock(vp, LK_SHARED | LK_RETRY);
955				VOP_GETATTR(vp, &vat, td->td_ucred);
956				ino = vat.va_fileid;
957				vput(vp);
958				VFS_UNLOCK_GIANT(locked);
959			}
960		} else {
961			flags = 0;
962			ref_count = 0;
963			shadow_count = 0;
964		}
965
966		/*
967		 * format:
968		 *  start, end, access, offset, major, minor, inode, name.
969		 */
970		error = sbuf_printf(sb,
971		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
972		    (u_long)e_start, (u_long)e_end,
973		    (e_prot & VM_PROT_READ)?"r":"-",
974		    (e_prot & VM_PROT_WRITE)?"w":"-",
975		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
976		    "p",
977		    (u_long)off,
978		    0,
979		    0,
980		    (u_long)ino,
981		    *name ? "     " : "",
982		    name
983		    );
984		if (freename)
985			free(freename, M_TEMP);
986		vm_map_lock_read(map);
987		if (error == -1) {
988			error = 0;
989			break;
990		}
991		if (last_timestamp != map->timestamp) {
992			/*
993			 * Look again for the entry because the map was
994			 * modified while it was unlocked.  Specifically,
995			 * the entry may have been clipped, merged, or deleted.
996			 */
997			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
998			entry = tmp_entry;
999		}
1000	}
1001	vm_map_unlock_read(map);
1002	vmspace_free(vm);
1003
1004	return (error);
1005}
1006
1007/*
1008 * Filler function for proc/net/dev
1009 */
1010static int
1011linprocfs_donetdev(PFS_FILL_ARGS)
1012{
1013	INIT_VNET_NET(TD_TO_VNET(curthread));
1014	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1015	struct ifnet *ifp;
1016
1017	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1018	    "Inter-", "   Receive", "  Transmit", " face",
1019	    "bytes    packets errs drop fifo frame compressed",
1020	    "bytes    packets errs drop fifo frame compressed");
1021
1022	IFNET_RLOCK();
1023	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1024		linux_ifname(ifp, ifname, sizeof ifname);
1025			sbuf_printf(sb, "%6.6s:", ifname);
1026		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1027		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1028		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1029		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1030	}
1031	IFNET_RUNLOCK();
1032
1033	return (0);
1034}
1035
1036/*
1037 * Filler function for proc/sys/kernel/osrelease
1038 */
1039static int
1040linprocfs_doosrelease(PFS_FILL_ARGS)
1041{
1042	char osrelease[LINUX_MAX_UTSNAME];
1043
1044	linux_get_osrelease(td, osrelease);
1045	sbuf_printf(sb, "%s\n", osrelease);
1046
1047	return (0);
1048}
1049
1050/*
1051 * Filler function for proc/sys/kernel/ostype
1052 */
1053static int
1054linprocfs_doostype(PFS_FILL_ARGS)
1055{
1056	char osname[LINUX_MAX_UTSNAME];
1057
1058	linux_get_osname(td, osname);
1059	sbuf_printf(sb, "%s\n", osname);
1060
1061	return (0);
1062}
1063
1064/*
1065 * Filler function for proc/sys/kernel/version
1066 */
1067static int
1068linprocfs_doosbuild(PFS_FILL_ARGS)
1069{
1070
1071	linprocfs_osbuild(td, sb);
1072	sbuf_cat(sb, "\n");
1073	return (0);
1074}
1075
1076/*
1077 * Filler function for proc/sys/kernel/msgmni
1078 */
1079static int
1080linprocfs_domsgmni(PFS_FILL_ARGS)
1081{
1082
1083	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1084	return (0);
1085}
1086
1087/*
1088 * Filler function for proc/sys/kernel/pid_max
1089 */
1090static int
1091linprocfs_dopid_max(PFS_FILL_ARGS)
1092{
1093
1094	sbuf_printf(sb, "%i\n", PID_MAX);
1095	return (0);
1096}
1097
1098/*
1099 * Filler function for proc/sys/kernel/sem
1100 */
1101static int
1102linprocfs_dosem(PFS_FILL_ARGS)
1103{
1104
1105	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1106	    seminfo.semopm, seminfo.semmni);
1107	return (0);
1108}
1109
1110/*
1111 * Filler function for proc/scsi/device_info
1112 */
1113static int
1114linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1115{
1116
1117	return (0);
1118}
1119
1120/*
1121 * Filler function for proc/scsi/scsi
1122 */
1123static int
1124linprocfs_doscsiscsi(PFS_FILL_ARGS)
1125{
1126
1127	return (0);
1128}
1129
1130extern struct cdevsw *cdevsw[];
1131
1132/*
1133 * Filler function for proc/devices
1134 */
1135static int
1136linprocfs_dodevices(PFS_FILL_ARGS)
1137{
1138	char *char_devices;
1139	sbuf_printf(sb, "Character devices:\n");
1140
1141	char_devices = linux_get_char_devices();
1142	sbuf_printf(sb, "%s", char_devices);
1143	linux_free_get_char_devices(char_devices);
1144
1145	sbuf_printf(sb, "\nBlock devices:\n");
1146
1147	return (0);
1148}
1149
1150/*
1151 * Filler function for proc/cmdline
1152 */
1153static int
1154linprocfs_docmdline(PFS_FILL_ARGS)
1155{
1156
1157	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1158	sbuf_printf(sb, " ro root=302\n");
1159	return (0);
1160}
1161
1162#if 0
1163/*
1164 * Filler function for proc/modules
1165 */
1166static int
1167linprocfs_domodules(PFS_FILL_ARGS)
1168{
1169	struct linker_file *lf;
1170
1171	TAILQ_FOREACH(lf, &linker_files, link) {
1172		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1173		    (unsigned long)lf->size, lf->refs);
1174	}
1175	return (0);
1176}
1177#endif
1178
1179/*
1180 * Constructor
1181 */
1182static int
1183linprocfs_init(PFS_INIT_ARGS)
1184{
1185	struct pfs_node *root;
1186	struct pfs_node *dir;
1187
1188	root = pi->pi_root;
1189
1190	/* /proc/... */
1191	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1192	    NULL, NULL, NULL, PFS_RD);
1193	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1194	    NULL, NULL, NULL, PFS_RD);
1195	pfs_create_file(root, "devices", &linprocfs_dodevices,
1196	    NULL, NULL, NULL, PFS_RD);
1197	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1198	    NULL, NULL, NULL, PFS_RD);
1199	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1200	    NULL, NULL, NULL, PFS_RD);
1201#if 0
1202	pfs_create_file(root, "modules", &linprocfs_domodules,
1203	    NULL, NULL, NULL, PFS_RD);
1204#endif
1205	pfs_create_file(root, "mounts", &linprocfs_domtab,
1206	    NULL, NULL, NULL, PFS_RD);
1207	pfs_create_file(root, "mtab", &linprocfs_domtab,
1208	    NULL, NULL, NULL, PFS_RD);
1209	pfs_create_link(root, "self", &procfs_docurproc,
1210	    NULL, NULL, NULL, 0);
1211	pfs_create_file(root, "stat", &linprocfs_dostat,
1212	    NULL, NULL, NULL, PFS_RD);
1213	pfs_create_file(root, "uptime", &linprocfs_douptime,
1214	    NULL, NULL, NULL, PFS_RD);
1215	pfs_create_file(root, "version", &linprocfs_doversion,
1216	    NULL, NULL, NULL, PFS_RD);
1217
1218	/* /proc/net/... */
1219	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1220	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1221	    NULL, NULL, NULL, PFS_RD);
1222
1223	/* /proc/<pid>/... */
1224	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1225	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1226	    NULL, NULL, NULL, PFS_RD);
1227	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1228	    NULL, NULL, NULL, 0);
1229	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1230	    NULL, NULL, NULL, PFS_RD);
1231	pfs_create_link(dir, "exe", &procfs_doprocfile,
1232	    NULL, &procfs_notsystem, NULL, 0);
1233	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1234	    NULL, NULL, NULL, PFS_RD);
1235	pfs_create_file(dir, "mem", &procfs_doprocmem,
1236	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1237	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1238	    NULL, NULL, NULL, 0);
1239	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1240	    NULL, NULL, NULL, PFS_RD);
1241	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1242	    NULL, NULL, NULL, PFS_RD);
1243	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1244	    NULL, NULL, NULL, PFS_RD);
1245
1246	/* /proc/scsi/... */
1247	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1248	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1249	    NULL, NULL, NULL, PFS_RD);
1250	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1251	    NULL, NULL, NULL, PFS_RD);
1252
1253	/* /proc/sys/... */
1254	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1255	/* /proc/sys/kernel/... */
1256	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1257	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1258	    NULL, NULL, NULL, PFS_RD);
1259	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1260	    NULL, NULL, NULL, PFS_RD);
1261	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1262	    NULL, NULL, NULL, PFS_RD);
1263	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1264	    NULL, NULL, NULL, PFS_RD);
1265	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1266	    NULL, NULL, NULL, PFS_RD);
1267	pfs_create_file(dir, "sem", &linprocfs_dosem,
1268	    NULL, NULL, NULL, PFS_RD);
1269
1270	return (0);
1271}
1272
1273/*
1274 * Destructor
1275 */
1276static int
1277linprocfs_uninit(PFS_INIT_ARGS)
1278{
1279
1280	/* nothing to do, pseudofs will GC */
1281	return (0);
1282}
1283
1284PSEUDOFS(linprocfs, 1);
1285MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1286MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1287MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1288MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1289