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