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