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