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