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