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