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