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