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