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