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