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