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