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