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