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