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