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