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