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