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