xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision eddfbb763ded6b5f6777335142be9a0edab628bb)
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 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1082 	struct ifnet *ifp;
1083 
1084 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1085 	    "Inter-", "   Receive", "  Transmit", " face",
1086 	    "bytes    packets errs drop fifo frame compressed",
1087 	    "bytes    packets errs drop fifo frame compressed");
1088 
1089 	IFNET_RLOCK();
1090 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1091 		linux_ifname(ifp, ifname, sizeof ifname);
1092 			sbuf_printf(sb, "%6.6s:", ifname);
1093 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1094 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1095 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1096 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1097 	}
1098 	IFNET_RUNLOCK();
1099 
1100 	return (0);
1101 }
1102 
1103 /*
1104  * Filler function for proc/sys/kernel/osrelease
1105  */
1106 static int
1107 linprocfs_doosrelease(PFS_FILL_ARGS)
1108 {
1109 	char osrelease[LINUX_MAX_UTSNAME];
1110 
1111 	linux_get_osrelease(td, osrelease);
1112 	sbuf_printf(sb, "%s\n", osrelease);
1113 
1114 	return (0);
1115 }
1116 
1117 /*
1118  * Filler function for proc/sys/kernel/ostype
1119  */
1120 static int
1121 linprocfs_doostype(PFS_FILL_ARGS)
1122 {
1123 	char osname[LINUX_MAX_UTSNAME];
1124 
1125 	linux_get_osname(td, osname);
1126 	sbuf_printf(sb, "%s\n", osname);
1127 
1128 	return (0);
1129 }
1130 
1131 /*
1132  * Filler function for proc/sys/kernel/version
1133  */
1134 static int
1135 linprocfs_doosbuild(PFS_FILL_ARGS)
1136 {
1137 
1138 	linprocfs_osbuild(td, sb);
1139 	sbuf_cat(sb, "\n");
1140 	return (0);
1141 }
1142 
1143 /*
1144  * Filler function for proc/sys/kernel/msgmni
1145  */
1146 static int
1147 linprocfs_domsgmni(PFS_FILL_ARGS)
1148 {
1149 
1150 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1151 	return (0);
1152 }
1153 
1154 /*
1155  * Filler function for proc/sys/kernel/pid_max
1156  */
1157 static int
1158 linprocfs_dopid_max(PFS_FILL_ARGS)
1159 {
1160 
1161 	sbuf_printf(sb, "%i\n", PID_MAX);
1162 	return (0);
1163 }
1164 
1165 /*
1166  * Filler function for proc/sys/kernel/sem
1167  */
1168 static int
1169 linprocfs_dosem(PFS_FILL_ARGS)
1170 {
1171 
1172 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1173 	    seminfo.semopm, seminfo.semmni);
1174 	return (0);
1175 }
1176 
1177 /*
1178  * Filler function for proc/scsi/device_info
1179  */
1180 static int
1181 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1182 {
1183 
1184 	return (0);
1185 }
1186 
1187 /*
1188  * Filler function for proc/scsi/scsi
1189  */
1190 static int
1191 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1192 {
1193 
1194 	return (0);
1195 }
1196 
1197 extern struct cdevsw *cdevsw[];
1198 
1199 /*
1200  * Filler function for proc/devices
1201  */
1202 static int
1203 linprocfs_dodevices(PFS_FILL_ARGS)
1204 {
1205 	char *char_devices;
1206 	sbuf_printf(sb, "Character devices:\n");
1207 
1208 	char_devices = linux_get_char_devices();
1209 	sbuf_printf(sb, "%s", char_devices);
1210 	linux_free_get_char_devices(char_devices);
1211 
1212 	sbuf_printf(sb, "\nBlock devices:\n");
1213 
1214 	return (0);
1215 }
1216 
1217 /*
1218  * Filler function for proc/cmdline
1219  */
1220 static int
1221 linprocfs_docmdline(PFS_FILL_ARGS)
1222 {
1223 
1224 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1225 	sbuf_printf(sb, " ro root=302\n");
1226 	return (0);
1227 }
1228 
1229 #if 0
1230 /*
1231  * Filler function for proc/modules
1232  */
1233 static int
1234 linprocfs_domodules(PFS_FILL_ARGS)
1235 {
1236 	struct linker_file *lf;
1237 
1238 	TAILQ_FOREACH(lf, &linker_files, link) {
1239 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1240 		    (unsigned long)lf->size, lf->refs);
1241 	}
1242 	return (0);
1243 }
1244 #endif
1245 
1246 /*
1247  * Constructor
1248  */
1249 static int
1250 linprocfs_init(PFS_INIT_ARGS)
1251 {
1252 	struct pfs_node *root;
1253 	struct pfs_node *dir;
1254 
1255 	root = pi->pi_root;
1256 
1257 	/* /proc/... */
1258 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1259 	    NULL, NULL, NULL, PFS_RD);
1260 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1261 	    NULL, NULL, NULL, PFS_RD);
1262 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1263 	    NULL, NULL, NULL, PFS_RD);
1264 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1265 	    NULL, NULL, NULL, PFS_RD);
1266 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1267 	    NULL, NULL, NULL, PFS_RD);
1268 #if 0
1269 	pfs_create_file(root, "modules", &linprocfs_domodules,
1270 	    NULL, NULL, NULL, PFS_RD);
1271 #endif
1272 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1273 	    NULL, NULL, NULL, PFS_RD);
1274 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1275 	    NULL, NULL, NULL, PFS_RD);
1276 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1277 	    NULL, NULL, NULL, PFS_RD);
1278 	pfs_create_link(root, "self", &procfs_docurproc,
1279 	    NULL, NULL, NULL, 0);
1280 	pfs_create_file(root, "stat", &linprocfs_dostat,
1281 	    NULL, NULL, NULL, PFS_RD);
1282 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1283 	    NULL, NULL, NULL, PFS_RD);
1284 	pfs_create_file(root, "version", &linprocfs_doversion,
1285 	    NULL, NULL, NULL, PFS_RD);
1286 
1287 	/* /proc/net/... */
1288 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1289 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1290 	    NULL, NULL, NULL, PFS_RD);
1291 
1292 	/* /proc/<pid>/... */
1293 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1294 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1295 	    NULL, NULL, NULL, PFS_RD);
1296 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1297 	    NULL, NULL, NULL, 0);
1298 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1299 	    NULL, NULL, NULL, PFS_RD);
1300 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1301 	    NULL, &procfs_notsystem, NULL, 0);
1302 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1303 	    NULL, NULL, NULL, PFS_RD);
1304 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1305 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1306 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1307 	    NULL, NULL, NULL, 0);
1308 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1309 	    NULL, NULL, NULL, PFS_RD);
1310 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1311 	    NULL, NULL, NULL, PFS_RD);
1312 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1313 	    NULL, NULL, NULL, PFS_RD);
1314 
1315 	/* /proc/scsi/... */
1316 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1317 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1318 	    NULL, NULL, NULL, PFS_RD);
1319 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1320 	    NULL, NULL, NULL, PFS_RD);
1321 
1322 	/* /proc/sys/... */
1323 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1324 	/* /proc/sys/kernel/... */
1325 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1326 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1327 	    NULL, NULL, NULL, PFS_RD);
1328 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1329 	    NULL, NULL, NULL, PFS_RD);
1330 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1331 	    NULL, NULL, NULL, PFS_RD);
1332 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1333 	    NULL, NULL, NULL, PFS_RD);
1334 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1335 	    NULL, NULL, NULL, PFS_RD);
1336 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1337 	    NULL, NULL, NULL, PFS_RD);
1338 
1339 	return (0);
1340 }
1341 
1342 /*
1343  * Destructor
1344  */
1345 static int
1346 linprocfs_uninit(PFS_INIT_ARGS)
1347 {
1348 
1349 	/* nothing to do, pseudofs will GC */
1350 	return (0);
1351 }
1352 
1353 PSEUDOFS(linprocfs, 1);
1354 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1355 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1356 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1357 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1358