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