xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision bc96366c864c07ef352edb92017357917c75b36c)
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  */
399 static int
400 linprocfs_dopartitions(PFS_FILL_ARGS)
401 {
402 	struct g_class *cp;
403 	struct g_geom *gp;
404 	struct g_provider *pp;
405 	struct nameidata nd;
406 	const char *lep;
407 	char  *dlep, *flep;
408 	size_t lep_len;
409 	int error;
410 	int major, minor;
411 
412 	/* resolve symlinks etc. in the emulation tree prefix */
413 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
414 	flep = NULL;
415 	error = namei(&nd);
416 	lep = linux_emul_path;
417 	if (error == 0) {
418 		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
419 			lep = dlep;
420 		vrele(nd.ni_vp);
421 	}
422 	lep_len = strlen(lep);
423 
424 	g_topology_lock();
425 	error = 0;
426 	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
427 	    "ruse wio wmerge wsect wuse running use aveq\n");
428 
429 	LIST_FOREACH(cp, &g_classes, class) {
430 		if (strcmp(cp->name, "DISK") == 0 ||
431 		    strcmp(cp->name, "PART") == 0)
432 			LIST_FOREACH(gp, &cp->geom, geom) {
433 				LIST_FOREACH(pp, &gp->provider, provider) {
434 					if (linux_driver_get_major_minor(
435 					    pp->name, &major, &minor) != 0) {
436 						major = 0;
437 						minor = 0;
438 					}
439 					sbuf_printf(sb, "%d %d %lld %s "
440 					    "%d %d %d %d %d "
441 					     "%d %d %d %d %d %d\n",
442 					     major, minor,
443 					     (long long)pp->mediasize, pp->name,
444 					     0, 0, 0, 0, 0,
445 					     0, 0, 0, 0, 0, 0);
446 				}
447 			}
448 	}
449 	g_topology_unlock();
450 
451 	free(flep, M_TEMP);
452 	return (error);
453 }
454 
455 
456 /*
457  * Filler function for proc/stat
458  */
459 static int
460 linprocfs_dostat(PFS_FILL_ARGS)
461 {
462 	struct pcpu *pcpu;
463 	long cp_time[CPUSTATES];
464 	long *cp;
465 	int i;
466 
467 	read_cpu_time(cp_time);
468 	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
469 	    T2J(cp_time[CP_USER]),
470 	    T2J(cp_time[CP_NICE]),
471 	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
472 	    T2J(cp_time[CP_IDLE]));
473 	CPU_FOREACH(i) {
474 		pcpu = pcpu_find(i);
475 		cp = pcpu->pc_cp_time;
476 		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
477 		    T2J(cp[CP_USER]),
478 		    T2J(cp[CP_NICE]),
479 		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
480 		    T2J(cp[CP_IDLE]));
481 	}
482 	sbuf_printf(sb,
483 	    "disk 0 0 0 0\n"
484 	    "page %u %u\n"
485 	    "swap %u %u\n"
486 	    "intr %u\n"
487 	    "ctxt %u\n"
488 	    "btime %lld\n",
489 	    vm_cnt.v_vnodepgsin,
490 	    vm_cnt.v_vnodepgsout,
491 	    vm_cnt.v_swappgsin,
492 	    vm_cnt.v_swappgsout,
493 	    vm_cnt.v_intr,
494 	    vm_cnt.v_swtch,
495 	    (long long)boottime.tv_sec);
496 	return (0);
497 }
498 
499 static int
500 linprocfs_doswaps(PFS_FILL_ARGS)
501 {
502 	struct xswdev xsw;
503 	uintmax_t total, used;
504 	int n;
505 	char devname[SPECNAMELEN + 1];
506 
507 	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
508 	mtx_lock(&Giant);
509 	for (n = 0; ; n++) {
510 		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
511 			break;
512 		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
513 		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
514 
515 		/*
516 		 * The space and not tab after the device name is on
517 		 * purpose.  Linux does so.
518 		 */
519 		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
520 		    devname, total, used);
521 	}
522 	mtx_unlock(&Giant);
523 	return (0);
524 }
525 
526 /*
527  * Filler function for proc/uptime
528  */
529 static int
530 linprocfs_douptime(PFS_FILL_ARGS)
531 {
532 	long cp_time[CPUSTATES];
533 	struct timeval tv;
534 
535 	getmicrouptime(&tv);
536 	read_cpu_time(cp_time);
537 	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
538 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
539 	    T2S(cp_time[CP_IDLE] / mp_ncpus),
540 	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
541 	return (0);
542 }
543 
544 /*
545  * Get OS build date
546  */
547 static void
548 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
549 {
550 #if 0
551 	char osbuild[256];
552 	char *cp1, *cp2;
553 
554 	strncpy(osbuild, version, 256);
555 	osbuild[255] = '\0';
556 	cp1 = strstr(osbuild, "\n");
557 	cp2 = strstr(osbuild, ":");
558 	if (cp1 && cp2) {
559 		*cp1 = *cp2 = '\0';
560 		cp1 = strstr(osbuild, "#");
561 	} else
562 		cp1 = NULL;
563 	if (cp1)
564 		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
565 	else
566 #endif
567 		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
568 }
569 
570 /*
571  * Get OS builder
572  */
573 static void
574 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
575 {
576 #if 0
577 	char builder[256];
578 	char *cp;
579 
580 	cp = strstr(version, "\n    ");
581 	if (cp) {
582 		strncpy(builder, cp + 5, 256);
583 		builder[255] = '\0';
584 		cp = strstr(builder, ":");
585 		if (cp)
586 			*cp = '\0';
587 	}
588 	if (cp)
589 		sbuf_cat(sb, builder);
590 	else
591 #endif
592 		sbuf_cat(sb, "des@freebsd.org");
593 }
594 
595 /*
596  * Filler function for proc/version
597  */
598 static int
599 linprocfs_doversion(PFS_FILL_ARGS)
600 {
601 	char osname[LINUX_MAX_UTSNAME];
602 	char osrelease[LINUX_MAX_UTSNAME];
603 
604 	linux_get_osname(td, osname);
605 	linux_get_osrelease(td, osrelease);
606 	sbuf_printf(sb, "%s version %s (", osname, osrelease);
607 	linprocfs_osbuilder(td, sb);
608 	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
609 	linprocfs_osbuild(td, sb);
610 	sbuf_cat(sb, "\n");
611 
612 	return (0);
613 }
614 
615 /*
616  * Filler function for proc/loadavg
617  */
618 static int
619 linprocfs_doloadavg(PFS_FILL_ARGS)
620 {
621 
622 	sbuf_printf(sb,
623 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
624 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
625 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
626 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
627 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
628 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
629 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
630 	    1,				/* number of running tasks */
631 	    nprocs,			/* number of tasks */
632 	    lastpid			/* the last pid */
633 	);
634 	return (0);
635 }
636 
637 /*
638  * Filler function for proc/pid/stat
639  */
640 static int
641 linprocfs_doprocstat(PFS_FILL_ARGS)
642 {
643 	struct kinfo_proc kp;
644 	char state;
645 	static int ratelimit = 0;
646 	vm_offset_t startcode, startdata;
647 
648 	sx_slock(&proctree_lock);
649 	PROC_LOCK(p);
650 	fill_kinfo_proc(p, &kp);
651 	sx_sunlock(&proctree_lock);
652 	if (p->p_vmspace) {
653 	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
654 	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
655 	} else {
656 	   startcode = 0;
657 	   startdata = 0;
658 	};
659 	sbuf_printf(sb, "%d", p->p_pid);
660 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
661 	PS_ADD("comm",		"(%s)",	p->p_comm);
662 	if (kp.ki_stat > sizeof(linux_state)) {
663 		state = 'R';
664 
665 		if (ratelimit == 0) {
666 			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
667 			    kp.ki_stat, sizeof(linux_state));
668 			++ratelimit;
669 		}
670 	} else
671 		state = linux_state[kp.ki_stat - 1];
672 	PS_ADD("state",		"%c",	state);
673 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
674 	PS_ADD("pgrp",		"%d",	p->p_pgid);
675 	PS_ADD("session",	"%d",	p->p_session->s_sid);
676 	PROC_UNLOCK(p);
677 	PS_ADD("tty",		"%ju",	(uintmax_t)kp.ki_tdev);
678 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
679 	PS_ADD("flags",		"%u",	0); /* XXX */
680 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
681 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
682 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
683 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
684 	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
685 	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
686 	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
687 	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
688 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
689 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
690 	PS_ADD("0",		"%d",	0); /* removed field */
691 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
692 	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
693 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
694 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
695 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
696 	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
697 	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
698 	PS_ADD("startstack",	"%u",	0); /* XXX */
699 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
700 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
701 	PS_ADD("signal",	"%u",	0); /* XXX */
702 	PS_ADD("blocked",	"%u",	0); /* XXX */
703 	PS_ADD("sigignore",	"%u",	0); /* XXX */
704 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
705 	PS_ADD("wchan",		"%u",	0); /* XXX */
706 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
707 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
708 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
709 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
710 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
711 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
712 #undef PS_ADD
713 	sbuf_putc(sb, '\n');
714 
715 	return (0);
716 }
717 
718 /*
719  * Filler function for proc/pid/statm
720  */
721 static int
722 linprocfs_doprocstatm(PFS_FILL_ARGS)
723 {
724 	struct kinfo_proc kp;
725 	segsz_t lsize;
726 
727 	sx_slock(&proctree_lock);
728 	PROC_LOCK(p);
729 	fill_kinfo_proc(p, &kp);
730 	PROC_UNLOCK(p);
731 	sx_sunlock(&proctree_lock);
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 	sx_slock(&proctree_lock);
765 	PROC_LOCK(p);
766 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
767 
768 	if (P_SHOULDSTOP(p)) {
769 		state = "T (stopped)";
770 	} else {
771 		switch(p->p_state) {
772 		case PRS_NEW:
773 			state = "I (idle)";
774 			break;
775 		case PRS_NORMAL:
776 			if (p->p_flag & P_WEXIT) {
777 				state = "X (exiting)";
778 				break;
779 			}
780 			switch(td2->td_state) {
781 			case TDS_INHIBITED:
782 				state = "S (sleeping)";
783 				break;
784 			case TDS_RUNQ:
785 			case TDS_RUNNING:
786 				state = "R (running)";
787 				break;
788 			default:
789 				state = "? (unknown)";
790 				break;
791 			}
792 			break;
793 		case PRS_ZOMBIE:
794 			state = "Z (zombie)";
795 			break;
796 		default:
797 			state = "? (unknown)";
798 			break;
799 		}
800 	}
801 
802 	fill_kinfo_proc(p, &kp);
803 	sx_sunlock(&proctree_lock);
804 
805 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
806 	sbuf_printf(sb, "State:\t%s\n",		state);
807 
808 	/*
809 	 * Credentials
810 	 */
811 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
812 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
813 						p->p_pptr->p_pid : 0);
814 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
815 						p->p_ucred->cr_uid,
816 						p->p_ucred->cr_svuid,
817 						/* FreeBSD doesn't have fsuid */
818 						p->p_ucred->cr_uid);
819 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
820 						p->p_ucred->cr_gid,
821 						p->p_ucred->cr_svgid,
822 						/* FreeBSD doesn't have fsgid */
823 						p->p_ucred->cr_gid);
824 	sbuf_cat(sb, "Groups:\t");
825 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
826 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
827 	PROC_UNLOCK(p);
828 	sbuf_putc(sb, '\n');
829 
830 	/*
831 	 * Memory
832 	 *
833 	 * While our approximation of VmLib may not be accurate (I
834 	 * don't know of a simple way to verify it, and I'm not sure
835 	 * it has much meaning anyway), I believe it's good enough.
836 	 *
837 	 * The same code that could (I think) accurately compute VmLib
838 	 * could also compute VmLck, but I don't really care enough to
839 	 * implement it. Submissions are welcome.
840 	 */
841 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
842 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
843 	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
844 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
845 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
846 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
847 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
848 	    kp.ki_ssize - kp.ki_tsize - 1;
849 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
850 
851 	/*
852 	 * Signal masks
853 	 *
854 	 * We support up to 128 signals, while Linux supports 32,
855 	 * but we only define 32 (the same 32 as Linux, to boot), so
856 	 * just show the lower 32 bits of each mask. XXX hack.
857 	 *
858 	 * NB: on certain platforms (Sparc at least) Linux actually
859 	 * supports 64 signals, but this code is a long way from
860 	 * running on anything but i386, so ignore that for now.
861 	 */
862 	PROC_LOCK(p);
863 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
864 	/*
865 	 * I can't seem to find out where the signal mask is in
866 	 * relation to struct proc, so SigBlk is left unimplemented.
867 	 */
868 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
869 	ps = p->p_sigacts;
870 	mtx_lock(&ps->ps_mtx);
871 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
872 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
873 	mtx_unlock(&ps->ps_mtx);
874 	PROC_UNLOCK(p);
875 
876 	/*
877 	 * Linux also prints the capability masks, but we don't have
878 	 * capabilities yet, and when we do get them they're likely to
879 	 * be meaningless to Linux programs, so we lie. XXX
880 	 */
881 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
882 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
883 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
884 
885 	return (0);
886 }
887 
888 
889 /*
890  * Filler function for proc/pid/cwd
891  */
892 static int
893 linprocfs_doproccwd(PFS_FILL_ARGS)
894 {
895 	char *fullpath = "unknown";
896 	char *freepath = NULL;
897 
898 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
899 	sbuf_printf(sb, "%s", fullpath);
900 	if (freepath)
901 		free(freepath, M_TEMP);
902 	return (0);
903 }
904 
905 /*
906  * Filler function for proc/pid/root
907  */
908 static int
909 linprocfs_doprocroot(PFS_FILL_ARGS)
910 {
911 	struct vnode *rvp;
912 	char *fullpath = "unknown";
913 	char *freepath = NULL;
914 
915 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
916 	vn_fullpath(td, rvp, &fullpath, &freepath);
917 	sbuf_printf(sb, "%s", fullpath);
918 	if (freepath)
919 		free(freepath, M_TEMP);
920 	return (0);
921 }
922 
923 /*
924  * Filler function for proc/pid/cmdline
925  */
926 static int
927 linprocfs_doproccmdline(PFS_FILL_ARGS)
928 {
929 	int ret;
930 
931 	PROC_LOCK(p);
932 	if ((ret = p_cansee(td, p)) != 0) {
933 		PROC_UNLOCK(p);
934 		return (ret);
935 	}
936 
937 	/*
938 	 * Mimic linux behavior and pass only processes with usermode
939 	 * address space as valid.  Return zero silently otherwize.
940 	 */
941 	if (p->p_vmspace == &vmspace0) {
942 		PROC_UNLOCK(p);
943 		return (0);
944 	}
945 	if (p->p_args != NULL) {
946 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
947 		PROC_UNLOCK(p);
948 		return (0);
949 	}
950 
951 	if ((p->p_flag & P_SYSTEM) != 0) {
952 		PROC_UNLOCK(p);
953 		return (0);
954 	}
955 
956 	PROC_UNLOCK(p);
957 
958 	ret = proc_getargv(td, p, sb);
959 	return (ret);
960 }
961 
962 /*
963  * Filler function for proc/pid/environ
964  */
965 static int
966 linprocfs_doprocenviron(PFS_FILL_ARGS)
967 {
968 	int ret;
969 
970 	PROC_LOCK(p);
971 	if ((ret = p_candebug(td, p)) != 0) {
972 		PROC_UNLOCK(p);
973 		return (ret);
974 	}
975 
976 	/*
977 	 * Mimic linux behavior and pass only processes with usermode
978 	 * address space as valid.  Return zero silently otherwize.
979 	 */
980 	if (p->p_vmspace == &vmspace0) {
981 		PROC_UNLOCK(p);
982 		return (0);
983 	}
984 
985 	if ((p->p_flag & P_SYSTEM) != 0) {
986 		PROC_UNLOCK(p);
987 		return (0);
988 	}
989 
990 	PROC_UNLOCK(p);
991 
992 	ret = proc_getenvv(td, p, sb);
993 	return (ret);
994 }
995 
996 /*
997  * Filler function for proc/pid/maps
998  */
999 static int
1000 linprocfs_doprocmaps(PFS_FILL_ARGS)
1001 {
1002 	struct vmspace *vm;
1003 	vm_map_t map;
1004 	vm_map_entry_t entry, tmp_entry;
1005 	vm_object_t obj, tobj, lobj;
1006 	vm_offset_t e_start, e_end;
1007 	vm_ooffset_t off = 0;
1008 	vm_prot_t e_prot;
1009 	unsigned int last_timestamp;
1010 	char *name = "", *freename = NULL;
1011 	ino_t ino;
1012 	int ref_count, shadow_count, flags;
1013 	int error;
1014 	struct vnode *vp;
1015 	struct vattr vat;
1016 
1017 	PROC_LOCK(p);
1018 	error = p_candebug(td, p);
1019 	PROC_UNLOCK(p);
1020 	if (error)
1021 		return (error);
1022 
1023 	if (uio->uio_rw != UIO_READ)
1024 		return (EOPNOTSUPP);
1025 
1026 	error = 0;
1027 	vm = vmspace_acquire_ref(p);
1028 	if (vm == NULL)
1029 		return (ESRCH);
1030 	map = &vm->vm_map;
1031 	vm_map_lock_read(map);
1032 	for (entry = map->header.next; entry != &map->header;
1033 	    entry = entry->next) {
1034 		name = "";
1035 		freename = NULL;
1036 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1037 			continue;
1038 		e_prot = entry->protection;
1039 		e_start = entry->start;
1040 		e_end = entry->end;
1041 		obj = entry->object.vm_object;
1042 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1043 			VM_OBJECT_RLOCK(tobj);
1044 			if (lobj != obj)
1045 				VM_OBJECT_RUNLOCK(lobj);
1046 			lobj = tobj;
1047 		}
1048 		last_timestamp = map->timestamp;
1049 		vm_map_unlock_read(map);
1050 		ino = 0;
1051 		if (lobj) {
1052 			off = IDX_TO_OFF(lobj->size);
1053 			if (lobj->type == OBJT_VNODE) {
1054 				vp = lobj->handle;
1055 				if (vp)
1056 					vref(vp);
1057 			}
1058 			else
1059 				vp = NULL;
1060 			if (lobj != obj)
1061 				VM_OBJECT_RUNLOCK(lobj);
1062 			flags = obj->flags;
1063 			ref_count = obj->ref_count;
1064 			shadow_count = obj->shadow_count;
1065 			VM_OBJECT_RUNLOCK(obj);
1066 			if (vp) {
1067 				vn_fullpath(td, vp, &name, &freename);
1068 				vn_lock(vp, LK_SHARED | LK_RETRY);
1069 				VOP_GETATTR(vp, &vat, td->td_ucred);
1070 				ino = vat.va_fileid;
1071 				vput(vp);
1072 			}
1073 		} else {
1074 			flags = 0;
1075 			ref_count = 0;
1076 			shadow_count = 0;
1077 		}
1078 
1079 		/*
1080 		 * format:
1081 		 *  start, end, access, offset, major, minor, inode, name.
1082 		 */
1083 		error = sbuf_printf(sb,
1084 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1085 		    (u_long)e_start, (u_long)e_end,
1086 		    (e_prot & VM_PROT_READ)?"r":"-",
1087 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1088 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1089 		    "p",
1090 		    (u_long)off,
1091 		    0,
1092 		    0,
1093 		    (u_long)ino,
1094 		    *name ? "     " : "",
1095 		    name
1096 		    );
1097 		if (freename)
1098 			free(freename, M_TEMP);
1099 		vm_map_lock_read(map);
1100 		if (error == -1) {
1101 			error = 0;
1102 			break;
1103 		}
1104 		if (last_timestamp != map->timestamp) {
1105 			/*
1106 			 * Look again for the entry because the map was
1107 			 * modified while it was unlocked.  Specifically,
1108 			 * the entry may have been clipped, merged, or deleted.
1109 			 */
1110 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1111 			entry = tmp_entry;
1112 		}
1113 	}
1114 	vm_map_unlock_read(map);
1115 	vmspace_free(vm);
1116 
1117 	return (error);
1118 }
1119 
1120 /*
1121  * Filler function for proc/net/dev
1122  */
1123 static int
1124 linprocfs_donetdev(PFS_FILL_ARGS)
1125 {
1126 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1127 	struct ifnet *ifp;
1128 
1129 	sbuf_printf(sb, "%6s|%58s|%s\n"
1130 	    "%6s|%58s|%58s\n",
1131 	    "Inter-", "   Receive", "  Transmit",
1132 	    " face",
1133 	    "bytes    packets errs drop fifo frame compressed multicast",
1134 	    "bytes    packets errs drop fifo colls carrier compressed");
1135 
1136 	CURVNET_SET(TD_TO_VNET(curthread));
1137 	IFNET_RLOCK();
1138 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1139 		linux_ifname(ifp, ifname, sizeof ifname);
1140 		sbuf_printf(sb, "%6.6s: ", ifname);
1141 		sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1142 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1143 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1144 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1145 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1146 							/* rx_missed_errors */
1147 		    0UL,				/* rx_fifo_errors */
1148 		    0UL,				/* rx_length_errors +
1149 							 * rx_over_errors +
1150 							 * rx_crc_errors +
1151 							 * rx_frame_errors */
1152 		    0UL,				/* rx_compressed */
1153 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1154 							/* XXX-BZ rx only? */
1155 		sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1156 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1157 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1158 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1159 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1160 		    0UL,				/* tx_fifo_errors */
1161 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1162 		    0UL,				/* tx_carrier_errors +
1163 							 * tx_aborted_errors +
1164 							 * tx_window_errors +
1165 							 * tx_heartbeat_errors*/
1166 		    0UL);				/* tx_compressed */
1167 	}
1168 	IFNET_RUNLOCK();
1169 	CURVNET_RESTORE();
1170 
1171 	return (0);
1172 }
1173 
1174 /*
1175  * Filler function for proc/sys/kernel/osrelease
1176  */
1177 static int
1178 linprocfs_doosrelease(PFS_FILL_ARGS)
1179 {
1180 	char osrelease[LINUX_MAX_UTSNAME];
1181 
1182 	linux_get_osrelease(td, osrelease);
1183 	sbuf_printf(sb, "%s\n", osrelease);
1184 
1185 	return (0);
1186 }
1187 
1188 /*
1189  * Filler function for proc/sys/kernel/ostype
1190  */
1191 static int
1192 linprocfs_doostype(PFS_FILL_ARGS)
1193 {
1194 	char osname[LINUX_MAX_UTSNAME];
1195 
1196 	linux_get_osname(td, osname);
1197 	sbuf_printf(sb, "%s\n", osname);
1198 
1199 	return (0);
1200 }
1201 
1202 /*
1203  * Filler function for proc/sys/kernel/version
1204  */
1205 static int
1206 linprocfs_doosbuild(PFS_FILL_ARGS)
1207 {
1208 
1209 	linprocfs_osbuild(td, sb);
1210 	sbuf_cat(sb, "\n");
1211 	return (0);
1212 }
1213 
1214 /*
1215  * Filler function for proc/sys/kernel/msgmni
1216  */
1217 static int
1218 linprocfs_domsgmni(PFS_FILL_ARGS)
1219 {
1220 
1221 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1222 	return (0);
1223 }
1224 
1225 /*
1226  * Filler function for proc/sys/kernel/pid_max
1227  */
1228 static int
1229 linprocfs_dopid_max(PFS_FILL_ARGS)
1230 {
1231 
1232 	sbuf_printf(sb, "%i\n", PID_MAX);
1233 	return (0);
1234 }
1235 
1236 /*
1237  * Filler function for proc/sys/kernel/sem
1238  */
1239 static int
1240 linprocfs_dosem(PFS_FILL_ARGS)
1241 {
1242 
1243 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1244 	    seminfo.semopm, seminfo.semmni);
1245 	return (0);
1246 }
1247 
1248 /*
1249  * Filler function for proc/scsi/device_info
1250  */
1251 static int
1252 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1253 {
1254 
1255 	return (0);
1256 }
1257 
1258 /*
1259  * Filler function for proc/scsi/scsi
1260  */
1261 static int
1262 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1263 {
1264 
1265 	return (0);
1266 }
1267 
1268 extern struct cdevsw *cdevsw[];
1269 
1270 /*
1271  * Filler function for proc/devices
1272  */
1273 static int
1274 linprocfs_dodevices(PFS_FILL_ARGS)
1275 {
1276 	char *char_devices;
1277 	sbuf_printf(sb, "Character devices:\n");
1278 
1279 	char_devices = linux_get_char_devices();
1280 	sbuf_printf(sb, "%s", char_devices);
1281 	linux_free_get_char_devices(char_devices);
1282 
1283 	sbuf_printf(sb, "\nBlock devices:\n");
1284 
1285 	return (0);
1286 }
1287 
1288 /*
1289  * Filler function for proc/cmdline
1290  */
1291 static int
1292 linprocfs_docmdline(PFS_FILL_ARGS)
1293 {
1294 
1295 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1296 	sbuf_printf(sb, " ro root=302\n");
1297 	return (0);
1298 }
1299 
1300 /*
1301  * Filler function for proc/filesystems
1302  */
1303 static int
1304 linprocfs_dofilesystems(PFS_FILL_ARGS)
1305 {
1306 	struct vfsconf *vfsp;
1307 
1308 	mtx_lock(&Giant);
1309 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1310 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1311 			sbuf_printf(sb, "nodev");
1312 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1313 	}
1314 	mtx_unlock(&Giant);
1315 	return(0);
1316 }
1317 
1318 #if 0
1319 /*
1320  * Filler function for proc/modules
1321  */
1322 static int
1323 linprocfs_domodules(PFS_FILL_ARGS)
1324 {
1325 	struct linker_file *lf;
1326 
1327 	TAILQ_FOREACH(lf, &linker_files, link) {
1328 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1329 		    (unsigned long)lf->size, lf->refs);
1330 	}
1331 	return (0);
1332 }
1333 #endif
1334 
1335 /*
1336  * Filler function for proc/pid/fd
1337  */
1338 static int
1339 linprocfs_dofdescfs(PFS_FILL_ARGS)
1340 {
1341 
1342 	if (p == curproc)
1343 		sbuf_printf(sb, "/dev/fd");
1344 	else
1345 		sbuf_printf(sb, "unknown");
1346 	return (0);
1347 }
1348 
1349 
1350 /*
1351  * Filler function for proc/sys/kernel/random/uuid
1352  */
1353 static int
1354 linprocfs_douuid(PFS_FILL_ARGS)
1355 {
1356 	struct uuid uuid;
1357 
1358 	kern_uuidgen(&uuid, 1);
1359 	sbuf_printf_uuid(sb, &uuid);
1360 	sbuf_printf(sb, "\n");
1361 	return(0);
1362 }
1363 
1364 
1365 /*
1366  * Constructor
1367  */
1368 static int
1369 linprocfs_init(PFS_INIT_ARGS)
1370 {
1371 	struct pfs_node *root;
1372 	struct pfs_node *dir;
1373 
1374 	root = pi->pi_root;
1375 
1376 	/* /proc/... */
1377 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1378 	    NULL, NULL, NULL, PFS_RD);
1379 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1380 	    NULL, NULL, NULL, PFS_RD);
1381 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1382 	    NULL, NULL, NULL, PFS_RD);
1383 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1384 	    NULL, NULL, NULL, PFS_RD);
1385 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1386 	    NULL, NULL, NULL, PFS_RD);
1387 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1388 	    NULL, NULL, NULL, PFS_RD);
1389 #if 0
1390 	pfs_create_file(root, "modules", &linprocfs_domodules,
1391 	    NULL, NULL, NULL, PFS_RD);
1392 #endif
1393 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1394 	    NULL, NULL, NULL, PFS_RD);
1395 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1396 	    NULL, NULL, NULL, PFS_RD);
1397 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1398 	    NULL, NULL, NULL, PFS_RD);
1399 	pfs_create_link(root, "self", &procfs_docurproc,
1400 	    NULL, NULL, NULL, 0);
1401 	pfs_create_file(root, "stat", &linprocfs_dostat,
1402 	    NULL, NULL, NULL, PFS_RD);
1403 	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1404 	    NULL, NULL, NULL, PFS_RD);
1405 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1406 	    NULL, NULL, NULL, PFS_RD);
1407 	pfs_create_file(root, "version", &linprocfs_doversion,
1408 	    NULL, NULL, NULL, PFS_RD);
1409 
1410 	/* /proc/net/... */
1411 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1412 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1413 	    NULL, NULL, NULL, PFS_RD);
1414 
1415 	/* /proc/<pid>/... */
1416 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1417 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1418 	    NULL, NULL, NULL, PFS_RD);
1419 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1420 	    NULL, NULL, NULL, 0);
1421 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1422 	    NULL, NULL, NULL, PFS_RD);
1423 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1424 	    NULL, &procfs_notsystem, NULL, 0);
1425 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1426 	    NULL, NULL, NULL, PFS_RD);
1427 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1428 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1429 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1430 	    NULL, NULL, NULL, 0);
1431 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1432 	    NULL, NULL, NULL, PFS_RD);
1433 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1434 	    NULL, NULL, NULL, PFS_RD);
1435 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1436 	    NULL, NULL, NULL, PFS_RD);
1437 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1438 	    NULL, NULL, NULL, 0);
1439 
1440 	/* /proc/scsi/... */
1441 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1442 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1443 	    NULL, NULL, NULL, PFS_RD);
1444 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1445 	    NULL, NULL, NULL, PFS_RD);
1446 
1447 	/* /proc/sys/... */
1448 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1449 	/* /proc/sys/kernel/... */
1450 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1451 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1452 	    NULL, NULL, NULL, PFS_RD);
1453 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1454 	    NULL, NULL, NULL, PFS_RD);
1455 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1456 	    NULL, NULL, NULL, PFS_RD);
1457 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1458 	    NULL, NULL, NULL, PFS_RD);
1459 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1460 	    NULL, NULL, NULL, PFS_RD);
1461 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1462 	    NULL, NULL, NULL, PFS_RD);
1463 
1464 	/* /proc/sys/kernel/random/... */
1465 	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1466 	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1467 	    NULL, NULL, NULL, PFS_RD);
1468 
1469 	return (0);
1470 }
1471 
1472 /*
1473  * Destructor
1474  */
1475 static int
1476 linprocfs_uninit(PFS_INIT_ARGS)
1477 {
1478 
1479 	/* nothing to do, pseudofs will GC */
1480 	return (0);
1481 }
1482 
1483 PSEUDOFS(linprocfs, 1, 0);
1484 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1485 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1486 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1487 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1488