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