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