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