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