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