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