xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision aa64588d28258aef88cc33b8043112e8856948d0)
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 	for (i = 0; i <= mp_maxid; ++i) {
472 		if (CPU_ABSENT(i))
473 			continue;
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 /*
500  * Filler function for proc/uptime
501  */
502 static int
503 linprocfs_douptime(PFS_FILL_ARGS)
504 {
505 	long cp_time[CPUSTATES];
506 	struct timeval tv;
507 
508 	getmicrouptime(&tv);
509 	read_cpu_time(cp_time);
510 	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
511 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
512 	    T2S(cp_time[CP_IDLE] / mp_ncpus),
513 	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
514 	return (0);
515 }
516 
517 /*
518  * Get OS build date
519  */
520 static void
521 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
522 {
523 #if 0
524 	char osbuild[256];
525 	char *cp1, *cp2;
526 
527 	strncpy(osbuild, version, 256);
528 	osbuild[255] = '\0';
529 	cp1 = strstr(osbuild, "\n");
530 	cp2 = strstr(osbuild, ":");
531 	if (cp1 && cp2) {
532 		*cp1 = *cp2 = '\0';
533 		cp1 = strstr(osbuild, "#");
534 	} else
535 		cp1 = NULL;
536 	if (cp1)
537 		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
538 	else
539 #endif
540 		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
541 }
542 
543 /*
544  * Get OS builder
545  */
546 static void
547 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
548 {
549 #if 0
550 	char builder[256];
551 	char *cp;
552 
553 	cp = strstr(version, "\n    ");
554 	if (cp) {
555 		strncpy(builder, cp + 5, 256);
556 		builder[255] = '\0';
557 		cp = strstr(builder, ":");
558 		if (cp)
559 			*cp = '\0';
560 	}
561 	if (cp)
562 		sbuf_cat(sb, builder);
563 	else
564 #endif
565 		sbuf_cat(sb, "des@freebsd.org");
566 }
567 
568 /*
569  * Filler function for proc/version
570  */
571 static int
572 linprocfs_doversion(PFS_FILL_ARGS)
573 {
574 	char osname[LINUX_MAX_UTSNAME];
575 	char osrelease[LINUX_MAX_UTSNAME];
576 
577 	linux_get_osname(td, osname);
578 	linux_get_osrelease(td, osrelease);
579 	sbuf_printf(sb, "%s version %s (", osname, osrelease);
580 	linprocfs_osbuilder(td, sb);
581 	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
582 	linprocfs_osbuild(td, sb);
583 	sbuf_cat(sb, "\n");
584 
585 	return (0);
586 }
587 
588 /*
589  * Filler function for proc/loadavg
590  */
591 static int
592 linprocfs_doloadavg(PFS_FILL_ARGS)
593 {
594 
595 	sbuf_printf(sb,
596 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
597 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
598 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
599 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
600 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
601 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
602 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
603 	    1,				/* number of running tasks */
604 	    nprocs,			/* number of tasks */
605 	    lastpid			/* the last pid */
606 	);
607 	return (0);
608 }
609 
610 /*
611  * Filler function for proc/pid/stat
612  */
613 static int
614 linprocfs_doprocstat(PFS_FILL_ARGS)
615 {
616 	struct kinfo_proc kp;
617 	char state;
618 	static int ratelimit = 0;
619 	vm_offset_t startcode, startdata;
620 
621 	PROC_LOCK(p);
622 	fill_kinfo_proc(p, &kp);
623 	if (p->p_vmspace) {
624 	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
625 	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
626 	} else {
627 	   startcode = 0;
628 	   startdata = 0;
629 	};
630 	sbuf_printf(sb, "%d", p->p_pid);
631 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
632 	PS_ADD("comm",		"(%s)",	p->p_comm);
633 	if (kp.ki_stat > sizeof(linux_state)) {
634 		state = 'R';
635 
636 		if (ratelimit == 0) {
637 			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
638 			    kp.ki_stat, sizeof(linux_state));
639 			++ratelimit;
640 		}
641 	} else
642 		state = linux_state[kp.ki_stat - 1];
643 	PS_ADD("state",		"%c",	state);
644 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
645 	PS_ADD("pgrp",		"%d",	p->p_pgid);
646 	PS_ADD("session",	"%d",	p->p_session->s_sid);
647 	PROC_UNLOCK(p);
648 	PS_ADD("tty",		"%d",	kp.ki_tdev);
649 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
650 	PS_ADD("flags",		"%u",	0); /* XXX */
651 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
652 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
653 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
654 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
655 	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
656 	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
657 	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
658 	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
659 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
660 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
661 	PS_ADD("0",		"%d",	0); /* removed field */
662 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
663 	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
664 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
665 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
666 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
667 	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
668 	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
669 	PS_ADD("startstack",	"%u",	0); /* XXX */
670 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
671 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
672 	PS_ADD("signal",	"%u",	0); /* XXX */
673 	PS_ADD("blocked",	"%u",	0); /* XXX */
674 	PS_ADD("sigignore",	"%u",	0); /* XXX */
675 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
676 	PS_ADD("wchan",		"%u",	0); /* XXX */
677 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
678 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
679 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
680 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
681 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
682 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
683 #undef PS_ADD
684 	sbuf_putc(sb, '\n');
685 
686 	return (0);
687 }
688 
689 /*
690  * Filler function for proc/pid/statm
691  */
692 static int
693 linprocfs_doprocstatm(PFS_FILL_ARGS)
694 {
695 	struct kinfo_proc kp;
696 	segsz_t lsize;
697 
698 	PROC_LOCK(p);
699 	fill_kinfo_proc(p, &kp);
700 	PROC_UNLOCK(p);
701 
702 	/*
703 	 * See comments in linprocfs_doprocstatus() regarding the
704 	 * computation of lsize.
705 	 */
706 	/* size resident share trs drs lrs dt */
707 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
708 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
709 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
710 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
711 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
712 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
713 	    kp.ki_ssize - kp.ki_tsize - 1;
714 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
715 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
716 
717 	return (0);
718 }
719 
720 /*
721  * Filler function for proc/pid/status
722  */
723 static int
724 linprocfs_doprocstatus(PFS_FILL_ARGS)
725 {
726 	struct kinfo_proc kp;
727 	char *state;
728 	segsz_t lsize;
729 	struct thread *td2;
730 	struct sigacts *ps;
731 	int i;
732 
733 	PROC_LOCK(p);
734 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
735 
736 	if (P_SHOULDSTOP(p)) {
737 		state = "T (stopped)";
738 	} else {
739 		PROC_SLOCK(p);
740 		switch(p->p_state) {
741 		case PRS_NEW:
742 			state = "I (idle)";
743 			break;
744 		case PRS_NORMAL:
745 			if (p->p_flag & P_WEXIT) {
746 				state = "X (exiting)";
747 				break;
748 			}
749 			switch(td2->td_state) {
750 			case TDS_INHIBITED:
751 				state = "S (sleeping)";
752 				break;
753 			case TDS_RUNQ:
754 			case TDS_RUNNING:
755 				state = "R (running)";
756 				break;
757 			default:
758 				state = "? (unknown)";
759 				break;
760 			}
761 			break;
762 		case PRS_ZOMBIE:
763 			state = "Z (zombie)";
764 			break;
765 		default:
766 			state = "? (unknown)";
767 			break;
768 		}
769 		PROC_SUNLOCK(p);
770 	}
771 
772 	fill_kinfo_proc(p, &kp);
773 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
774 	sbuf_printf(sb, "State:\t%s\n",		state);
775 
776 	/*
777 	 * Credentials
778 	 */
779 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
780 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
781 						p->p_pptr->p_pid : 0);
782 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
783 						p->p_ucred->cr_uid,
784 						p->p_ucred->cr_svuid,
785 						/* FreeBSD doesn't have fsuid */
786 						p->p_ucred->cr_uid);
787 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
788 						p->p_ucred->cr_gid,
789 						p->p_ucred->cr_svgid,
790 						/* FreeBSD doesn't have fsgid */
791 						p->p_ucred->cr_gid);
792 	sbuf_cat(sb, "Groups:\t");
793 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
794 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
795 	PROC_UNLOCK(p);
796 	sbuf_putc(sb, '\n');
797 
798 	/*
799 	 * Memory
800 	 *
801 	 * While our approximation of VmLib may not be accurate (I
802 	 * don't know of a simple way to verify it, and I'm not sure
803 	 * it has much meaning anyway), I believe it's good enough.
804 	 *
805 	 * The same code that could (I think) accurately compute VmLib
806 	 * could also compute VmLck, but I don't really care enough to
807 	 * implement it. Submissions are welcome.
808 	 */
809 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
810 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
811 	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
812 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
813 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
814 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
815 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
816 	    kp.ki_ssize - kp.ki_tsize - 1;
817 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
818 
819 	/*
820 	 * Signal masks
821 	 *
822 	 * We support up to 128 signals, while Linux supports 32,
823 	 * but we only define 32 (the same 32 as Linux, to boot), so
824 	 * just show the lower 32 bits of each mask. XXX hack.
825 	 *
826 	 * NB: on certain platforms (Sparc at least) Linux actually
827 	 * supports 64 signals, but this code is a long way from
828 	 * running on anything but i386, so ignore that for now.
829 	 */
830 	PROC_LOCK(p);
831 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
832 	/*
833 	 * I can't seem to find out where the signal mask is in
834 	 * relation to struct proc, so SigBlk is left unimplemented.
835 	 */
836 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
837 	ps = p->p_sigacts;
838 	mtx_lock(&ps->ps_mtx);
839 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
840 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
841 	mtx_unlock(&ps->ps_mtx);
842 	PROC_UNLOCK(p);
843 
844 	/*
845 	 * Linux also prints the capability masks, but we don't have
846 	 * capabilities yet, and when we do get them they're likely to
847 	 * be meaningless to Linux programs, so we lie. XXX
848 	 */
849 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
850 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
851 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
852 
853 	return (0);
854 }
855 
856 
857 /*
858  * Filler function for proc/pid/cwd
859  */
860 static int
861 linprocfs_doproccwd(PFS_FILL_ARGS)
862 {
863 	char *fullpath = "unknown";
864 	char *freepath = NULL;
865 
866 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
867 	sbuf_printf(sb, "%s", fullpath);
868 	if (freepath)
869 		free(freepath, M_TEMP);
870 	return (0);
871 }
872 
873 /*
874  * Filler function for proc/pid/root
875  */
876 static int
877 linprocfs_doprocroot(PFS_FILL_ARGS)
878 {
879 	struct vnode *rvp;
880 	char *fullpath = "unknown";
881 	char *freepath = NULL;
882 
883 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
884 	vn_fullpath(td, rvp, &fullpath, &freepath);
885 	sbuf_printf(sb, "%s", fullpath);
886 	if (freepath)
887 		free(freepath, M_TEMP);
888 	return (0);
889 }
890 
891 /*
892  * Filler function for proc/pid/cmdline
893  */
894 static int
895 linprocfs_doproccmdline(PFS_FILL_ARGS)
896 {
897 	struct ps_strings pstr;
898 	char **ps_argvstr;
899 	int error, i;
900 
901 	/*
902 	 * If we are using the ps/cmdline caching, use that.  Otherwise
903 	 * revert back to the old way which only implements full cmdline
904 	 * for the currept process and just p->p_comm for all other
905 	 * processes.
906 	 * Note that if the argv is no longer available, we deliberately
907 	 * don't fall back on p->p_comm or return an error: the authentic
908 	 * Linux behaviour is to return zero-length in this case.
909 	 */
910 
911 	PROC_LOCK(p);
912 	if (p->p_args && p_cansee(td, p) == 0) {
913 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
914 		PROC_UNLOCK(p);
915 	} else if (p != td->td_proc) {
916 		PROC_UNLOCK(p);
917 		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
918 	} else {
919 		PROC_UNLOCK(p);
920 		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
921 		    sizeof(pstr));
922 		if (error)
923 			return (error);
924 		if (pstr.ps_nargvstr > ARG_MAX)
925 			return (E2BIG);
926 		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
927 		    M_TEMP, M_WAITOK);
928 		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
929 		    pstr.ps_nargvstr * sizeof(char *));
930 		if (error) {
931 			free(ps_argvstr, M_TEMP);
932 			return (error);
933 		}
934 		for (i = 0; i < pstr.ps_nargvstr; i++) {
935 			sbuf_copyin(sb, ps_argvstr[i], 0);
936 			sbuf_printf(sb, "%c", '\0');
937 		}
938 		free(ps_argvstr, M_TEMP);
939 	}
940 
941 	return (0);
942 }
943 
944 /*
945  * Filler function for proc/pid/environ
946  */
947 static int
948 linprocfs_doprocenviron(PFS_FILL_ARGS)
949 {
950 
951 	sbuf_printf(sb, "doprocenviron\n%c", '\0');
952 	return (0);
953 }
954 
955 /*
956  * Filler function for proc/pid/maps
957  */
958 static int
959 linprocfs_doprocmaps(PFS_FILL_ARGS)
960 {
961 	struct vmspace *vm;
962 	vm_map_t map;
963 	vm_map_entry_t entry, tmp_entry;
964 	vm_object_t obj, tobj, lobj;
965 	vm_offset_t e_start, e_end;
966 	vm_ooffset_t off = 0;
967 	vm_prot_t e_prot;
968 	unsigned int last_timestamp;
969 	char *name = "", *freename = NULL;
970 	ino_t ino;
971 	int ref_count, shadow_count, flags;
972 	int error;
973 	struct vnode *vp;
974 	struct vattr vat;
975 	int locked;
976 
977 	PROC_LOCK(p);
978 	error = p_candebug(td, p);
979 	PROC_UNLOCK(p);
980 	if (error)
981 		return (error);
982 
983 	if (uio->uio_rw != UIO_READ)
984 		return (EOPNOTSUPP);
985 
986 	error = 0;
987 	vm = vmspace_acquire_ref(p);
988 	if (vm == NULL)
989 		return (ESRCH);
990 	map = &vm->vm_map;
991 	vm_map_lock_read(map);
992 	for (entry = map->header.next; entry != &map->header;
993 	    entry = entry->next) {
994 		name = "";
995 		freename = NULL;
996 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
997 			continue;
998 		e_prot = entry->protection;
999 		e_start = entry->start;
1000 		e_end = entry->end;
1001 		obj = entry->object.vm_object;
1002 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1003 			VM_OBJECT_LOCK(tobj);
1004 			if (lobj != obj)
1005 				VM_OBJECT_UNLOCK(lobj);
1006 			lobj = tobj;
1007 		}
1008 		last_timestamp = map->timestamp;
1009 		vm_map_unlock_read(map);
1010 		ino = 0;
1011 		if (lobj) {
1012 			off = IDX_TO_OFF(lobj->size);
1013 			if (lobj->type == OBJT_VNODE) {
1014 				vp = lobj->handle;
1015 				if (vp)
1016 					vref(vp);
1017 			}
1018 			else
1019 				vp = NULL;
1020 			if (lobj != obj)
1021 				VM_OBJECT_UNLOCK(lobj);
1022 			flags = obj->flags;
1023 			ref_count = obj->ref_count;
1024 			shadow_count = obj->shadow_count;
1025 			VM_OBJECT_UNLOCK(obj);
1026 			if (vp) {
1027 				vn_fullpath(td, vp, &name, &freename);
1028 				locked = VFS_LOCK_GIANT(vp->v_mount);
1029 				vn_lock(vp, LK_SHARED | LK_RETRY);
1030 				VOP_GETATTR(vp, &vat, td->td_ucred);
1031 				ino = vat.va_fileid;
1032 				vput(vp);
1033 				VFS_UNLOCK_GIANT(locked);
1034 			}
1035 		} else {
1036 			flags = 0;
1037 			ref_count = 0;
1038 			shadow_count = 0;
1039 		}
1040 
1041 		/*
1042 		 * format:
1043 		 *  start, end, access, offset, major, minor, inode, name.
1044 		 */
1045 		error = sbuf_printf(sb,
1046 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1047 		    (u_long)e_start, (u_long)e_end,
1048 		    (e_prot & VM_PROT_READ)?"r":"-",
1049 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1050 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1051 		    "p",
1052 		    (u_long)off,
1053 		    0,
1054 		    0,
1055 		    (u_long)ino,
1056 		    *name ? "     " : "",
1057 		    name
1058 		    );
1059 		if (freename)
1060 			free(freename, M_TEMP);
1061 		vm_map_lock_read(map);
1062 		if (error == -1) {
1063 			error = 0;
1064 			break;
1065 		}
1066 		if (last_timestamp != map->timestamp) {
1067 			/*
1068 			 * Look again for the entry because the map was
1069 			 * modified while it was unlocked.  Specifically,
1070 			 * the entry may have been clipped, merged, or deleted.
1071 			 */
1072 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1073 			entry = tmp_entry;
1074 		}
1075 	}
1076 	vm_map_unlock_read(map);
1077 	vmspace_free(vm);
1078 
1079 	return (error);
1080 }
1081 
1082 /*
1083  * Filler function for proc/net/dev
1084  */
1085 static int
1086 linprocfs_donetdev(PFS_FILL_ARGS)
1087 {
1088 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1089 	struct ifnet *ifp;
1090 
1091 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1092 	    "Inter-", "   Receive", "  Transmit", " face",
1093 	    "bytes    packets errs drop fifo frame compressed",
1094 	    "bytes    packets errs drop fifo frame compressed");
1095 
1096 	CURVNET_SET(TD_TO_VNET(curthread));
1097 	IFNET_RLOCK();
1098 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1099 		linux_ifname(ifp, ifname, sizeof ifname);
1100 			sbuf_printf(sb, "%6.6s:", ifname);
1101 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1102 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1103 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1104 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1105 	}
1106 	IFNET_RUNLOCK();
1107 	CURVNET_RESTORE();
1108 
1109 	return (0);
1110 }
1111 
1112 /*
1113  * Filler function for proc/sys/kernel/osrelease
1114  */
1115 static int
1116 linprocfs_doosrelease(PFS_FILL_ARGS)
1117 {
1118 	char osrelease[LINUX_MAX_UTSNAME];
1119 
1120 	linux_get_osrelease(td, osrelease);
1121 	sbuf_printf(sb, "%s\n", osrelease);
1122 
1123 	return (0);
1124 }
1125 
1126 /*
1127  * Filler function for proc/sys/kernel/ostype
1128  */
1129 static int
1130 linprocfs_doostype(PFS_FILL_ARGS)
1131 {
1132 	char osname[LINUX_MAX_UTSNAME];
1133 
1134 	linux_get_osname(td, osname);
1135 	sbuf_printf(sb, "%s\n", osname);
1136 
1137 	return (0);
1138 }
1139 
1140 /*
1141  * Filler function for proc/sys/kernel/version
1142  */
1143 static int
1144 linprocfs_doosbuild(PFS_FILL_ARGS)
1145 {
1146 
1147 	linprocfs_osbuild(td, sb);
1148 	sbuf_cat(sb, "\n");
1149 	return (0);
1150 }
1151 
1152 /*
1153  * Filler function for proc/sys/kernel/msgmni
1154  */
1155 static int
1156 linprocfs_domsgmni(PFS_FILL_ARGS)
1157 {
1158 
1159 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1160 	return (0);
1161 }
1162 
1163 /*
1164  * Filler function for proc/sys/kernel/pid_max
1165  */
1166 static int
1167 linprocfs_dopid_max(PFS_FILL_ARGS)
1168 {
1169 
1170 	sbuf_printf(sb, "%i\n", PID_MAX);
1171 	return (0);
1172 }
1173 
1174 /*
1175  * Filler function for proc/sys/kernel/sem
1176  */
1177 static int
1178 linprocfs_dosem(PFS_FILL_ARGS)
1179 {
1180 
1181 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1182 	    seminfo.semopm, seminfo.semmni);
1183 	return (0);
1184 }
1185 
1186 /*
1187  * Filler function for proc/scsi/device_info
1188  */
1189 static int
1190 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1191 {
1192 
1193 	return (0);
1194 }
1195 
1196 /*
1197  * Filler function for proc/scsi/scsi
1198  */
1199 static int
1200 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1201 {
1202 
1203 	return (0);
1204 }
1205 
1206 extern struct cdevsw *cdevsw[];
1207 
1208 /*
1209  * Filler function for proc/devices
1210  */
1211 static int
1212 linprocfs_dodevices(PFS_FILL_ARGS)
1213 {
1214 	char *char_devices;
1215 	sbuf_printf(sb, "Character devices:\n");
1216 
1217 	char_devices = linux_get_char_devices();
1218 	sbuf_printf(sb, "%s", char_devices);
1219 	linux_free_get_char_devices(char_devices);
1220 
1221 	sbuf_printf(sb, "\nBlock devices:\n");
1222 
1223 	return (0);
1224 }
1225 
1226 /*
1227  * Filler function for proc/cmdline
1228  */
1229 static int
1230 linprocfs_docmdline(PFS_FILL_ARGS)
1231 {
1232 
1233 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1234 	sbuf_printf(sb, " ro root=302\n");
1235 	return (0);
1236 }
1237 
1238 /*
1239  * Filler function for proc/filesystems
1240  */
1241 static int
1242 linprocfs_dofilesystems(PFS_FILL_ARGS)
1243 {
1244 	struct vfsconf *vfsp;
1245 
1246 	mtx_lock(&Giant);
1247 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1248 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1249 			sbuf_printf(sb, "nodev");
1250 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1251 	}
1252 	mtx_unlock(&Giant);
1253 	return(0);
1254 }
1255 
1256 #if 0
1257 /*
1258  * Filler function for proc/modules
1259  */
1260 static int
1261 linprocfs_domodules(PFS_FILL_ARGS)
1262 {
1263 	struct linker_file *lf;
1264 
1265 	TAILQ_FOREACH(lf, &linker_files, link) {
1266 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1267 		    (unsigned long)lf->size, lf->refs);
1268 	}
1269 	return (0);
1270 }
1271 #endif
1272 
1273 /*
1274  * Filler function for proc/pid/fd
1275  */
1276 static int
1277 linprocfs_dofdescfs(PFS_FILL_ARGS)
1278 {
1279 
1280 	if (p == curproc)
1281 		sbuf_printf(sb, "/dev/fd");
1282 	else
1283 		sbuf_printf(sb, "unknown");
1284 	return (0);
1285 }
1286 
1287 /*
1288  * Constructor
1289  */
1290 static int
1291 linprocfs_init(PFS_INIT_ARGS)
1292 {
1293 	struct pfs_node *root;
1294 	struct pfs_node *dir;
1295 
1296 	root = pi->pi_root;
1297 
1298 	/* /proc/... */
1299 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1300 	    NULL, NULL, NULL, PFS_RD);
1301 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1302 	    NULL, NULL, NULL, PFS_RD);
1303 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1304 	    NULL, NULL, NULL, PFS_RD);
1305 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1306 	    NULL, NULL, NULL, PFS_RD);
1307 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1308 	    NULL, NULL, NULL, PFS_RD);
1309 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1310 	    NULL, NULL, NULL, PFS_RD);
1311 #if 0
1312 	pfs_create_file(root, "modules", &linprocfs_domodules,
1313 	    NULL, NULL, NULL, PFS_RD);
1314 #endif
1315 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1316 	    NULL, NULL, NULL, PFS_RD);
1317 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1318 	    NULL, NULL, NULL, PFS_RD);
1319 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1320 	    NULL, NULL, NULL, PFS_RD);
1321 	pfs_create_link(root, "self", &procfs_docurproc,
1322 	    NULL, NULL, NULL, 0);
1323 	pfs_create_file(root, "stat", &linprocfs_dostat,
1324 	    NULL, NULL, NULL, PFS_RD);
1325 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1326 	    NULL, NULL, NULL, PFS_RD);
1327 	pfs_create_file(root, "version", &linprocfs_doversion,
1328 	    NULL, NULL, NULL, PFS_RD);
1329 
1330 	/* /proc/net/... */
1331 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1332 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1333 	    NULL, NULL, NULL, PFS_RD);
1334 
1335 	/* /proc/<pid>/... */
1336 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1337 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1338 	    NULL, NULL, NULL, PFS_RD);
1339 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1340 	    NULL, NULL, NULL, 0);
1341 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1342 	    NULL, NULL, NULL, PFS_RD);
1343 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1344 	    NULL, &procfs_notsystem, NULL, 0);
1345 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1346 	    NULL, NULL, NULL, PFS_RD);
1347 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1348 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1349 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1350 	    NULL, NULL, NULL, 0);
1351 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1352 	    NULL, NULL, NULL, PFS_RD);
1353 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1354 	    NULL, NULL, NULL, PFS_RD);
1355 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1356 	    NULL, NULL, NULL, PFS_RD);
1357 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1358 	    NULL, NULL, NULL, 0);
1359 
1360 	/* /proc/scsi/... */
1361 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1362 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1363 	    NULL, NULL, NULL, PFS_RD);
1364 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1365 	    NULL, NULL, NULL, PFS_RD);
1366 
1367 	/* /proc/sys/... */
1368 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1369 	/* /proc/sys/kernel/... */
1370 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1371 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1372 	    NULL, NULL, NULL, PFS_RD);
1373 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1374 	    NULL, NULL, NULL, PFS_RD);
1375 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1376 	    NULL, NULL, NULL, PFS_RD);
1377 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1378 	    NULL, NULL, NULL, PFS_RD);
1379 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1380 	    NULL, NULL, NULL, PFS_RD);
1381 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1382 	    NULL, NULL, NULL, PFS_RD);
1383 
1384 	return (0);
1385 }
1386 
1387 /*
1388  * Destructor
1389  */
1390 static int
1391 linprocfs_uninit(PFS_INIT_ARGS)
1392 {
1393 
1394 	/* nothing to do, pseudofs will GC */
1395 	return (0);
1396 }
1397 
1398 PSEUDOFS(linprocfs, 1);
1399 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1400 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1401 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1402 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1403