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