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