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