xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision d825ce0a5de8e66cd685cf63dc3231d50bbb3500)
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 	if (flep != NULL)
390 		free(flep, M_TEMP);
391 	return (error);
392 }
393 
394 /*
395  * Filler function for proc/partitions
396  *
397  */
398 static int
399 linprocfs_dopartitions(PFS_FILL_ARGS)
400 {
401 	struct g_class *cp;
402 	struct g_geom *gp;
403 	struct g_provider *pp;
404 	struct nameidata nd;
405 	const char *lep;
406 	char  *dlep, *flep;
407 	size_t lep_len;
408 	int error;
409 	int major, minor;
410 
411 	/* resolve symlinks etc. in the emulation tree prefix */
412 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
413 	flep = NULL;
414 	error = namei(&nd);
415 	lep = linux_emul_path;
416 	if (error == 0) {
417 		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
418 			lep = dlep;
419 		vrele(nd.ni_vp);
420 	}
421 	lep_len = strlen(lep);
422 
423 	g_topology_lock();
424 	error = 0;
425 	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
426 	    "ruse wio wmerge wsect wuse running use aveq\n");
427 
428 	LIST_FOREACH(cp, &g_classes, class) {
429 		if (strcmp(cp->name, "DISK") == 0 ||
430 		    strcmp(cp->name, "PART") == 0)
431 			LIST_FOREACH(gp, &cp->geom, geom) {
432 				LIST_FOREACH(pp, &gp->provider, provider) {
433 					if (linux_driver_get_major_minor(
434 					    pp->name, &major, &minor) != 0) {
435 						major = 0;
436 						minor = 0;
437 					}
438 					sbuf_printf(sb, "%d %d %lld %s "
439 					    "%d %d %d %d %d "
440 					     "%d %d %d %d %d %d\n",
441 					     major, minor,
442 					     (long long)pp->mediasize, pp->name,
443 					     0, 0, 0, 0, 0,
444 					     0, 0, 0, 0, 0, 0);
445 				}
446 			}
447 	}
448 	g_topology_unlock();
449 
450 	if (flep != NULL)
451 		free(flep, M_TEMP);
452 	return (error);
453 }
454 
455 
456 /*
457  * Filler function for proc/stat
458  */
459 static int
460 linprocfs_dostat(PFS_FILL_ARGS)
461 {
462 	struct pcpu *pcpu;
463 	long cp_time[CPUSTATES];
464 	long *cp;
465 	int i;
466 
467 	read_cpu_time(cp_time);
468 	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
469 	    T2J(cp_time[CP_USER]),
470 	    T2J(cp_time[CP_NICE]),
471 	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
472 	    T2J(cp_time[CP_IDLE]));
473 	CPU_FOREACH(i) {
474 		pcpu = pcpu_find(i);
475 		cp = pcpu->pc_cp_time;
476 		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
477 		    T2J(cp[CP_USER]),
478 		    T2J(cp[CP_NICE]),
479 		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
480 		    T2J(cp[CP_IDLE]));
481 	}
482 	sbuf_printf(sb,
483 	    "disk 0 0 0 0\n"
484 	    "page %u %u\n"
485 	    "swap %u %u\n"
486 	    "intr %u\n"
487 	    "ctxt %u\n"
488 	    "btime %lld\n",
489 	    cnt.v_vnodepgsin,
490 	    cnt.v_vnodepgsout,
491 	    cnt.v_swappgsin,
492 	    cnt.v_swappgsout,
493 	    cnt.v_intr,
494 	    cnt.v_swtch,
495 	    (long long)boottime.tv_sec);
496 	return (0);
497 }
498 
499 static int
500 linprocfs_doswaps(PFS_FILL_ARGS)
501 {
502 	struct xswdev xsw;
503 	uintmax_t total, used;
504 	int n;
505 	char devname[SPECNAMELEN + 1];
506 
507 	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
508 	mtx_lock(&Giant);
509 	for (n = 0; ; n++) {
510 		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
511 			break;
512 		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
513 		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
514 
515 		/*
516 		 * The space and not tab after the device name is on
517 		 * purpose.  Linux does so.
518 		 */
519 		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
520 		    devname, total, used);
521 	}
522 	mtx_unlock(&Giant);
523 	return (0);
524 }
525 
526 /*
527  * Filler function for proc/uptime
528  */
529 static int
530 linprocfs_douptime(PFS_FILL_ARGS)
531 {
532 	long cp_time[CPUSTATES];
533 	struct timeval tv;
534 
535 	getmicrouptime(&tv);
536 	read_cpu_time(cp_time);
537 	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
538 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
539 	    T2S(cp_time[CP_IDLE] / mp_ncpus),
540 	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
541 	return (0);
542 }
543 
544 /*
545  * Get OS build date
546  */
547 static void
548 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
549 {
550 #if 0
551 	char osbuild[256];
552 	char *cp1, *cp2;
553 
554 	strncpy(osbuild, version, 256);
555 	osbuild[255] = '\0';
556 	cp1 = strstr(osbuild, "\n");
557 	cp2 = strstr(osbuild, ":");
558 	if (cp1 && cp2) {
559 		*cp1 = *cp2 = '\0';
560 		cp1 = strstr(osbuild, "#");
561 	} else
562 		cp1 = NULL;
563 	if (cp1)
564 		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
565 	else
566 #endif
567 		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
568 }
569 
570 /*
571  * Get OS builder
572  */
573 static void
574 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
575 {
576 #if 0
577 	char builder[256];
578 	char *cp;
579 
580 	cp = strstr(version, "\n    ");
581 	if (cp) {
582 		strncpy(builder, cp + 5, 256);
583 		builder[255] = '\0';
584 		cp = strstr(builder, ":");
585 		if (cp)
586 			*cp = '\0';
587 	}
588 	if (cp)
589 		sbuf_cat(sb, builder);
590 	else
591 #endif
592 		sbuf_cat(sb, "des@freebsd.org");
593 }
594 
595 /*
596  * Filler function for proc/version
597  */
598 static int
599 linprocfs_doversion(PFS_FILL_ARGS)
600 {
601 	char osname[LINUX_MAX_UTSNAME];
602 	char osrelease[LINUX_MAX_UTSNAME];
603 
604 	linux_get_osname(td, osname);
605 	linux_get_osrelease(td, osrelease);
606 	sbuf_printf(sb, "%s version %s (", osname, osrelease);
607 	linprocfs_osbuilder(td, sb);
608 	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
609 	linprocfs_osbuild(td, sb);
610 	sbuf_cat(sb, "\n");
611 
612 	return (0);
613 }
614 
615 /*
616  * Filler function for proc/loadavg
617  */
618 static int
619 linprocfs_doloadavg(PFS_FILL_ARGS)
620 {
621 
622 	sbuf_printf(sb,
623 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
624 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
625 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
626 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
627 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
628 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
629 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
630 	    1,				/* number of running tasks */
631 	    nprocs,			/* number of tasks */
632 	    lastpid			/* the last pid */
633 	);
634 	return (0);
635 }
636 
637 /*
638  * Filler function for proc/pid/stat
639  */
640 static int
641 linprocfs_doprocstat(PFS_FILL_ARGS)
642 {
643 	struct kinfo_proc kp;
644 	char state;
645 	static int ratelimit = 0;
646 	vm_offset_t startcode, startdata;
647 
648 	PROC_LOCK(p);
649 	fill_kinfo_proc(p, &kp);
650 	if (p->p_vmspace) {
651 	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
652 	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
653 	} else {
654 	   startcode = 0;
655 	   startdata = 0;
656 	};
657 	sbuf_printf(sb, "%d", p->p_pid);
658 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
659 	PS_ADD("comm",		"(%s)",	p->p_comm);
660 	if (kp.ki_stat > sizeof(linux_state)) {
661 		state = 'R';
662 
663 		if (ratelimit == 0) {
664 			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
665 			    kp.ki_stat, sizeof(linux_state));
666 			++ratelimit;
667 		}
668 	} else
669 		state = linux_state[kp.ki_stat - 1];
670 	PS_ADD("state",		"%c",	state);
671 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
672 	PS_ADD("pgrp",		"%d",	p->p_pgid);
673 	PS_ADD("session",	"%d",	p->p_session->s_sid);
674 	PROC_UNLOCK(p);
675 	PS_ADD("tty",		"%d",	kp.ki_tdev);
676 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
677 	PS_ADD("flags",		"%u",	0); /* XXX */
678 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
679 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
680 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
681 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
682 	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
683 	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
684 	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
685 	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
686 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
687 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
688 	PS_ADD("0",		"%d",	0); /* removed field */
689 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
690 	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
691 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
692 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
693 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
694 	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
695 	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
696 	PS_ADD("startstack",	"%u",	0); /* XXX */
697 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
698 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
699 	PS_ADD("signal",	"%u",	0); /* XXX */
700 	PS_ADD("blocked",	"%u",	0); /* XXX */
701 	PS_ADD("sigignore",	"%u",	0); /* XXX */
702 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
703 	PS_ADD("wchan",		"%u",	0); /* XXX */
704 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
705 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
706 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
707 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
708 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
709 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
710 #undef PS_ADD
711 	sbuf_putc(sb, '\n');
712 
713 	return (0);
714 }
715 
716 /*
717  * Filler function for proc/pid/statm
718  */
719 static int
720 linprocfs_doprocstatm(PFS_FILL_ARGS)
721 {
722 	struct kinfo_proc kp;
723 	segsz_t lsize;
724 
725 	PROC_LOCK(p);
726 	fill_kinfo_proc(p, &kp);
727 	PROC_UNLOCK(p);
728 
729 	/*
730 	 * See comments in linprocfs_doprocstatus() regarding the
731 	 * computation of lsize.
732 	 */
733 	/* size resident share trs drs lrs dt */
734 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
735 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
736 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
737 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
738 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
739 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
740 	    kp.ki_ssize - kp.ki_tsize - 1;
741 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
742 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
743 
744 	return (0);
745 }
746 
747 /*
748  * Filler function for proc/pid/status
749  */
750 static int
751 linprocfs_doprocstatus(PFS_FILL_ARGS)
752 {
753 	struct kinfo_proc kp;
754 	char *state;
755 	segsz_t lsize;
756 	struct thread *td2;
757 	struct sigacts *ps;
758 	int i;
759 
760 	PROC_LOCK(p);
761 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
762 
763 	if (P_SHOULDSTOP(p)) {
764 		state = "T (stopped)";
765 	} else {
766 		switch(p->p_state) {
767 		case PRS_NEW:
768 			state = "I (idle)";
769 			break;
770 		case PRS_NORMAL:
771 			if (p->p_flag & P_WEXIT) {
772 				state = "X (exiting)";
773 				break;
774 			}
775 			switch(td2->td_state) {
776 			case TDS_INHIBITED:
777 				state = "S (sleeping)";
778 				break;
779 			case TDS_RUNQ:
780 			case TDS_RUNNING:
781 				state = "R (running)";
782 				break;
783 			default:
784 				state = "? (unknown)";
785 				break;
786 			}
787 			break;
788 		case PRS_ZOMBIE:
789 			state = "Z (zombie)";
790 			break;
791 		default:
792 			state = "? (unknown)";
793 			break;
794 		}
795 	}
796 
797 	fill_kinfo_proc(p, &kp);
798 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
799 	sbuf_printf(sb, "State:\t%s\n",		state);
800 
801 	/*
802 	 * Credentials
803 	 */
804 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
805 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
806 						p->p_pptr->p_pid : 0);
807 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
808 						p->p_ucred->cr_uid,
809 						p->p_ucred->cr_svuid,
810 						/* FreeBSD doesn't have fsuid */
811 						p->p_ucred->cr_uid);
812 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
813 						p->p_ucred->cr_gid,
814 						p->p_ucred->cr_svgid,
815 						/* FreeBSD doesn't have fsgid */
816 						p->p_ucred->cr_gid);
817 	sbuf_cat(sb, "Groups:\t");
818 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
819 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
820 	PROC_UNLOCK(p);
821 	sbuf_putc(sb, '\n');
822 
823 	/*
824 	 * Memory
825 	 *
826 	 * While our approximation of VmLib may not be accurate (I
827 	 * don't know of a simple way to verify it, and I'm not sure
828 	 * it has much meaning anyway), I believe it's good enough.
829 	 *
830 	 * The same code that could (I think) accurately compute VmLib
831 	 * could also compute VmLck, but I don't really care enough to
832 	 * implement it. Submissions are welcome.
833 	 */
834 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
835 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
836 	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
837 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
838 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
839 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
840 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
841 	    kp.ki_ssize - kp.ki_tsize - 1;
842 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
843 
844 	/*
845 	 * Signal masks
846 	 *
847 	 * We support up to 128 signals, while Linux supports 32,
848 	 * but we only define 32 (the same 32 as Linux, to boot), so
849 	 * just show the lower 32 bits of each mask. XXX hack.
850 	 *
851 	 * NB: on certain platforms (Sparc at least) Linux actually
852 	 * supports 64 signals, but this code is a long way from
853 	 * running on anything but i386, so ignore that for now.
854 	 */
855 	PROC_LOCK(p);
856 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
857 	/*
858 	 * I can't seem to find out where the signal mask is in
859 	 * relation to struct proc, so SigBlk is left unimplemented.
860 	 */
861 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
862 	ps = p->p_sigacts;
863 	mtx_lock(&ps->ps_mtx);
864 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
865 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
866 	mtx_unlock(&ps->ps_mtx);
867 	PROC_UNLOCK(p);
868 
869 	/*
870 	 * Linux also prints the capability masks, but we don't have
871 	 * capabilities yet, and when we do get them they're likely to
872 	 * be meaningless to Linux programs, so we lie. XXX
873 	 */
874 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
875 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
876 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
877 
878 	return (0);
879 }
880 
881 
882 /*
883  * Filler function for proc/pid/cwd
884  */
885 static int
886 linprocfs_doproccwd(PFS_FILL_ARGS)
887 {
888 	char *fullpath = "unknown";
889 	char *freepath = NULL;
890 
891 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
892 	sbuf_printf(sb, "%s", fullpath);
893 	if (freepath)
894 		free(freepath, M_TEMP);
895 	return (0);
896 }
897 
898 /*
899  * Filler function for proc/pid/root
900  */
901 static int
902 linprocfs_doprocroot(PFS_FILL_ARGS)
903 {
904 	struct vnode *rvp;
905 	char *fullpath = "unknown";
906 	char *freepath = NULL;
907 
908 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
909 	vn_fullpath(td, rvp, &fullpath, &freepath);
910 	sbuf_printf(sb, "%s", fullpath);
911 	if (freepath)
912 		free(freepath, M_TEMP);
913 	return (0);
914 }
915 
916 /*
917  * Filler function for proc/pid/cmdline
918  */
919 static int
920 linprocfs_doproccmdline(PFS_FILL_ARGS)
921 {
922 	int ret;
923 
924 	PROC_LOCK(p);
925 	if ((ret = p_cansee(td, p)) != 0) {
926 		PROC_UNLOCK(p);
927 		return (ret);
928 	}
929 
930 	/*
931 	 * Mimic linux behavior and pass only processes with usermode
932 	 * address space as valid.  Return zero silently otherwize.
933 	 */
934 	if (p->p_vmspace == &vmspace0) {
935 		PROC_UNLOCK(p);
936 		return (0);
937 	}
938 	if (p->p_args != NULL) {
939 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
940 		PROC_UNLOCK(p);
941 		return (0);
942 	}
943 
944 	if ((p->p_flag & P_SYSTEM) != 0) {
945 		PROC_UNLOCK(p);
946 		return (0);
947 	}
948 
949 	PROC_UNLOCK(p);
950 
951 	ret = proc_getargv(td, p, sb);
952 	return (ret);
953 }
954 
955 /*
956  * Filler function for proc/pid/environ
957  */
958 static int
959 linprocfs_doprocenviron(PFS_FILL_ARGS)
960 {
961 	int ret;
962 
963 	PROC_LOCK(p);
964 	if ((ret = p_candebug(td, p)) != 0) {
965 		PROC_UNLOCK(p);
966 		return (ret);
967 	}
968 
969 	/*
970 	 * Mimic linux behavior and pass only processes with usermode
971 	 * address space as valid.  Return zero silently otherwize.
972 	 */
973 	if (p->p_vmspace == &vmspace0) {
974 		PROC_UNLOCK(p);
975 		return (0);
976 	}
977 
978 	if ((p->p_flag & P_SYSTEM) != 0) {
979 		PROC_UNLOCK(p);
980 		return (0);
981 	}
982 
983 	PROC_UNLOCK(p);
984 
985 	ret = proc_getenvv(td, p, sb);
986 	return (ret);
987 }
988 
989 /*
990  * Filler function for proc/pid/maps
991  */
992 static int
993 linprocfs_doprocmaps(PFS_FILL_ARGS)
994 {
995 	struct vmspace *vm;
996 	vm_map_t map;
997 	vm_map_entry_t entry, tmp_entry;
998 	vm_object_t obj, tobj, lobj;
999 	vm_offset_t e_start, e_end;
1000 	vm_ooffset_t off = 0;
1001 	vm_prot_t e_prot;
1002 	unsigned int last_timestamp;
1003 	char *name = "", *freename = NULL;
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_LOCK(tobj);
1037 			if (lobj != obj)
1038 				VM_OBJECT_UNLOCK(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_UNLOCK(lobj);
1055 			flags = obj->flags;
1056 			ref_count = obj->ref_count;
1057 			shadow_count = obj->shadow_count;
1058 			VM_OBJECT_UNLOCK(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 		error = sbuf_printf(sb,
1077 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1078 		    (u_long)e_start, (u_long)e_end,
1079 		    (e_prot & VM_PROT_READ)?"r":"-",
1080 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1081 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1082 		    "p",
1083 		    (u_long)off,
1084 		    0,
1085 		    0,
1086 		    (u_long)ino,
1087 		    *name ? "     " : "",
1088 		    name
1089 		    );
1090 		if (freename)
1091 			free(freename, M_TEMP);
1092 		vm_map_lock_read(map);
1093 		if (error == -1) {
1094 			error = 0;
1095 			break;
1096 		}
1097 		if (last_timestamp != map->timestamp) {
1098 			/*
1099 			 * Look again for the entry because the map was
1100 			 * modified while it was unlocked.  Specifically,
1101 			 * the entry may have been clipped, merged, or deleted.
1102 			 */
1103 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1104 			entry = tmp_entry;
1105 		}
1106 	}
1107 	vm_map_unlock_read(map);
1108 	vmspace_free(vm);
1109 
1110 	return (error);
1111 }
1112 
1113 /*
1114  * Filler function for proc/net/dev
1115  */
1116 static int
1117 linprocfs_donetdev(PFS_FILL_ARGS)
1118 {
1119 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1120 	struct ifnet *ifp;
1121 
1122 	sbuf_printf(sb, "%6s|%58s|%s\n"
1123 	    "%6s|%58s|%58s\n",
1124 	    "Inter-", "   Receive", "  Transmit",
1125 	    " face",
1126 	    "bytes    packets errs drop fifo frame compressed multicast",
1127 	    "bytes    packets errs drop fifo colls carrier compressed");
1128 
1129 	CURVNET_SET(TD_TO_VNET(curthread));
1130 	IFNET_RLOCK();
1131 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1132 		linux_ifname(ifp, ifname, sizeof ifname);
1133 		sbuf_printf(sb, "%6.6s: ", ifname);
1134 		sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1135 		    ifp->if_ibytes,	/* rx_bytes */
1136 		    ifp->if_ipackets,	/* rx_packets */
1137 		    ifp->if_ierrors,	/* rx_errors */
1138 		    ifp->if_iqdrops,	/* rx_dropped +
1139 					 * rx_missed_errors */
1140 		    0UL,		/* rx_fifo_errors */
1141 		    0UL,		/* rx_length_errors +
1142 					 * rx_over_errors +
1143 		    			 * rx_crc_errors +
1144 					 * rx_frame_errors */
1145 		    0UL,		/* rx_compressed */
1146 		    ifp->if_imcasts);	/* multicast, XXX-BZ rx only? */
1147 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1148 		    ifp->if_obytes,	/* tx_bytes */
1149 		    ifp->if_opackets,	/* tx_packets */
1150 		    ifp->if_oerrors,	/* tx_errors */
1151 		    0UL,		/* tx_dropped */
1152 		    0UL,		/* tx_fifo_errors */
1153 		    ifp->if_collisions,	/* collisions */
1154 		    0UL,		/* tx_carrier_errors +
1155 					 * tx_aborted_errors +
1156 					 * tx_window_errors +
1157 					 * tx_heartbeat_errors */
1158 		    0UL);		/* tx_compressed */
1159 	}
1160 	IFNET_RUNLOCK();
1161 	CURVNET_RESTORE();
1162 
1163 	return (0);
1164 }
1165 
1166 /*
1167  * Filler function for proc/sys/kernel/osrelease
1168  */
1169 static int
1170 linprocfs_doosrelease(PFS_FILL_ARGS)
1171 {
1172 	char osrelease[LINUX_MAX_UTSNAME];
1173 
1174 	linux_get_osrelease(td, osrelease);
1175 	sbuf_printf(sb, "%s\n", osrelease);
1176 
1177 	return (0);
1178 }
1179 
1180 /*
1181  * Filler function for proc/sys/kernel/ostype
1182  */
1183 static int
1184 linprocfs_doostype(PFS_FILL_ARGS)
1185 {
1186 	char osname[LINUX_MAX_UTSNAME];
1187 
1188 	linux_get_osname(td, osname);
1189 	sbuf_printf(sb, "%s\n", osname);
1190 
1191 	return (0);
1192 }
1193 
1194 /*
1195  * Filler function for proc/sys/kernel/version
1196  */
1197 static int
1198 linprocfs_doosbuild(PFS_FILL_ARGS)
1199 {
1200 
1201 	linprocfs_osbuild(td, sb);
1202 	sbuf_cat(sb, "\n");
1203 	return (0);
1204 }
1205 
1206 /*
1207  * Filler function for proc/sys/kernel/msgmni
1208  */
1209 static int
1210 linprocfs_domsgmni(PFS_FILL_ARGS)
1211 {
1212 
1213 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1214 	return (0);
1215 }
1216 
1217 /*
1218  * Filler function for proc/sys/kernel/pid_max
1219  */
1220 static int
1221 linprocfs_dopid_max(PFS_FILL_ARGS)
1222 {
1223 
1224 	sbuf_printf(sb, "%i\n", PID_MAX);
1225 	return (0);
1226 }
1227 
1228 /*
1229  * Filler function for proc/sys/kernel/sem
1230  */
1231 static int
1232 linprocfs_dosem(PFS_FILL_ARGS)
1233 {
1234 
1235 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1236 	    seminfo.semopm, seminfo.semmni);
1237 	return (0);
1238 }
1239 
1240 /*
1241  * Filler function for proc/scsi/device_info
1242  */
1243 static int
1244 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1245 {
1246 
1247 	return (0);
1248 }
1249 
1250 /*
1251  * Filler function for proc/scsi/scsi
1252  */
1253 static int
1254 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1255 {
1256 
1257 	return (0);
1258 }
1259 
1260 extern struct cdevsw *cdevsw[];
1261 
1262 /*
1263  * Filler function for proc/devices
1264  */
1265 static int
1266 linprocfs_dodevices(PFS_FILL_ARGS)
1267 {
1268 	char *char_devices;
1269 	sbuf_printf(sb, "Character devices:\n");
1270 
1271 	char_devices = linux_get_char_devices();
1272 	sbuf_printf(sb, "%s", char_devices);
1273 	linux_free_get_char_devices(char_devices);
1274 
1275 	sbuf_printf(sb, "\nBlock devices:\n");
1276 
1277 	return (0);
1278 }
1279 
1280 /*
1281  * Filler function for proc/cmdline
1282  */
1283 static int
1284 linprocfs_docmdline(PFS_FILL_ARGS)
1285 {
1286 
1287 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1288 	sbuf_printf(sb, " ro root=302\n");
1289 	return (0);
1290 }
1291 
1292 /*
1293  * Filler function for proc/filesystems
1294  */
1295 static int
1296 linprocfs_dofilesystems(PFS_FILL_ARGS)
1297 {
1298 	struct vfsconf *vfsp;
1299 
1300 	mtx_lock(&Giant);
1301 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1302 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1303 			sbuf_printf(sb, "nodev");
1304 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1305 	}
1306 	mtx_unlock(&Giant);
1307 	return(0);
1308 }
1309 
1310 #if 0
1311 /*
1312  * Filler function for proc/modules
1313  */
1314 static int
1315 linprocfs_domodules(PFS_FILL_ARGS)
1316 {
1317 	struct linker_file *lf;
1318 
1319 	TAILQ_FOREACH(lf, &linker_files, link) {
1320 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1321 		    (unsigned long)lf->size, lf->refs);
1322 	}
1323 	return (0);
1324 }
1325 #endif
1326 
1327 /*
1328  * Filler function for proc/pid/fd
1329  */
1330 static int
1331 linprocfs_dofdescfs(PFS_FILL_ARGS)
1332 {
1333 
1334 	if (p == curproc)
1335 		sbuf_printf(sb, "/dev/fd");
1336 	else
1337 		sbuf_printf(sb, "unknown");
1338 	return (0);
1339 }
1340 
1341 /*
1342  * Constructor
1343  */
1344 static int
1345 linprocfs_init(PFS_INIT_ARGS)
1346 {
1347 	struct pfs_node *root;
1348 	struct pfs_node *dir;
1349 
1350 	root = pi->pi_root;
1351 
1352 	/* /proc/... */
1353 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1354 	    NULL, NULL, NULL, PFS_RD);
1355 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1356 	    NULL, NULL, NULL, PFS_RD);
1357 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1358 	    NULL, NULL, NULL, PFS_RD);
1359 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1360 	    NULL, NULL, NULL, PFS_RD);
1361 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1362 	    NULL, NULL, NULL, PFS_RD);
1363 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1364 	    NULL, NULL, NULL, PFS_RD);
1365 #if 0
1366 	pfs_create_file(root, "modules", &linprocfs_domodules,
1367 	    NULL, NULL, NULL, PFS_RD);
1368 #endif
1369 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1370 	    NULL, NULL, NULL, PFS_RD);
1371 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1372 	    NULL, NULL, NULL, PFS_RD);
1373 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1374 	    NULL, NULL, NULL, PFS_RD);
1375 	pfs_create_link(root, "self", &procfs_docurproc,
1376 	    NULL, NULL, NULL, 0);
1377 	pfs_create_file(root, "stat", &linprocfs_dostat,
1378 	    NULL, NULL, NULL, PFS_RD);
1379 	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1380 	    NULL, NULL, NULL, PFS_RD);
1381 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1382 	    NULL, NULL, NULL, PFS_RD);
1383 	pfs_create_file(root, "version", &linprocfs_doversion,
1384 	    NULL, NULL, NULL, PFS_RD);
1385 
1386 	/* /proc/net/... */
1387 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1388 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1389 	    NULL, NULL, NULL, PFS_RD);
1390 
1391 	/* /proc/<pid>/... */
1392 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1393 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1394 	    NULL, NULL, NULL, PFS_RD);
1395 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1396 	    NULL, NULL, NULL, 0);
1397 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1398 	    NULL, NULL, NULL, PFS_RD);
1399 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1400 	    NULL, &procfs_notsystem, NULL, 0);
1401 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1402 	    NULL, NULL, NULL, PFS_RD);
1403 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1404 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1405 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1406 	    NULL, NULL, NULL, 0);
1407 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1408 	    NULL, NULL, NULL, PFS_RD);
1409 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1410 	    NULL, NULL, NULL, PFS_RD);
1411 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1412 	    NULL, NULL, NULL, PFS_RD);
1413 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1414 	    NULL, NULL, NULL, 0);
1415 
1416 	/* /proc/scsi/... */
1417 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1418 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1419 	    NULL, NULL, NULL, PFS_RD);
1420 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1421 	    NULL, NULL, NULL, PFS_RD);
1422 
1423 	/* /proc/sys/... */
1424 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1425 	/* /proc/sys/kernel/... */
1426 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1427 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1428 	    NULL, NULL, NULL, PFS_RD);
1429 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1430 	    NULL, NULL, NULL, PFS_RD);
1431 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1432 	    NULL, NULL, NULL, PFS_RD);
1433 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1434 	    NULL, NULL, NULL, PFS_RD);
1435 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1436 	    NULL, NULL, NULL, PFS_RD);
1437 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1438 	    NULL, NULL, NULL, PFS_RD);
1439 
1440 	return (0);
1441 }
1442 
1443 /*
1444  * Destructor
1445  */
1446 static int
1447 linprocfs_uninit(PFS_INIT_ARGS)
1448 {
1449 
1450 	/* nothing to do, pseudofs will GC */
1451 	return (0);
1452 }
1453 
1454 PSEUDOFS(linprocfs, 1, 0);
1455 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1456 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1457 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1458 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1459