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