xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision dcc0e6c49352e89a864ba8a8f54a498ccb3b54a8)
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 
950 	/*
951 	 * Mimic linux behavior and pass only processes with usermode
952 	 * address space as valid.  Return zero silently otherwize.
953 	 */
954 	if (p->p_vmspace == &vmspace0)
955 		return (0);
956 
957 	return (proc_getenvv(td, p, sb));
958 }
959 
960 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
961 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
962 static char vdso_str[] = "      [vdso]";
963 static char stack_str[] = "      [stack]";
964 
965 /*
966  * Filler function for proc/pid/maps
967  */
968 static int
969 linprocfs_doprocmaps(PFS_FILL_ARGS)
970 {
971 	struct vmspace *vm;
972 	vm_map_t map;
973 	vm_map_entry_t entry, tmp_entry;
974 	vm_object_t obj, tobj, lobj;
975 	vm_offset_t e_start, e_end;
976 	vm_ooffset_t off = 0;
977 	vm_prot_t e_prot;
978 	unsigned int last_timestamp;
979 	char *name = "", *freename = NULL;
980 	const char *l_map_str;
981 	ino_t ino;
982 	int ref_count, shadow_count, flags;
983 	int error;
984 	struct vnode *vp;
985 	struct vattr vat;
986 
987 	PROC_LOCK(p);
988 	error = p_candebug(td, p);
989 	PROC_UNLOCK(p);
990 	if (error)
991 		return (error);
992 
993 	if (uio->uio_rw != UIO_READ)
994 		return (EOPNOTSUPP);
995 
996 	error = 0;
997 	vm = vmspace_acquire_ref(p);
998 	if (vm == NULL)
999 		return (ESRCH);
1000 
1001 	if (SV_CURPROC_FLAG(SV_LP64))
1002 		l_map_str = l64_map_str;
1003 	else
1004 		l_map_str = l32_map_str;
1005 	map = &vm->vm_map;
1006 	vm_map_lock_read(map);
1007 	for (entry = map->header.next; entry != &map->header;
1008 	    entry = entry->next) {
1009 		name = "";
1010 		freename = NULL;
1011 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1012 			continue;
1013 		e_prot = entry->protection;
1014 		e_start = entry->start;
1015 		e_end = entry->end;
1016 		obj = entry->object.vm_object;
1017 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1018 			VM_OBJECT_RLOCK(tobj);
1019 			if (lobj != obj)
1020 				VM_OBJECT_RUNLOCK(lobj);
1021 			lobj = tobj;
1022 		}
1023 		last_timestamp = map->timestamp;
1024 		vm_map_unlock_read(map);
1025 		ino = 0;
1026 		if (lobj) {
1027 			off = IDX_TO_OFF(lobj->size);
1028 			if (lobj->type == OBJT_VNODE) {
1029 				vp = lobj->handle;
1030 				if (vp)
1031 					vref(vp);
1032 			}
1033 			else
1034 				vp = NULL;
1035 			if (lobj != obj)
1036 				VM_OBJECT_RUNLOCK(lobj);
1037 			flags = obj->flags;
1038 			ref_count = obj->ref_count;
1039 			shadow_count = obj->shadow_count;
1040 			VM_OBJECT_RUNLOCK(obj);
1041 			if (vp) {
1042 				vn_fullpath(td, vp, &name, &freename);
1043 				vn_lock(vp, LK_SHARED | LK_RETRY);
1044 				VOP_GETATTR(vp, &vat, td->td_ucred);
1045 				ino = vat.va_fileid;
1046 				vput(vp);
1047 			} else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1048 				if (e_start == p->p_sysent->sv_shared_page_base)
1049 					name = vdso_str;
1050 				if (e_end == p->p_sysent->sv_usrstack)
1051 					name = stack_str;
1052 			}
1053 		} else {
1054 			flags = 0;
1055 			ref_count = 0;
1056 			shadow_count = 0;
1057 		}
1058 
1059 		/*
1060 		 * format:
1061 		 *  start, end, access, offset, major, minor, inode, name.
1062 		 */
1063 		error = sbuf_printf(sb, l_map_str,
1064 		    (u_long)e_start, (u_long)e_end,
1065 		    (e_prot & VM_PROT_READ)?"r":"-",
1066 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1067 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1068 		    "p",
1069 		    (u_long)off,
1070 		    0,
1071 		    0,
1072 		    (u_long)ino,
1073 		    *name ? "     " : "",
1074 		    name
1075 		    );
1076 		if (freename)
1077 			free(freename, M_TEMP);
1078 		vm_map_lock_read(map);
1079 		if (error == -1) {
1080 			error = 0;
1081 			break;
1082 		}
1083 		if (last_timestamp != map->timestamp) {
1084 			/*
1085 			 * Look again for the entry because the map was
1086 			 * modified while it was unlocked.  Specifically,
1087 			 * the entry may have been clipped, merged, or deleted.
1088 			 */
1089 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1090 			entry = tmp_entry;
1091 		}
1092 	}
1093 	vm_map_unlock_read(map);
1094 	vmspace_free(vm);
1095 
1096 	return (error);
1097 }
1098 
1099 /*
1100  * Criteria for interface name translation
1101  */
1102 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1103 
1104 static int
1105 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1106 {
1107 	struct ifnet *ifscan;
1108 	int ethno;
1109 
1110 	IFNET_RLOCK_ASSERT();
1111 
1112 	/* Short-circuit non ethernet interfaces */
1113 	if (!IFP_IS_ETH(ifp))
1114 		return (strlcpy(buffer, ifp->if_xname, buflen));
1115 
1116 	/* Determine the (relative) unit number for ethernet interfaces */
1117 	ethno = 0;
1118 	TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1119 		if (ifscan == ifp)
1120 			return (snprintf(buffer, buflen, "eth%d", ethno));
1121 		if (IFP_IS_ETH(ifscan))
1122 			ethno++;
1123 	}
1124 
1125 	return (0);
1126 }
1127 
1128 /*
1129  * Filler function for proc/net/dev
1130  */
1131 static int
1132 linprocfs_donetdev(PFS_FILL_ARGS)
1133 {
1134 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1135 	struct ifnet *ifp;
1136 
1137 	sbuf_printf(sb, "%6s|%58s|%s\n"
1138 	    "%6s|%58s|%58s\n",
1139 	    "Inter-", "   Receive", "  Transmit",
1140 	    " face",
1141 	    "bytes    packets errs drop fifo frame compressed multicast",
1142 	    "bytes    packets errs drop fifo colls carrier compressed");
1143 
1144 	CURVNET_SET(TD_TO_VNET(curthread));
1145 	IFNET_RLOCK();
1146 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1147 		linux_ifname(ifp, ifname, sizeof ifname);
1148 		sbuf_printf(sb, "%6.6s: ", ifname);
1149 		sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1150 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1151 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1152 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1153 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1154 							/* rx_missed_errors */
1155 		    0UL,				/* rx_fifo_errors */
1156 		    0UL,				/* rx_length_errors +
1157 							 * rx_over_errors +
1158 							 * rx_crc_errors +
1159 							 * rx_frame_errors */
1160 		    0UL,				/* rx_compressed */
1161 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1162 							/* XXX-BZ rx only? */
1163 		sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1164 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1165 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1166 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1167 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1168 		    0UL,				/* tx_fifo_errors */
1169 		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1170 		    0UL,				/* tx_carrier_errors +
1171 							 * tx_aborted_errors +
1172 							 * tx_window_errors +
1173 							 * tx_heartbeat_errors*/
1174 		    0UL);				/* tx_compressed */
1175 	}
1176 	IFNET_RUNLOCK();
1177 	CURVNET_RESTORE();
1178 
1179 	return (0);
1180 }
1181 
1182 /*
1183  * Filler function for proc/sys/kernel/osrelease
1184  */
1185 static int
1186 linprocfs_doosrelease(PFS_FILL_ARGS)
1187 {
1188 	char osrelease[LINUX_MAX_UTSNAME];
1189 
1190 	linux_get_osrelease(td, osrelease);
1191 	sbuf_printf(sb, "%s\n", osrelease);
1192 
1193 	return (0);
1194 }
1195 
1196 /*
1197  * Filler function for proc/sys/kernel/ostype
1198  */
1199 static int
1200 linprocfs_doostype(PFS_FILL_ARGS)
1201 {
1202 	char osname[LINUX_MAX_UTSNAME];
1203 
1204 	linux_get_osname(td, osname);
1205 	sbuf_printf(sb, "%s\n", osname);
1206 
1207 	return (0);
1208 }
1209 
1210 /*
1211  * Filler function for proc/sys/kernel/version
1212  */
1213 static int
1214 linprocfs_doosbuild(PFS_FILL_ARGS)
1215 {
1216 
1217 	linprocfs_osbuild(td, sb);
1218 	sbuf_cat(sb, "\n");
1219 	return (0);
1220 }
1221 
1222 /*
1223  * Filler function for proc/sys/kernel/msgmni
1224  */
1225 static int
1226 linprocfs_domsgmni(PFS_FILL_ARGS)
1227 {
1228 
1229 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1230 	return (0);
1231 }
1232 
1233 /*
1234  * Filler function for proc/sys/kernel/pid_max
1235  */
1236 static int
1237 linprocfs_dopid_max(PFS_FILL_ARGS)
1238 {
1239 
1240 	sbuf_printf(sb, "%i\n", PID_MAX);
1241 	return (0);
1242 }
1243 
1244 /*
1245  * Filler function for proc/sys/kernel/sem
1246  */
1247 static int
1248 linprocfs_dosem(PFS_FILL_ARGS)
1249 {
1250 
1251 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1252 	    seminfo.semopm, seminfo.semmni);
1253 	return (0);
1254 }
1255 
1256 /*
1257  * Filler function for proc/scsi/device_info
1258  */
1259 static int
1260 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1261 {
1262 
1263 	return (0);
1264 }
1265 
1266 /*
1267  * Filler function for proc/scsi/scsi
1268  */
1269 static int
1270 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1271 {
1272 
1273 	return (0);
1274 }
1275 
1276 /*
1277  * Filler function for proc/devices
1278  */
1279 static int
1280 linprocfs_dodevices(PFS_FILL_ARGS)
1281 {
1282 	char *char_devices;
1283 	sbuf_printf(sb, "Character devices:\n");
1284 
1285 	char_devices = linux_get_char_devices();
1286 	sbuf_printf(sb, "%s", char_devices);
1287 	linux_free_get_char_devices(char_devices);
1288 
1289 	sbuf_printf(sb, "\nBlock devices:\n");
1290 
1291 	return (0);
1292 }
1293 
1294 /*
1295  * Filler function for proc/cmdline
1296  */
1297 static int
1298 linprocfs_docmdline(PFS_FILL_ARGS)
1299 {
1300 
1301 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1302 	sbuf_printf(sb, " ro root=302\n");
1303 	return (0);
1304 }
1305 
1306 /*
1307  * Filler function for proc/filesystems
1308  */
1309 static int
1310 linprocfs_dofilesystems(PFS_FILL_ARGS)
1311 {
1312 	struct vfsconf *vfsp;
1313 
1314 	mtx_lock(&Giant);
1315 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1316 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1317 			sbuf_printf(sb, "nodev");
1318 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1319 	}
1320 	mtx_unlock(&Giant);
1321 	return(0);
1322 }
1323 
1324 #if 0
1325 /*
1326  * Filler function for proc/modules
1327  */
1328 static int
1329 linprocfs_domodules(PFS_FILL_ARGS)
1330 {
1331 	struct linker_file *lf;
1332 
1333 	TAILQ_FOREACH(lf, &linker_files, link) {
1334 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1335 		    (unsigned long)lf->size, lf->refs);
1336 	}
1337 	return (0);
1338 }
1339 #endif
1340 
1341 /*
1342  * Filler function for proc/pid/fd
1343  */
1344 static int
1345 linprocfs_dofdescfs(PFS_FILL_ARGS)
1346 {
1347 
1348 	if (p == curproc)
1349 		sbuf_printf(sb, "/dev/fd");
1350 	else
1351 		sbuf_printf(sb, "unknown");
1352 	return (0);
1353 }
1354 
1355 
1356 /*
1357  * Filler function for proc/sys/kernel/random/uuid
1358  */
1359 static int
1360 linprocfs_douuid(PFS_FILL_ARGS)
1361 {
1362 	struct uuid uuid;
1363 
1364 	kern_uuidgen(&uuid, 1);
1365 	sbuf_printf_uuid(sb, &uuid);
1366 	sbuf_printf(sb, "\n");
1367 	return(0);
1368 }
1369 
1370 /*
1371  * Filler function for proc/pid/auxv
1372  */
1373 static int
1374 linprocfs_doauxv(PFS_FILL_ARGS)
1375 {
1376 	struct sbuf *asb;
1377 	off_t buflen, resid;
1378 	int error;
1379 
1380 	/*
1381 	 * Mimic linux behavior and pass only processes with usermode
1382 	 * address space as valid. Return zero silently otherwise.
1383 	 */
1384 	if (p->p_vmspace == &vmspace0)
1385 		return (0);
1386 
1387 	if (uio->uio_resid == 0)
1388 		return (0);
1389 	if (uio->uio_offset < 0 || uio->uio_resid < 0)
1390 		return (EINVAL);
1391 
1392 	asb = sbuf_new_auto();
1393 	if (asb == NULL)
1394 		return (ENOMEM);
1395 	error = proc_getauxv(td, p, asb);
1396 	if (error == 0)
1397 		error = sbuf_finish(asb);
1398 
1399 	resid = sbuf_len(asb) - uio->uio_offset;
1400 	if (resid > uio->uio_resid)
1401 		buflen = uio->uio_resid;
1402 	else
1403 		buflen = resid;
1404 	if (buflen > IOSIZE_MAX)
1405 		return (EINVAL);
1406 	if (buflen > MAXPHYS)
1407 		buflen = MAXPHYS;
1408 	if (resid <= 0)
1409 		return (0);
1410 
1411 	if (error == 0)
1412 		error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1413 	sbuf_delete(asb);
1414 	return (error);
1415 }
1416 
1417 /*
1418  * Constructor
1419  */
1420 static int
1421 linprocfs_init(PFS_INIT_ARGS)
1422 {
1423 	struct pfs_node *root;
1424 	struct pfs_node *dir;
1425 
1426 	root = pi->pi_root;
1427 
1428 	/* /proc/... */
1429 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1430 	    NULL, NULL, NULL, PFS_RD);
1431 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1432 	    NULL, NULL, NULL, PFS_RD);
1433 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1434 	    NULL, NULL, NULL, PFS_RD);
1435 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1436 	    NULL, NULL, NULL, PFS_RD);
1437 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1438 	    NULL, NULL, NULL, PFS_RD);
1439 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1440 	    NULL, NULL, NULL, PFS_RD);
1441 #if 0
1442 	pfs_create_file(root, "modules", &linprocfs_domodules,
1443 	    NULL, NULL, NULL, PFS_RD);
1444 #endif
1445 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1446 	    NULL, NULL, NULL, PFS_RD);
1447 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1448 	    NULL, NULL, NULL, PFS_RD);
1449 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1450 	    NULL, NULL, NULL, PFS_RD);
1451 	pfs_create_link(root, "self", &procfs_docurproc,
1452 	    NULL, NULL, NULL, 0);
1453 	pfs_create_file(root, "stat", &linprocfs_dostat,
1454 	    NULL, NULL, NULL, PFS_RD);
1455 	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1456 	    NULL, NULL, NULL, PFS_RD);
1457 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1458 	    NULL, NULL, NULL, PFS_RD);
1459 	pfs_create_file(root, "version", &linprocfs_doversion,
1460 	    NULL, NULL, NULL, PFS_RD);
1461 
1462 	/* /proc/net/... */
1463 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1464 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1465 	    NULL, NULL, NULL, PFS_RD);
1466 
1467 	/* /proc/<pid>/... */
1468 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1469 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1470 	    NULL, NULL, NULL, PFS_RD);
1471 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1472 	    NULL, NULL, NULL, 0);
1473 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1474 	    NULL, &procfs_candebug, NULL, PFS_RD);
1475 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1476 	    NULL, &procfs_notsystem, NULL, 0);
1477 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1478 	    NULL, NULL, NULL, PFS_RD);
1479 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1480 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1481 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1482 	    NULL, NULL, NULL, 0);
1483 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1484 	    NULL, NULL, NULL, PFS_RD);
1485 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1486 	    NULL, NULL, NULL, PFS_RD);
1487 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1488 	    NULL, NULL, NULL, PFS_RD);
1489 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1490 	    NULL, NULL, NULL, 0);
1491 	pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1492 	    NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1493 
1494 	/* /proc/scsi/... */
1495 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1496 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1497 	    NULL, NULL, NULL, PFS_RD);
1498 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1499 	    NULL, NULL, NULL, PFS_RD);
1500 
1501 	/* /proc/sys/... */
1502 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1503 	/* /proc/sys/kernel/... */
1504 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1505 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1506 	    NULL, NULL, NULL, PFS_RD);
1507 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1508 	    NULL, NULL, NULL, PFS_RD);
1509 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1510 	    NULL, NULL, NULL, PFS_RD);
1511 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1512 	    NULL, NULL, NULL, PFS_RD);
1513 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1514 	    NULL, NULL, NULL, PFS_RD);
1515 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1516 	    NULL, NULL, NULL, PFS_RD);
1517 
1518 	/* /proc/sys/kernel/random/... */
1519 	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1520 	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1521 	    NULL, NULL, NULL, PFS_RD);
1522 
1523 	return (0);
1524 }
1525 
1526 /*
1527  * Destructor
1528  */
1529 static int
1530 linprocfs_uninit(PFS_INIT_ARGS)
1531 {
1532 
1533 	/* nothing to do, pseudofs will GC */
1534 	return (0);
1535 }
1536 
1537 PSEUDOFS(linprocfs, 1, 0);
1538 #if defined(__amd64__)
1539 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1540 #else
1541 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1542 #endif
1543 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1544 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1545 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1546