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