xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision acc1a9ef)
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 	int i;
451 
452 	read_cpu_time(cp_time);
453 	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
454 	    T2J(cp_time[CP_USER]),
455 	    T2J(cp_time[CP_NICE]),
456 	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
457 	    T2J(cp_time[CP_IDLE]));
458 	CPU_FOREACH(i) {
459 		pcpu = pcpu_find(i);
460 		cp = pcpu->pc_cp_time;
461 		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
462 		    T2J(cp[CP_USER]),
463 		    T2J(cp[CP_NICE]),
464 		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
465 		    T2J(cp[CP_IDLE]));
466 	}
467 	sbuf_printf(sb,
468 	    "disk 0 0 0 0\n"
469 	    "page %u %u\n"
470 	    "swap %u %u\n"
471 	    "intr %u\n"
472 	    "ctxt %u\n"
473 	    "btime %lld\n",
474 	    vm_cnt.v_vnodepgsin,
475 	    vm_cnt.v_vnodepgsout,
476 	    vm_cnt.v_swappgsin,
477 	    vm_cnt.v_swappgsout,
478 	    vm_cnt.v_intr,
479 	    vm_cnt.v_swtch,
480 	    (long long)boottime.tv_sec);
481 	return (0);
482 }
483 
484 static int
485 linprocfs_doswaps(PFS_FILL_ARGS)
486 {
487 	struct xswdev xsw;
488 	uintmax_t total, used;
489 	int n;
490 	char devname[SPECNAMELEN + 1];
491 
492 	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
493 	mtx_lock(&Giant);
494 	for (n = 0; ; n++) {
495 		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
496 			break;
497 		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
498 		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
499 
500 		/*
501 		 * The space and not tab after the device name is on
502 		 * purpose.  Linux does so.
503 		 */
504 		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
505 		    devname, total, used);
506 	}
507 	mtx_unlock(&Giant);
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 	char state;
630 	static int ratelimit = 0;
631 	vm_offset_t startcode, startdata;
632 
633 	sx_slock(&proctree_lock);
634 	PROC_LOCK(p);
635 	fill_kinfo_proc(p, &kp);
636 	sx_sunlock(&proctree_lock);
637 	if (p->p_vmspace) {
638 	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
639 	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
640 	} else {
641 	   startcode = 0;
642 	   startdata = 0;
643 	};
644 	sbuf_printf(sb, "%d", p->p_pid);
645 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
646 	PS_ADD("comm",		"(%s)",	p->p_comm);
647 	if (kp.ki_stat > sizeof(linux_state)) {
648 		state = 'R';
649 
650 		if (ratelimit == 0) {
651 			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
652 			    kp.ki_stat, sizeof(linux_state));
653 			++ratelimit;
654 		}
655 	} else
656 		state = linux_state[kp.ki_stat - 1];
657 	PS_ADD("state",		"%c",	state);
658 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
659 	PS_ADD("pgrp",		"%d",	p->p_pgid);
660 	PS_ADD("session",	"%d",	p->p_session->s_sid);
661 	PROC_UNLOCK(p);
662 	PS_ADD("tty",		"%ju",	(uintmax_t)kp.ki_tdev);
663 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
664 	PS_ADD("flags",		"%u",	0); /* XXX */
665 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
666 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
667 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
668 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
669 	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
670 	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
671 	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
672 	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
673 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
674 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
675 	PS_ADD("0",		"%d",	0); /* removed field */
676 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
677 	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
678 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
679 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
680 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
681 	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
682 	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
683 	PS_ADD("startstack",	"%u",	0); /* XXX */
684 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
685 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
686 	PS_ADD("signal",	"%u",	0); /* XXX */
687 	PS_ADD("blocked",	"%u",	0); /* XXX */
688 	PS_ADD("sigignore",	"%u",	0); /* XXX */
689 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
690 	PS_ADD("wchan",		"%u",	0); /* XXX */
691 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
692 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
693 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
694 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
695 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
696 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
697 #undef PS_ADD
698 	sbuf_putc(sb, '\n');
699 
700 	return (0);
701 }
702 
703 /*
704  * Filler function for proc/pid/statm
705  */
706 static int
707 linprocfs_doprocstatm(PFS_FILL_ARGS)
708 {
709 	struct kinfo_proc kp;
710 	segsz_t lsize;
711 
712 	sx_slock(&proctree_lock);
713 	PROC_LOCK(p);
714 	fill_kinfo_proc(p, &kp);
715 	PROC_UNLOCK(p);
716 	sx_sunlock(&proctree_lock);
717 
718 	/*
719 	 * See comments in linprocfs_doprocstatus() regarding the
720 	 * computation of lsize.
721 	 */
722 	/* size resident share trs drs lrs dt */
723 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
724 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
725 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
726 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
727 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
728 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
729 	    kp.ki_ssize - kp.ki_tsize - 1;
730 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
731 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
732 
733 	return (0);
734 }
735 
736 /*
737  * Filler function for proc/pid/status
738  */
739 static int
740 linprocfs_doprocstatus(PFS_FILL_ARGS)
741 {
742 	struct kinfo_proc kp;
743 	char *state;
744 	segsz_t lsize;
745 	struct thread *td2;
746 	struct sigacts *ps;
747 	l_sigset_t siglist, sigignore, sigcatch;
748 	int i;
749 
750 	sx_slock(&proctree_lock);
751 	PROC_LOCK(p);
752 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
753 
754 	if (P_SHOULDSTOP(p)) {
755 		state = "T (stopped)";
756 	} else {
757 		switch(p->p_state) {
758 		case PRS_NEW:
759 			state = "I (idle)";
760 			break;
761 		case PRS_NORMAL:
762 			if (p->p_flag & P_WEXIT) {
763 				state = "X (exiting)";
764 				break;
765 			}
766 			switch(td2->td_state) {
767 			case TDS_INHIBITED:
768 				state = "S (sleeping)";
769 				break;
770 			case TDS_RUNQ:
771 			case TDS_RUNNING:
772 				state = "R (running)";
773 				break;
774 			default:
775 				state = "? (unknown)";
776 				break;
777 			}
778 			break;
779 		case PRS_ZOMBIE:
780 			state = "Z (zombie)";
781 			break;
782 		default:
783 			state = "? (unknown)";
784 			break;
785 		}
786 	}
787 
788 	fill_kinfo_proc(p, &kp);
789 	sx_sunlock(&proctree_lock);
790 
791 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
792 	sbuf_printf(sb, "State:\t%s\n",		state);
793 
794 	/*
795 	 * Credentials
796 	 */
797 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
798 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
799 						p->p_pptr->p_pid : 0);
800 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
801 						p->p_ucred->cr_uid,
802 						p->p_ucred->cr_svuid,
803 						/* FreeBSD doesn't have fsuid */
804 						p->p_ucred->cr_uid);
805 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
806 						p->p_ucred->cr_gid,
807 						p->p_ucred->cr_svgid,
808 						/* FreeBSD doesn't have fsgid */
809 						p->p_ucred->cr_gid);
810 	sbuf_cat(sb, "Groups:\t");
811 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
812 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
813 	PROC_UNLOCK(p);
814 	sbuf_putc(sb, '\n');
815 
816 	/*
817 	 * Memory
818 	 *
819 	 * While our approximation of VmLib may not be accurate (I
820 	 * don't know of a simple way to verify it, and I'm not sure
821 	 * it has much meaning anyway), I believe it's good enough.
822 	 *
823 	 * The same code that could (I think) accurately compute VmLib
824 	 * could also compute VmLck, but I don't really care enough to
825 	 * implement it. Submissions are welcome.
826 	 */
827 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
828 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
829 	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
830 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
831 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
832 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
833 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
834 	    kp.ki_ssize - kp.ki_tsize - 1;
835 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
836 
837 	/*
838 	 * Signal masks
839 	 */
840 	PROC_LOCK(p);
841 	bsd_to_linux_sigset(&p->p_siglist, &siglist);
842 	ps = p->p_sigacts;
843 	mtx_lock(&ps->ps_mtx);
844 	bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
845 	bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
846 	mtx_unlock(&ps->ps_mtx);
847 	PROC_UNLOCK(p);
848 
849 	sbuf_printf(sb, "SigPnd:\t%016jx\n",	siglist.__mask);
850 	/*
851 	 * XXX. SigBlk - target thread's signal mask, td_sigmask.
852 	 * To implement SigBlk pseudofs should support proc/tid dir entries.
853 	 */
854 	sbuf_printf(sb, "SigBlk:\t%016x\n",	0);
855 	sbuf_printf(sb, "SigIgn:\t%016jx\n",	sigignore.__mask);
856 	sbuf_printf(sb, "SigCgt:\t%016jx\n",	sigcatch.__mask);
857 
858 	/*
859 	 * Linux also prints the capability masks, but we don't have
860 	 * capabilities yet, and when we do get them they're likely to
861 	 * be meaningless to Linux programs, so we lie. XXX
862 	 */
863 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
864 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
865 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
866 
867 	return (0);
868 }
869 
870 
871 /*
872  * Filler function for proc/pid/cwd
873  */
874 static int
875 linprocfs_doproccwd(PFS_FILL_ARGS)
876 {
877 	struct filedesc *fdp;
878 	struct vnode *vp;
879 	char *fullpath = "unknown";
880 	char *freepath = NULL;
881 
882 	fdp = p->p_fd;
883 	FILEDESC_SLOCK(fdp);
884 	vp = fdp->fd_cdir;
885 	if (vp != NULL)
886 		VREF(vp);
887 	FILEDESC_SUNLOCK(fdp);
888 	vn_fullpath(td, vp, &fullpath, &freepath);
889 	if (vp != NULL)
890 		vrele(vp);
891 	sbuf_printf(sb, "%s", fullpath);
892 	if (freepath)
893 		free(freepath, M_TEMP);
894 	return (0);
895 }
896 
897 /*
898  * Filler function for proc/pid/root
899  */
900 static int
901 linprocfs_doprocroot(PFS_FILL_ARGS)
902 {
903 	struct filedesc *fdp;
904 	struct vnode *vp;
905 	char *fullpath = "unknown";
906 	char *freepath = NULL;
907 
908 	fdp = p->p_fd;
909 	FILEDESC_SLOCK(fdp);
910 	vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
911 	if (vp != NULL)
912 		VREF(vp);
913 	FILEDESC_SUNLOCK(fdp);
914 	vn_fullpath(td, vp, &fullpath, &freepath);
915 	if (vp != NULL)
916 		vrele(vp);
917 	sbuf_printf(sb, "%s", fullpath);
918 	if (freepath)
919 		free(freepath, M_TEMP);
920 	return (0);
921 }
922 
923 /*
924  * Filler function for proc/pid/cmdline
925  */
926 static int
927 linprocfs_doproccmdline(PFS_FILL_ARGS)
928 {
929 	int ret;
930 
931 	PROC_LOCK(p);
932 	if ((ret = p_cansee(td, p)) != 0) {
933 		PROC_UNLOCK(p);
934 		return (ret);
935 	}
936 
937 	/*
938 	 * Mimic linux behavior and pass only processes with usermode
939 	 * address space as valid.  Return zero silently otherwize.
940 	 */
941 	if (p->p_vmspace == &vmspace0) {
942 		PROC_UNLOCK(p);
943 		return (0);
944 	}
945 	if (p->p_args != NULL) {
946 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
947 		PROC_UNLOCK(p);
948 		return (0);
949 	}
950 
951 	if ((p->p_flag & P_SYSTEM) != 0) {
952 		PROC_UNLOCK(p);
953 		return (0);
954 	}
955 
956 	PROC_UNLOCK(p);
957 
958 	ret = proc_getargv(td, p, sb);
959 	return (ret);
960 }
961 
962 /*
963  * Filler function for proc/pid/environ
964  */
965 static int
966 linprocfs_doprocenviron(PFS_FILL_ARGS)
967 {
968 
969 	/*
970 	 * Mimic linux behavior and pass only processes with usermode
971 	 * address space as valid.  Return zero silently otherwize.
972 	 */
973 	if (p->p_vmspace == &vmspace0)
974 		return (0);
975 
976 	return (proc_getenvv(td, p, sb));
977 }
978 
979 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
980 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
981 static char vdso_str[] = "      [vdso]";
982 static char stack_str[] = "      [stack]";
983 
984 /*
985  * Filler function for proc/pid/maps
986  */
987 static int
988 linprocfs_doprocmaps(PFS_FILL_ARGS)
989 {
990 	struct vmspace *vm;
991 	vm_map_t map;
992 	vm_map_entry_t entry, tmp_entry;
993 	vm_object_t obj, tobj, lobj;
994 	vm_offset_t e_start, e_end;
995 	vm_ooffset_t off = 0;
996 	vm_prot_t e_prot;
997 	unsigned int last_timestamp;
998 	char *name = "", *freename = NULL;
999 	const char *l_map_str;
1000 	ino_t ino;
1001 	int ref_count, shadow_count, flags;
1002 	int error;
1003 	struct vnode *vp;
1004 	struct vattr vat;
1005 
1006 	PROC_LOCK(p);
1007 	error = p_candebug(td, p);
1008 	PROC_UNLOCK(p);
1009 	if (error)
1010 		return (error);
1011 
1012 	if (uio->uio_rw != UIO_READ)
1013 		return (EOPNOTSUPP);
1014 
1015 	error = 0;
1016 	vm = vmspace_acquire_ref(p);
1017 	if (vm == NULL)
1018 		return (ESRCH);
1019 
1020 	if (SV_CURPROC_FLAG(SV_LP64))
1021 		l_map_str = l64_map_str;
1022 	else
1023 		l_map_str = l32_map_str;
1024 	map = &vm->vm_map;
1025 	vm_map_lock_read(map);
1026 	for (entry = map->header.next; entry != &map->header;
1027 	    entry = entry->next) {
1028 		name = "";
1029 		freename = NULL;
1030 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1031 			continue;
1032 		e_prot = entry->protection;
1033 		e_start = entry->start;
1034 		e_end = entry->end;
1035 		obj = entry->object.vm_object;
1036 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1037 			VM_OBJECT_RLOCK(tobj);
1038 			if (lobj != obj)
1039 				VM_OBJECT_RUNLOCK(lobj);
1040 			lobj = tobj;
1041 		}
1042 		last_timestamp = map->timestamp;
1043 		vm_map_unlock_read(map);
1044 		ino = 0;
1045 		if (lobj) {
1046 			off = IDX_TO_OFF(lobj->size);
1047 			vp = vm_object_vnode(lobj);
1048 			if (vp != NULL)
1049 				vref(vp);
1050 			if (lobj != obj)
1051 				VM_OBJECT_RUNLOCK(lobj);
1052 			flags = obj->flags;
1053 			ref_count = obj->ref_count;
1054 			shadow_count = obj->shadow_count;
1055 			VM_OBJECT_RUNLOCK(obj);
1056 			if (vp != NULL) {
1057 				vn_fullpath(td, vp, &name, &freename);
1058 				vn_lock(vp, LK_SHARED | LK_RETRY);
1059 				VOP_GETATTR(vp, &vat, td->td_ucred);
1060 				ino = vat.va_fileid;
1061 				vput(vp);
1062 			} else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1063 				if (e_start == p->p_sysent->sv_shared_page_base)
1064 					name = vdso_str;
1065 				if (e_end == p->p_sysent->sv_usrstack)
1066 					name = stack_str;
1067 			}
1068 		} else {
1069 			flags = 0;
1070 			ref_count = 0;
1071 			shadow_count = 0;
1072 		}
1073 
1074 		/*
1075 		 * format:
1076 		 *  start, end, access, offset, major, minor, inode, name.
1077 		 */
1078 		error = sbuf_printf(sb, l_map_str,
1079 		    (u_long)e_start, (u_long)e_end,
1080 		    (e_prot & VM_PROT_READ)?"r":"-",
1081 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1082 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1083 		    "p",
1084 		    (u_long)off,
1085 		    0,
1086 		    0,
1087 		    (u_long)ino,
1088 		    *name ? "     " : "",
1089 		    name
1090 		    );
1091 		if (freename)
1092 			free(freename, M_TEMP);
1093 		vm_map_lock_read(map);
1094 		if (error == -1) {
1095 			error = 0;
1096 			break;
1097 		}
1098 		if (last_timestamp != map->timestamp) {
1099 			/*
1100 			 * Look again for the entry because the map was
1101 			 * modified while it was unlocked.  Specifically,
1102 			 * the entry may have been clipped, merged, or deleted.
1103 			 */
1104 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1105 			entry = tmp_entry;
1106 		}
1107 	}
1108 	vm_map_unlock_read(map);
1109 	vmspace_free(vm);
1110 
1111 	return (error);
1112 }
1113 
1114 /*
1115  * Criteria for interface name translation
1116  */
1117 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1118 
1119 static int
1120 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1121 {
1122 	struct ifnet *ifscan;
1123 	int ethno;
1124 
1125 	IFNET_RLOCK_ASSERT();
1126 
1127 	/* Short-circuit non ethernet interfaces */
1128 	if (!IFP_IS_ETH(ifp))
1129 		return (strlcpy(buffer, ifp->if_xname, buflen));
1130 
1131 	/* Determine the (relative) unit number for ethernet interfaces */
1132 	ethno = 0;
1133 	TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1134 		if (ifscan == ifp)
1135 			return (snprintf(buffer, buflen, "eth%d", ethno));
1136 		if (IFP_IS_ETH(ifscan))
1137 			ethno++;
1138 	}
1139 
1140 	return (0);
1141 }
1142 
1143 /*
1144  * Filler function for proc/net/dev
1145  */
1146 static int
1147 linprocfs_donetdev(PFS_FILL_ARGS)
1148 {
1149 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1150 	struct ifnet *ifp;
1151 
1152 	sbuf_printf(sb, "%6s|%58s|%s\n"
1153 	    "%6s|%58s|%58s\n",
1154 	    "Inter-", "   Receive", "  Transmit",
1155 	    " face",
1156 	    "bytes    packets errs drop fifo frame compressed multicast",
1157 	    "bytes    packets errs drop fifo colls carrier compressed");
1158 
1159 	CURVNET_SET(TD_TO_VNET(curthread));
1160 	IFNET_RLOCK();
1161 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1162 		linux_ifname(ifp, ifname, sizeof ifname);
1163 		sbuf_printf(sb, "%6.6s: ", ifname);
1164 		sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1165 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1166 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1167 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1168 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1169 							/* rx_missed_errors */
1170 		    0UL,				/* rx_fifo_errors */
1171 		    0UL,				/* rx_length_errors +
1172 							 * rx_over_errors +
1173 							 * rx_crc_errors +
1174 							 * rx_frame_errors */
1175 		    0UL,				/* rx_compressed */
1176 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1177 							/* XXX-BZ rx only? */
1178 		sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1179 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1180 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1181 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1182 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1183 		    0UL,				/* tx_fifo_errors */
1184 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1185 		    0UL,				/* tx_carrier_errors +
1186 							 * tx_aborted_errors +
1187 							 * tx_window_errors +
1188 							 * tx_heartbeat_errors*/
1189 		    0UL);				/* tx_compressed */
1190 	}
1191 	IFNET_RUNLOCK();
1192 	CURVNET_RESTORE();
1193 
1194 	return (0);
1195 }
1196 
1197 /*
1198  * Filler function for proc/sys/kernel/osrelease
1199  */
1200 static int
1201 linprocfs_doosrelease(PFS_FILL_ARGS)
1202 {
1203 	char osrelease[LINUX_MAX_UTSNAME];
1204 
1205 	linux_get_osrelease(td, osrelease);
1206 	sbuf_printf(sb, "%s\n", osrelease);
1207 
1208 	return (0);
1209 }
1210 
1211 /*
1212  * Filler function for proc/sys/kernel/ostype
1213  */
1214 static int
1215 linprocfs_doostype(PFS_FILL_ARGS)
1216 {
1217 	char osname[LINUX_MAX_UTSNAME];
1218 
1219 	linux_get_osname(td, osname);
1220 	sbuf_printf(sb, "%s\n", osname);
1221 
1222 	return (0);
1223 }
1224 
1225 /*
1226  * Filler function for proc/sys/kernel/version
1227  */
1228 static int
1229 linprocfs_doosbuild(PFS_FILL_ARGS)
1230 {
1231 
1232 	linprocfs_osbuild(td, sb);
1233 	sbuf_cat(sb, "\n");
1234 	return (0);
1235 }
1236 
1237 /*
1238  * Filler function for proc/sys/kernel/msgmni
1239  */
1240 static int
1241 linprocfs_domsgmni(PFS_FILL_ARGS)
1242 {
1243 
1244 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1245 	return (0);
1246 }
1247 
1248 /*
1249  * Filler function for proc/sys/kernel/pid_max
1250  */
1251 static int
1252 linprocfs_dopid_max(PFS_FILL_ARGS)
1253 {
1254 
1255 	sbuf_printf(sb, "%i\n", PID_MAX);
1256 	return (0);
1257 }
1258 
1259 /*
1260  * Filler function for proc/sys/kernel/sem
1261  */
1262 static int
1263 linprocfs_dosem(PFS_FILL_ARGS)
1264 {
1265 
1266 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1267 	    seminfo.semopm, seminfo.semmni);
1268 	return (0);
1269 }
1270 
1271 /*
1272  * Filler function for proc/scsi/device_info
1273  */
1274 static int
1275 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1276 {
1277 
1278 	return (0);
1279 }
1280 
1281 /*
1282  * Filler function for proc/scsi/scsi
1283  */
1284 static int
1285 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1286 {
1287 
1288 	return (0);
1289 }
1290 
1291 /*
1292  * Filler function for proc/devices
1293  */
1294 static int
1295 linprocfs_dodevices(PFS_FILL_ARGS)
1296 {
1297 	char *char_devices;
1298 	sbuf_printf(sb, "Character devices:\n");
1299 
1300 	char_devices = linux_get_char_devices();
1301 	sbuf_printf(sb, "%s", char_devices);
1302 	linux_free_get_char_devices(char_devices);
1303 
1304 	sbuf_printf(sb, "\nBlock devices:\n");
1305 
1306 	return (0);
1307 }
1308 
1309 /*
1310  * Filler function for proc/cmdline
1311  */
1312 static int
1313 linprocfs_docmdline(PFS_FILL_ARGS)
1314 {
1315 
1316 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1317 	sbuf_printf(sb, " ro root=302\n");
1318 	return (0);
1319 }
1320 
1321 /*
1322  * Filler function for proc/filesystems
1323  */
1324 static int
1325 linprocfs_dofilesystems(PFS_FILL_ARGS)
1326 {
1327 	struct vfsconf *vfsp;
1328 
1329 	mtx_lock(&Giant);
1330 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1331 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1332 			sbuf_printf(sb, "nodev");
1333 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1334 	}
1335 	mtx_unlock(&Giant);
1336 	return(0);
1337 }
1338 
1339 #if 0
1340 /*
1341  * Filler function for proc/modules
1342  */
1343 static int
1344 linprocfs_domodules(PFS_FILL_ARGS)
1345 {
1346 	struct linker_file *lf;
1347 
1348 	TAILQ_FOREACH(lf, &linker_files, link) {
1349 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1350 		    (unsigned long)lf->size, lf->refs);
1351 	}
1352 	return (0);
1353 }
1354 #endif
1355 
1356 /*
1357  * Filler function for proc/pid/fd
1358  */
1359 static int
1360 linprocfs_dofdescfs(PFS_FILL_ARGS)
1361 {
1362 
1363 	if (p == curproc)
1364 		sbuf_printf(sb, "/dev/fd");
1365 	else
1366 		sbuf_printf(sb, "unknown");
1367 	return (0);
1368 }
1369 
1370 /*
1371  * Filler function for proc/pid/limits
1372  */
1373 
1374 #define RLIM_NONE -1
1375 
1376 static const struct limit_info {
1377 	const char	*desc;
1378 	const char	*unit;
1379 	unsigned long long	rlim_id;
1380 } limits_info[] = {
1381 	{ "Max cpu time",		"seconds",	RLIMIT_CPU },
1382 	{ "Max file size",		"bytes",	RLIMIT_FSIZE },
1383 	{ "Max data size",		"bytes", 	RLIMIT_DATA },
1384 	{ "Max stack size",		"bytes", 	RLIMIT_STACK },
1385 	{ "Max core file size",		"bytes",	RLIMIT_CORE },
1386 	{ "Max resident set",		"bytes",	RLIMIT_RSS },
1387 	{ "Max processes",		"processes",	RLIMIT_NPROC },
1388 	{ "Max open files",		"files",	RLIMIT_NOFILE },
1389 	{ "Max locked memory",		"bytes",	RLIMIT_MEMLOCK },
1390 	{ "Max address space",		"bytes",	RLIMIT_AS },
1391 	{ "Max file locks",		"locks",	RLIM_INFINITY },
1392 	{ "Max pending signals",	"signals",	RLIM_INFINITY },
1393 	{ "Max msgqueue size",		"bytes",	RLIM_NONE },
1394 	{ "Max nice priority", 		"",		RLIM_NONE },
1395 	{ "Max realtime priority",	"",		RLIM_NONE },
1396 	{ "Max realtime timeout",	"us",		RLIM_INFINITY },
1397 	{ 0, 0, 0 }
1398 };
1399 
1400 static int
1401 linprocfs_doproclimits(PFS_FILL_ARGS)
1402 {
1403 	const struct limit_info	*li;
1404 	struct rlimit li_rlimits;
1405 	struct plimit *cur_proc_lim;
1406 
1407 	cur_proc_lim = lim_alloc();
1408 	lim_copy(cur_proc_lim, p->p_limit);
1409 	sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n", "Limit", "Soft Limit",
1410 			"Hard Limit", "Units");
1411 	for (li = limits_info; li->desc != NULL; ++li) {
1412 		if (li->rlim_id != RLIM_INFINITY && li->rlim_id != RLIM_NONE)
1413 			li_rlimits = cur_proc_lim->pl_rlimit[li->rlim_id];
1414 		else {
1415 			li_rlimits.rlim_cur = 0;
1416 			li_rlimits.rlim_max = 0;
1417 		}
1418 		if (li->rlim_id == RLIM_INFINITY ||
1419 		    li_rlimits.rlim_cur == RLIM_INFINITY)
1420 			sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1421 			    li->desc, "unlimited", "unlimited", li->unit);
1422 		else
1423 			sbuf_printf(sb, "%-26s%-21ld%-21ld%-10s\n",
1424 			    li->desc, (long)li_rlimits.rlim_cur,
1425 			    (long)li_rlimits.rlim_max, li->unit);
1426 	}
1427 	lim_free(cur_proc_lim);
1428 	return (0);
1429 }
1430 
1431 
1432 /*
1433  * Filler function for proc/sys/kernel/random/uuid
1434  */
1435 static int
1436 linprocfs_douuid(PFS_FILL_ARGS)
1437 {
1438 	struct uuid uuid;
1439 
1440 	kern_uuidgen(&uuid, 1);
1441 	sbuf_printf_uuid(sb, &uuid);
1442 	sbuf_printf(sb, "\n");
1443 	return(0);
1444 }
1445 
1446 /*
1447  * Filler function for proc/pid/auxv
1448  */
1449 static int
1450 linprocfs_doauxv(PFS_FILL_ARGS)
1451 {
1452 	struct sbuf *asb;
1453 	off_t buflen, resid;
1454 	int error;
1455 
1456 	/*
1457 	 * Mimic linux behavior and pass only processes with usermode
1458 	 * address space as valid. Return zero silently otherwise.
1459 	 */
1460 	if (p->p_vmspace == &vmspace0)
1461 		return (0);
1462 
1463 	if (uio->uio_resid == 0)
1464 		return (0);
1465 	if (uio->uio_offset < 0 || uio->uio_resid < 0)
1466 		return (EINVAL);
1467 
1468 	asb = sbuf_new_auto();
1469 	if (asb == NULL)
1470 		return (ENOMEM);
1471 	error = proc_getauxv(td, p, asb);
1472 	if (error == 0)
1473 		error = sbuf_finish(asb);
1474 
1475 	resid = sbuf_len(asb) - uio->uio_offset;
1476 	if (resid > uio->uio_resid)
1477 		buflen = uio->uio_resid;
1478 	else
1479 		buflen = resid;
1480 	if (buflen > IOSIZE_MAX)
1481 		return (EINVAL);
1482 	if (buflen > MAXPHYS)
1483 		buflen = MAXPHYS;
1484 	if (resid <= 0)
1485 		return (0);
1486 
1487 	if (error == 0)
1488 		error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1489 	sbuf_delete(asb);
1490 	return (error);
1491 }
1492 
1493 /*
1494  * Constructor
1495  */
1496 static int
1497 linprocfs_init(PFS_INIT_ARGS)
1498 {
1499 	struct pfs_node *root;
1500 	struct pfs_node *dir;
1501 
1502 	root = pi->pi_root;
1503 
1504 	/* /proc/... */
1505 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1506 	    NULL, NULL, NULL, PFS_RD);
1507 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1508 	    NULL, NULL, NULL, PFS_RD);
1509 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1510 	    NULL, NULL, NULL, PFS_RD);
1511 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1512 	    NULL, NULL, NULL, PFS_RD);
1513 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1514 	    NULL, NULL, NULL, PFS_RD);
1515 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1516 	    NULL, NULL, NULL, PFS_RD);
1517 #if 0
1518 	pfs_create_file(root, "modules", &linprocfs_domodules,
1519 	    NULL, NULL, NULL, PFS_RD);
1520 #endif
1521 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1522 	    NULL, NULL, NULL, PFS_RD);
1523 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1524 	    NULL, NULL, NULL, PFS_RD);
1525 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1526 	    NULL, NULL, NULL, PFS_RD);
1527 	pfs_create_link(root, "self", &procfs_docurproc,
1528 	    NULL, NULL, NULL, 0);
1529 	pfs_create_file(root, "stat", &linprocfs_dostat,
1530 	    NULL, NULL, NULL, PFS_RD);
1531 	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1532 	    NULL, NULL, NULL, PFS_RD);
1533 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1534 	    NULL, NULL, NULL, PFS_RD);
1535 	pfs_create_file(root, "version", &linprocfs_doversion,
1536 	    NULL, NULL, NULL, PFS_RD);
1537 
1538 	/* /proc/net/... */
1539 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1540 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1541 	    NULL, NULL, NULL, PFS_RD);
1542 
1543 	/* /proc/<pid>/... */
1544 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1545 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1546 	    NULL, NULL, NULL, PFS_RD);
1547 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1548 	    NULL, NULL, NULL, 0);
1549 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1550 	    NULL, &procfs_candebug, NULL, PFS_RD);
1551 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1552 	    NULL, &procfs_notsystem, NULL, 0);
1553 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1554 	    NULL, NULL, NULL, PFS_RD);
1555 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1556 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1557 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1558 	    NULL, NULL, NULL, 0);
1559 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1560 	    NULL, NULL, NULL, PFS_RD);
1561 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1562 	    NULL, NULL, NULL, PFS_RD);
1563 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1564 	    NULL, NULL, NULL, PFS_RD);
1565 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1566 	    NULL, NULL, NULL, 0);
1567 	pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1568 	    NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1569 	pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1570 	    NULL, NULL, NULL, PFS_RD);
1571 
1572 	/* /proc/scsi/... */
1573 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1574 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1575 	    NULL, NULL, NULL, PFS_RD);
1576 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1577 	    NULL, NULL, NULL, PFS_RD);
1578 
1579 	/* /proc/sys/... */
1580 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1581 	/* /proc/sys/kernel/... */
1582 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1583 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1584 	    NULL, NULL, NULL, PFS_RD);
1585 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1586 	    NULL, NULL, NULL, PFS_RD);
1587 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1588 	    NULL, NULL, NULL, PFS_RD);
1589 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1590 	    NULL, NULL, NULL, PFS_RD);
1591 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1592 	    NULL, NULL, NULL, PFS_RD);
1593 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1594 	    NULL, NULL, NULL, PFS_RD);
1595 
1596 	/* /proc/sys/kernel/random/... */
1597 	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1598 	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1599 	    NULL, NULL, NULL, PFS_RD);
1600 
1601 	return (0);
1602 }
1603 
1604 /*
1605  * Destructor
1606  */
1607 static int
1608 linprocfs_uninit(PFS_INIT_ARGS)
1609 {
1610 
1611 	/* nothing to do, pseudofs will GC */
1612 	return (0);
1613 }
1614 
1615 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1616 #if defined(__amd64__)
1617 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1618 #else
1619 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1620 #endif
1621 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1622 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1623 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1624