xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision 35a04710d7286aa9538917fd7f8e417dbee95b82)
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  * uninterruptible 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 		PROC_SLOCK(p);
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 		PROC_SUNLOCK(p);
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, tmp_entry;
864 	vm_object_t obj, tobj, lobj;
865 	vm_offset_t saved_end;
866 	vm_ooffset_t off = 0;
867 	char *name = "", *freename = NULL;
868 	size_t len;
869 	ino_t ino;
870 	unsigned int last_timestamp;
871 	int ref_count, shadow_count, flags;
872 	int error;
873 	struct vnode *vp;
874 	struct vattr vat;
875 	int locked;
876 
877 	PROC_LOCK(p);
878 	error = p_candebug(td, p);
879 	PROC_UNLOCK(p);
880 	if (error)
881 		return (error);
882 
883 	if (uio->uio_rw != UIO_READ)
884 		return (EOPNOTSUPP);
885 
886 	if (uio->uio_offset != 0)
887 		return (0);
888 
889 	error = 0;
890 	vm_map_lock_read(map);
891 	for (entry = map->header.next;
892 	    ((uio->uio_resid > 0) && (entry != &map->header));
893 	    entry = entry->next) {
894 		name = "";
895 		freename = NULL;
896 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
897 			continue;
898 		saved_end = entry->end;
899 		obj = entry->object.vm_object;
900 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
901 			VM_OBJECT_LOCK(tobj);
902 			if (lobj != obj)
903 				VM_OBJECT_UNLOCK(lobj);
904 			lobj = tobj;
905 		}
906 		ino = 0;
907 		if (lobj) {
908 			off = IDX_TO_OFF(lobj->size);
909 			if (lobj->type == OBJT_VNODE) {
910 				vp = lobj->handle;
911 				if (vp)
912 					vref(vp);
913 			}
914 			else
915 				vp = NULL;
916 			if (lobj != obj)
917 				VM_OBJECT_UNLOCK(lobj);
918 			flags = obj->flags;
919 			ref_count = obj->ref_count;
920 			shadow_count = obj->shadow_count;
921 			VM_OBJECT_UNLOCK(obj);
922 			if (vp) {
923 				vn_fullpath(td, vp, &name, &freename);
924 				locked = VFS_LOCK_GIANT(vp->v_mount);
925 				vn_lock(vp, LK_SHARED | LK_RETRY, td);
926 				VOP_GETATTR(vp, &vat, td->td_ucred, td);
927 				ino = vat.va_fileid;
928 				vput(vp);
929 				VFS_UNLOCK_GIANT(locked);
930 			}
931 		} else {
932 			flags = 0;
933 			ref_count = 0;
934 			shadow_count = 0;
935 		}
936 
937 		/*
938 		 * format:
939 		 *  start, end, access, offset, major, minor, inode, name.
940 		 */
941 		snprintf(mebuffer, sizeof mebuffer,
942 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
943 		    (u_long)entry->start, (u_long)entry->end,
944 		    (entry->protection & VM_PROT_READ)?"r":"-",
945 		    (entry->protection & VM_PROT_WRITE)?"w":"-",
946 		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
947 		    "p",
948 		    (u_long)off,
949 		    0,
950 		    0,
951 		    (u_long)ino,
952 		    *name ? "     " : "",
953 		    name
954 		    );
955 		if (freename)
956 			free(freename, M_TEMP);
957 		len = strlen(mebuffer);
958 		if (len > uio->uio_resid)
959 			len = uio->uio_resid; /*
960 					       * XXX We should probably return
961 					       * EFBIG here, as in procfs.
962 					       */
963 		last_timestamp = map->timestamp;
964 		vm_map_unlock_read(map);
965 		error = uiomove(mebuffer, len, uio);
966 		vm_map_lock_read(map);
967 		if (error)
968 			break;
969 		if (last_timestamp + 1 != map->timestamp) {
970 			/*
971 			 * Look again for the entry because the map was
972 			 * modified while it was unlocked.  Specifically,
973 			 * the entry may have been clipped, merged, or deleted.
974 			 */
975 			vm_map_lookup_entry(map, saved_end - 1, &tmp_entry);
976 			entry = tmp_entry;
977 		}
978 	}
979 	vm_map_unlock_read(map);
980 
981 	return (error);
982 }
983 
984 /*
985  * Filler function for proc/net/dev
986  */
987 static int
988 linprocfs_donetdev(PFS_FILL_ARGS)
989 {
990 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
991 	struct ifnet *ifp;
992 
993 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
994 	    "Inter-", "   Receive", "  Transmit", " face",
995 	    "bytes    packets errs drop fifo frame compressed",
996 	    "bytes    packets errs drop fifo frame compressed");
997 
998 	IFNET_RLOCK();
999 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1000 		linux_ifname(ifp, ifname, sizeof ifname);
1001 			sbuf_printf(sb, "%6.6s:", ifname);
1002 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1003 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1004 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1005 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1006 	}
1007 	IFNET_RUNLOCK();
1008 
1009 	return (0);
1010 }
1011 
1012 /*
1013  * Filler function for proc/sys/kernel/osrelease
1014  */
1015 static int
1016 linprocfs_doosrelease(PFS_FILL_ARGS)
1017 {
1018 	char osrelease[LINUX_MAX_UTSNAME];
1019 
1020 	linux_get_osrelease(td, osrelease);
1021 	sbuf_printf(sb, "%s\n", osrelease);
1022 
1023 	return (0);
1024 }
1025 
1026 /*
1027  * Filler function for proc/sys/kernel/ostype
1028  */
1029 static int
1030 linprocfs_doostype(PFS_FILL_ARGS)
1031 {
1032 	char osname[LINUX_MAX_UTSNAME];
1033 
1034 	linux_get_osname(td, osname);
1035 	sbuf_printf(sb, "%s\n", osname);
1036 
1037 	return (0);
1038 }
1039 
1040 /*
1041  * Filler function for proc/sys/kernel/version
1042  */
1043 static int
1044 linprocfs_doosbuild(PFS_FILL_ARGS)
1045 {
1046 
1047 	linprocfs_osbuild(td, sb);
1048 	sbuf_cat(sb, "\n");
1049 	return (0);
1050 }
1051 
1052 /*
1053  * Filler function for proc/sys/kernel/msgmni
1054  */
1055 static int
1056 linprocfs_domsgmni(PFS_FILL_ARGS)
1057 {
1058 
1059 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1060 	return (0);
1061 }
1062 
1063 /*
1064  * Filler function for proc/sys/kernel/pid_max
1065  */
1066 static int
1067 linprocfs_dopid_max(PFS_FILL_ARGS)
1068 {
1069 
1070 	sbuf_printf(sb, "%i\n", PID_MAX);
1071 	return (0);
1072 }
1073 
1074 /*
1075  * Filler function for proc/sys/kernel/sem
1076  */
1077 static int
1078 linprocfs_dosem(PFS_FILL_ARGS)
1079 {
1080 
1081 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1082 	    seminfo.semopm, seminfo.semmni);
1083 	return (0);
1084 }
1085 
1086 /*
1087  * Filler function for proc/scsi/device_info
1088  */
1089 static int
1090 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1091 {
1092 
1093 	return (0);
1094 }
1095 
1096 /*
1097  * Filler function for proc/scsi/scsi
1098  */
1099 static int
1100 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1101 {
1102 
1103 	return (0);
1104 }
1105 
1106 extern struct cdevsw *cdevsw[];
1107 
1108 /*
1109  * Filler function for proc/devices
1110  */
1111 static int
1112 linprocfs_dodevices(PFS_FILL_ARGS)
1113 {
1114 	char *char_devices;
1115 	sbuf_printf(sb, "Character devices:\n");
1116 
1117 	char_devices = linux_get_char_devices();
1118 	sbuf_printf(sb, "%s", char_devices);
1119 	linux_free_get_char_devices(char_devices);
1120 
1121 	sbuf_printf(sb, "\nBlock devices:\n");
1122 
1123 	return (0);
1124 }
1125 
1126 /*
1127  * Filler function for proc/cmdline
1128  */
1129 static int
1130 linprocfs_docmdline(PFS_FILL_ARGS)
1131 {
1132 
1133 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1134 	sbuf_printf(sb, " ro root=302\n");
1135 	return (0);
1136 }
1137 
1138 #if 0
1139 /*
1140  * Filler function for proc/modules
1141  */
1142 static int
1143 linprocfs_domodules(PFS_FILL_ARGS)
1144 {
1145 	struct linker_file *lf;
1146 
1147 	TAILQ_FOREACH(lf, &linker_files, link) {
1148 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1149 		    (unsigned long)lf->size, lf->refs);
1150 	}
1151 	return (0);
1152 }
1153 #endif
1154 
1155 /*
1156  * Constructor
1157  */
1158 static int
1159 linprocfs_init(PFS_INIT_ARGS)
1160 {
1161 	struct pfs_node *root;
1162 	struct pfs_node *dir;
1163 
1164 	root = pi->pi_root;
1165 
1166 	/* /proc/... */
1167 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1168 	    NULL, NULL, NULL, PFS_RD);
1169 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1170 	    NULL, NULL, NULL, PFS_RD);
1171 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1172 	    NULL, NULL, NULL, PFS_RD);
1173 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1174 	    NULL, NULL, NULL, PFS_RD);
1175 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1176 	    NULL, NULL, NULL, PFS_RD);
1177 #if 0
1178 	pfs_create_file(root, "modules", &linprocfs_domodules,
1179 	    NULL, NULL, NULL, PFS_RD);
1180 #endif
1181 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1182 	    NULL, NULL, NULL, PFS_RD);
1183 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1184 	    NULL, NULL, NULL, PFS_RD);
1185 	pfs_create_link(root, "self", &procfs_docurproc,
1186 	    NULL, NULL, NULL, 0);
1187 	pfs_create_file(root, "stat", &linprocfs_dostat,
1188 	    NULL, NULL, NULL, PFS_RD);
1189 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1190 	    NULL, NULL, NULL, PFS_RD);
1191 	pfs_create_file(root, "version", &linprocfs_doversion,
1192 	    NULL, NULL, NULL, PFS_RD);
1193 
1194 	/* /proc/net/... */
1195 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1196 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1197 	    NULL, NULL, NULL, PFS_RD);
1198 
1199 	/* /proc/<pid>/... */
1200 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1201 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1202 	    NULL, NULL, NULL, PFS_RD);
1203 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1204 	    NULL, NULL, NULL, 0);
1205 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1206 	    NULL, NULL, NULL, PFS_RD);
1207 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1208 	    NULL, &procfs_notsystem, NULL, 0);
1209 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1210 	    NULL, NULL, NULL, PFS_RD);
1211 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1212 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1213 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1214 	    NULL, NULL, NULL, 0);
1215 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1216 	    NULL, NULL, NULL, PFS_RD);
1217 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1218 	    NULL, NULL, NULL, PFS_RD);
1219 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1220 	    NULL, NULL, NULL, PFS_RD);
1221 
1222 	/* /proc/scsi/... */
1223 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1224 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1225 	    NULL, NULL, NULL, PFS_RD);
1226 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1227 	    NULL, NULL, NULL, PFS_RD);
1228 
1229 	/* /proc/sys/... */
1230 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1231 	/* /proc/sys/kernel/... */
1232 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1233 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1234 	    NULL, NULL, NULL, PFS_RD);
1235 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1236 	    NULL, NULL, NULL, PFS_RD);
1237 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1238 	    NULL, NULL, NULL, PFS_RD);
1239 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1240 	    NULL, NULL, NULL, PFS_RD);
1241 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1242 	    NULL, NULL, NULL, PFS_RD);
1243 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1244 	    NULL, NULL, NULL, PFS_RD);
1245 
1246 	return (0);
1247 }
1248 
1249 /*
1250  * Destructor
1251  */
1252 static int
1253 linprocfs_uninit(PFS_INIT_ARGS)
1254 {
1255 
1256 	/* nothing to do, pseudofs will GC */
1257 	return (0);
1258 }
1259 
1260 PSEUDOFS(linprocfs, 1);
1261 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1262 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1263 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1264 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1265