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