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