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