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