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