xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision f3bb407b7c1b3faa88d0580541f01a8e6fb6cc68)
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/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  */
124 static char linux_state[] = "RRSTZDD";
125 
126 /*
127  * Filler function for proc/meminfo
128  */
129 static int
130 linprocfs_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  */
202 static int
203 linprocfs_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  */
302 static int
303 linprocfs_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  */
370 static int
371 linprocfs_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  */
406 static int
407 linprocfs_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  */
421 static void
422 linprocfs_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  */
447 static void
448 linprocfs_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  */
470 static int
471 linprocfs_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  */
490 static int
491 linprocfs_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  */
512 static int
513 linprocfs_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  */
586 static int
587 linprocfs_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  */
617 static int
618 linprocfs_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  */
754 static int
755 linprocfs_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  */
770 static int
771 linprocfs_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  */
788 static int
789 linprocfs_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  */
841 static int
842 linprocfs_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  */
852 static int
853 linprocfs_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  */
963 static int
964 linprocfs_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  */
991 static int
992 linprocfs_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  */
1005 static int
1006 linprocfs_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  */
1019 static int
1020 linprocfs_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  */
1031 static int
1032 linprocfs_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  */
1049 static int
1050 linprocfs_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  */
1061 static int
1062 linprocfs_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  */
1099 static int
1100 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1101 {
1102 	return (0);
1103 }
1104 
1105 /*
1106  * Filler function for proc/scsi/scsi
1107  */
1108 static int
1109 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1110 {
1111 	return (0);
1112 }
1113 
1114 extern struct cdevsw *cdevsw[];
1115 
1116 /*
1117  * Filler function for proc/devices
1118  */
1119 static int
1120 linprocfs_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  */
1137 static int
1138 linprocfs_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  */
1149 static int
1150 linprocfs_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  */
1165 static int
1166 linprocfs_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, PFS_RD);
1176 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1177 	    NULL, NULL, PFS_RD);
1178 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1179 	    NULL, NULL, PFS_RD);
1180 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1181 	    NULL, NULL, PFS_RD);
1182 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1183 	    NULL, NULL, PFS_RD);
1184 #if 0
1185 	pfs_create_file(root, "modules", &linprocfs_domodules,
1186 	    NULL, NULL, PFS_RD);
1187 #endif
1188 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1189 	    NULL, NULL, PFS_RD);
1190 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1191 	    NULL, NULL, PFS_RD);
1192 	pfs_create_link(root, "self", &procfs_docurproc,
1193 	    NULL, NULL, 0);
1194 	pfs_create_file(root, "stat", &linprocfs_dostat,
1195 	    NULL, NULL, PFS_RD);
1196 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1197 	    NULL, NULL, PFS_RD);
1198 	pfs_create_file(root, "version", &linprocfs_doversion,
1199 	    NULL, NULL, PFS_RD);
1200 
1201 	/* /proc/net/... */
1202 	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1203 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1204 	    NULL, NULL, PFS_RD);
1205 
1206 	/* /proc/<pid>/... */
1207 	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1208 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1209 	    NULL, NULL, PFS_RD);
1210 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1211 	    NULL, NULL, 0);
1212 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1213 	    NULL, NULL, PFS_RD);
1214 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1215 	    NULL, &procfs_notsystem, 0);
1216 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1217 	    NULL, NULL, PFS_RD);
1218 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1219 	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1220 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1221 	    NULL, NULL, 0);
1222 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1223 	    NULL, NULL, PFS_RD);
1224 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1225 	    NULL, NULL, PFS_RD);
1226 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1227 	    NULL, NULL, PFS_RD);
1228 
1229 	/* /proc/scsi/... */
1230 	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1231 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1232 	    NULL, NULL, PFS_RD);
1233 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1234 	    NULL, NULL, PFS_RD);
1235 
1236 	/* /proc/sys/... */
1237 	dir = pfs_create_dir(root, "sys", NULL, NULL, 0);
1238 	/* /proc/sys/kernel/... */
1239 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0);
1240 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1241 	    NULL, NULL, PFS_RD);
1242 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1243 	    NULL, NULL, PFS_RD);
1244 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1245 	    NULL, NULL, PFS_RD);
1246 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1247 	    NULL, NULL, PFS_RD);
1248 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1249 	    NULL, NULL, PFS_RD);
1250 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1251 	    NULL, NULL, PFS_RD);
1252 
1253 	return (0);
1254 }
1255 
1256 /*
1257  * Destructor
1258  */
1259 static int
1260 linprocfs_uninit(PFS_INIT_ARGS)
1261 {
1262 
1263 	/* nothing to do, pseudofs will GC */
1264 	return (0);
1265 }
1266 
1267 PSEUDOFS(linprocfs, 1);
1268 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1269 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1270