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