linprocfs.c revision 209059
1139743Simp/*-
2184691Sdes * Copyright (c) 2000 Dag-Erling Co��dan Sm��rgrav
365577Sdes * Copyright (c) 1999 Pierre Beyssac
459412Smsmith * Copyright (c) 1993 Jan-Simon Pendry
559412Smsmith * Copyright (c) 1993
659412Smsmith *	The Regents of the University of California.  All rights reserved.
759412Smsmith *
859412Smsmith * This code is derived from software contributed to Berkeley by
959412Smsmith * Jan-Simon Pendry.
1059412Smsmith *
1159412Smsmith * Redistribution and use in source and binary forms, with or without
1259412Smsmith * modification, are permitted provided that the following conditions
1359412Smsmith * are met:
1459412Smsmith * 1. Redistributions of source code must retain the above copyright
1559412Smsmith *    notice, this list of conditions and the following disclaimer.
1659412Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1759412Smsmith *    notice, this list of conditions and the following disclaimer in the
1859412Smsmith *    documentation and/or other materials provided with the distribution.
1959412Smsmith * 3. All advertising materials mentioning features or use of this software
2059412Smsmith *    must display the following acknowledgement:
2159412Smsmith *	This product includes software developed by the University of
2259412Smsmith *	California, Berkeley and its contributors.
2359412Smsmith * 4. Neither the name of the University nor the names of its contributors
2459412Smsmith *    may be used to endorse or promote products derived from this software
2559412Smsmith *    without specific prior written permission.
2659412Smsmith *
2759412Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2859412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2959412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3059412Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3159412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3259412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3359412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3459412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3559412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3659412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3759412Smsmith * SUCH DAMAGE.
3859412Smsmith *
3959412Smsmith *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
4059412Smsmith */
4159412Smsmith
42182141Sjulian#include "opt_compat.h"
43182141Sjulian
44116173Sobrien#include <sys/cdefs.h>
45116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 209059 2010-06-11 18:46:34Z jhb $");
46116173Sobrien
4759412Smsmith#include <sys/param.h>
4883926Sdes#include <sys/queue.h>
4976166Smarkm#include <sys/blist.h>
5074135Sjlemon#include <sys/conf.h>
5183926Sdes#include <sys/exec.h>
52177785Skib#include <sys/fcntl.h>
53119911Sdes#include <sys/filedesc.h>
5476166Smarkm#include <sys/jail.h>
5565633Sdes#include <sys/kernel.h>
5683926Sdes#include <sys/linker.h>
5776166Smarkm#include <sys/lock.h>
5874135Sjlemon#include <sys/malloc.h>
5978025Sdes#include <sys/mount.h>
60168067Sjkim#include <sys/msg.h>
6176827Salfred#include <sys/mutex.h>
6285289Sdes#include <sys/namei.h>
6365633Sdes#include <sys/proc.h>
6465633Sdes#include <sys/resourcevar.h>
6569995Sdes#include <sys/sbuf.h>
66168067Sjkim#include <sys/sem.h>
67123246Sdes#include <sys/smp.h>
6883926Sdes#include <sys/socket.h>
6976839Sjlemon#include <sys/sysctl.h>
7083926Sdes#include <sys/systm.h>
71159995Snetchild#include <sys/time.h>
7265633Sdes#include <sys/tty.h>
7383926Sdes#include <sys/user.h>
7483926Sdes#include <sys/vmmeter.h>
7559412Smsmith#include <sys/vnode.h>
76190445Sambrisko#include <sys/bus.h>
7759412Smsmith
7883926Sdes#include <net/if.h>
79185571Sbz#include <net/vnet.h>
8083926Sdes
8159412Smsmith#include <vm/vm.h>
82185984Skib#include <vm/vm_extern.h>
8359412Smsmith#include <vm/pmap.h>
8467588Sdes#include <vm/vm_map.h>
8559412Smsmith#include <vm/vm_param.h>
8660860Sdes#include <vm/vm_object.h>
8759412Smsmith#include <vm/swap_pager.h>
8869799Sdes
8967589Sdes#include <machine/clock.h>
9078113Sdes
91190445Sambrisko#include <geom/geom.h>
92190445Sambrisko#include <geom/geom_int.h>
93190445Sambrisko
94133822Stjr#if defined(__i386__) || defined(__amd64__)
9567589Sdes#include <machine/cputypes.h>
9659412Smsmith#include <machine/md_var.h>
97133822Stjr#endif /* __i386__ || __amd64__ */
9859412Smsmith
99140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
100140214Sobrien#include <machine/../linux32/linux.h>
101140214Sobrien#else
10287275Srwatson#include <machine/../linux/linux.h>
103133822Stjr#endif
10485129Sdes#include <compat/linux/linux_ioctl.h>
10569995Sdes#include <compat/linux/linux_mib.h>
10685289Sdes#include <compat/linux/linux_util.h>
10778025Sdes#include <fs/pseudofs/pseudofs.h>
10884248Sdes#include <fs/procfs/procfs.h>
10959412Smsmith
11067588Sdes/*
11167588Sdes * Various conversion macros
11267588Sdes */
113206081Snetchild#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to jiffies */
114206081Snetchild#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to centiseconds */
11567588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11667588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11769799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11867588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11967588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
120206081Snetchild#define TV2J(x)	((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
12174135Sjlemon
122159995Snetchild/**
123159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
124159995Snetchild *
125159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
126159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
127172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
128159995Snetchild * or stopped, or process is paging respectively.
129159995Snetchild *
130159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
131159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
132159995Snetchild *
133159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
134159995Snetchild * map our states to suitable linux states.
135159995Snetchild */
136166140Snetchildstatic char linux_state[] = "RRSTZDD";
137159995Snetchild
13878113Sdes/*
13978113Sdes * Filler function for proc/meminfo
14078113Sdes */
14178025Sdesstatic int
14278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
14359412Smsmith{
14459412Smsmith	unsigned long memtotal;		/* total memory in bytes */
14559412Smsmith	unsigned long memused;		/* used memory in bytes */
14659412Smsmith	unsigned long memfree;		/* free memory in bytes */
14759412Smsmith	unsigned long memshared;	/* shared memory ??? */
14859412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
149113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
150113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
151113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
15260860Sdes	vm_object_t object;
153117723Sphk	int i, j;
15459412Smsmith
15559412Smsmith	memtotal = physmem * PAGE_SIZE;
15659412Smsmith	/*
15759412Smsmith	 * The correct thing here would be:
15859412Smsmith	 *
159170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
16059412Smsmith	memused = memtotal - memfree;
16159412Smsmith	 *
16259412Smsmith	 * but it might mislead linux binaries into thinking there
16359412Smsmith	 * is very little memory left, so we cheat and tell them that
16459412Smsmith	 * all memory that isn't wired down is free.
16559412Smsmith	 */
166170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
16759412Smsmith	memfree = memtotal - memused;
168117723Sphk	swap_pager_status(&i, &j);
169153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
170153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
171117723Sphk	swapfree = swaptotal - swapused;
17260860Sdes	memshared = 0;
173124082Salc	mtx_lock(&vm_object_list_mtx);
17471471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
17560860Sdes		if (object->shadow_count > 1)
17660860Sdes			memshared += object->resident_page_count;
177124082Salc	mtx_unlock(&vm_object_list_mtx);
17860860Sdes	memshared *= PAGE_SIZE;
17959412Smsmith	/*
18059412Smsmith	 * We'd love to be able to write:
18159412Smsmith	 *
18259412Smsmith	buffers = bufspace;
18359412Smsmith	 *
18459412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
18559412Smsmith	 * like unstaticizing it just for linprocfs's sake.
18659412Smsmith	 */
18759412Smsmith	buffers = 0;
188170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18959412Smsmith
19078025Sdes	sbuf_printf(sb,
19178031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
19269799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
19376839Sjlemon	    "Swap: %llu %llu %llu\n"
19469799Sdes	    "MemTotal: %9lu kB\n"
19569799Sdes	    "MemFree:  %9lu kB\n"
19669799Sdes	    "MemShared:%9lu kB\n"
19769799Sdes	    "Buffers:  %9lu kB\n"
19869799Sdes	    "Cached:   %9lu kB\n"
19976839Sjlemon	    "SwapTotal:%9llu kB\n"
20076839Sjlemon	    "SwapFree: %9llu kB\n",
20169799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
20269799Sdes	    swaptotal, swapused, swapfree,
20369799Sdes	    B2K(memtotal), B2K(memfree),
20469799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
20569799Sdes	    B2K(swaptotal), B2K(swapfree));
20659412Smsmith
20778025Sdes	return (0);
20859412Smsmith}
20959412Smsmith
210133822Stjr#if defined(__i386__) || defined(__amd64__)
21178113Sdes/*
212133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
21378113Sdes */
21478113Sdesstatic int
21578113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
21678113Sdes{
217159544Sdes	int hw_model[2];
218159544Sdes	char model[128];
219159544Sdes	size_t size;
220123246Sdes	int class, fqmhz, fqkhz;
221118421Sdes	int i;
22259412Smsmith
22369799Sdes	/*
22478031Sdes	 * We default the flags to include all non-conflicting flags,
22578031Sdes	 * and the Intel versions of conflicting flags.
22669799Sdes	 */
22778031Sdes	static char *flags[] = {
22878031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22978031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
23078031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
23178031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
23278031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
233183385Scognet		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
23467589Sdes		"3dnowext", "3dnow"
23567589Sdes	};
23667589Sdes
23759412Smsmith	switch (cpu_class) {
238133822Stjr#ifdef __i386__
23959412Smsmith	case CPUCLASS_286:
24067589Sdes		class = 2;
24159412Smsmith		break;
24259412Smsmith	case CPUCLASS_386:
24367589Sdes		class = 3;
24459412Smsmith		break;
24559412Smsmith	case CPUCLASS_486:
24667589Sdes		class = 4;
24759412Smsmith		break;
24859412Smsmith	case CPUCLASS_586:
24967589Sdes		class = 5;
25059412Smsmith		break;
25159412Smsmith	case CPUCLASS_686:
25267589Sdes		class = 6;
25359412Smsmith		break;
25459412Smsmith	default:
25578031Sdes		class = 0;
25659412Smsmith		break;
257159170Sdes#else /* __amd64__ */
258133822Stjr	default:
259159170Sdes		class = 15;
260133822Stjr		break;
261133822Stjr#endif
26259412Smsmith	}
26359412Smsmith
264159544Sdes	hw_model[0] = CTL_HW;
265159544Sdes	hw_model[1] = HW_MODEL;
266159544Sdes	model[0] = '\0';
267159544Sdes	size = sizeof(model);
268159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
269159544Sdes		strcpy(model, "unknown");
270123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
271118421Sdes		sbuf_printf(sb,
272118421Sdes		    "processor\t: %d\n"
273118421Sdes		    "vendor_id\t: %.20s\n"
274118421Sdes		    "cpu family\t: %d\n"
275118421Sdes		    "model\t\t: %d\n"
276159544Sdes		    "model name\t: %s\n"
277206597Semaste		    "stepping\t: %d\n\n",
278159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
279159544Sdes		/* XXX per-cpu vendor / class / model / id? */
280118421Sdes	}
28159412Smsmith
282185766Skib	sbuf_cat(sb, "flags\t\t:");
28367589Sdes
284187594Sjkim#ifdef __i386__
285187594Sjkim	switch (cpu_vendor_id) {
286187594Sjkim	case CPU_VENDOR_AMD:
287187594Sjkim		if (class < 6)
288187594Sjkim			flags[16] = "fcmov";
289187594Sjkim		break;
290187594Sjkim	case CPU_VENDOR_CYRIX:
29167589Sdes		flags[24] = "cxmmx";
292187594Sjkim		break;
29378031Sdes	}
294187594Sjkim#endif
295119068Sdes
29678031Sdes	for (i = 0; i < 32; i++)
29767589Sdes		if (cpu_feature & (1 << i))
29878025Sdes			sbuf_printf(sb, " %s", flags[i]);
29978025Sdes	sbuf_cat(sb, "\n");
30078031Sdes	if (class >= 5) {
30169799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
30269799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
30378025Sdes		sbuf_printf(sb,
30469799Sdes		    "cpu MHz\t\t: %d.%02d\n"
30569799Sdes		    "bogomips\t: %d.%02d\n",
30669799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
30778031Sdes	}
30869995Sdes
30978025Sdes	return (0);
31059412Smsmith}
311133822Stjr#endif /* __i386__ || __amd64__ */
31265633Sdes
31378113Sdes/*
31485289Sdes * Filler function for proc/mtab
31585289Sdes *
31685289Sdes * This file doesn't exist in Linux' procfs, but is included here so
31785289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
31885289Sdes */
31985289Sdesstatic int
32085289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
32185289Sdes{
32285289Sdes	struct nameidata nd;
32385289Sdes	struct mount *mp;
32491334Sjulian	const char *lep;
32591334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
32685289Sdes	size_t lep_len;
32785289Sdes	int error;
32885289Sdes
32985289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
330168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
33185289Sdes	flep = NULL;
332168942Sdes	error = namei(&nd);
333184649Sjhb	lep = linux_emul_path;
334184649Sjhb	if (error == 0) {
335188579Sjhb		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
336184649Sjhb			lep = dlep;
337184649Sjhb		vrele(nd.ni_vp);
338184649Sjhb		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
339184649Sjhb	}
34085289Sdes	lep_len = strlen(lep);
341119068Sdes
34285289Sdes	mtx_lock(&mountlist_mtx);
34385289Sdes	error = 0;
34485289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
34585289Sdes		/* determine device name */
34685289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
347119068Sdes
34885289Sdes		/* determine mount point */
34985289Sdes		mntto = mp->mnt_stat.f_mntonname;
35085289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
35185289Sdes		    mntto[lep_len] == '/')
35285289Sdes			mntto += lep_len;
35385289Sdes
35485289Sdes		/* determine fs type */
35585289Sdes		fstype = mp->mnt_stat.f_fstypename;
35685289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
35785289Sdes			mntfrom = fstype = "proc";
35885289Sdes		else if (strcmp(fstype, "procfs") == 0)
35985289Sdes			continue;
360119068Sdes
361158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
362158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
363158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
364158311Sambrisko		} else {
365190445Sambrisko			/* For Linux msdosfs is called vfat */
366190445Sambrisko			if (strcmp(fstype, "msdosfs") == 0)
367190445Sambrisko				fstype = "vfat";
368158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
369158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
370158311Sambrisko		}
37185289Sdes#define ADD_OPTION(opt, name) \
37285289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
37385289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
37485289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
37585289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
37685289Sdes		ADD_OPTION(MNT_UNION,		"union");
37785289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
37885289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
37985289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
38085289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
38185289Sdes#undef ADD_OPTION
38285289Sdes		/* a real Linux mtab will also show NFS options */
38385289Sdes		sbuf_printf(sb, " 0 0\n");
38485289Sdes	}
38585289Sdes	mtx_unlock(&mountlist_mtx);
38685289Sdes	if (flep != NULL)
38785289Sdes		free(flep, M_TEMP);
38885289Sdes	return (error);
38985289Sdes}
39085289Sdes
39185289Sdes/*
392190445Sambrisko * Filler function for proc/partitions
393190445Sambrisko *
394190445Sambrisko */
395190445Sambriskostatic int
396190445Sambriskolinprocfs_dopartitions(PFS_FILL_ARGS)
397190445Sambrisko{
398190445Sambrisko	struct g_class *cp;
399190445Sambrisko	struct g_geom *gp;
400190445Sambrisko	struct g_provider *pp;
401190445Sambrisko	struct nameidata nd;
402190445Sambrisko	const char *lep;
403190445Sambrisko	char  *dlep, *flep;
404190445Sambrisko	size_t lep_len;
405190445Sambrisko	int error;
406190445Sambrisko	int major, minor;
407190445Sambrisko
408190445Sambrisko	/* resolve symlinks etc. in the emulation tree prefix */
409190445Sambrisko	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
410190445Sambrisko	flep = NULL;
411190445Sambrisko	error = namei(&nd);
412190445Sambrisko	lep = linux_emul_path;
413190445Sambrisko	if (error == 0) {
414190445Sambrisko		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
415190445Sambrisko			lep = dlep;
416190445Sambrisko		vrele(nd.ni_vp);
417190445Sambrisko		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
418190445Sambrisko	}
419190445Sambrisko	lep_len = strlen(lep);
420190445Sambrisko
421190445Sambrisko	g_topology_lock();
422190445Sambrisko	error = 0;
423190445Sambrisko	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
424190445Sambrisko	    "ruse wio wmerge wsect wuse running use aveq\n");
425190445Sambrisko
426190445Sambrisko	LIST_FOREACH(cp, &g_classes, class) {
427190445Sambrisko		if (strcmp(cp->name, "DISK") == 0 ||
428190445Sambrisko		    strcmp(cp->name, "PART") == 0)
429190445Sambrisko			LIST_FOREACH(gp, &cp->geom, geom) {
430190445Sambrisko				LIST_FOREACH(pp, &gp->provider, provider) {
431190445Sambrisko					if (linux_driver_get_major_minor(
432190445Sambrisko					    pp->name, &major, &minor) != 0) {
433190445Sambrisko						major = 0;
434190445Sambrisko						minor = 0;
435190445Sambrisko					}
436190445Sambrisko					sbuf_printf(sb, "%d %d %lld %s "
437190445Sambrisko					    "%d %d %d %d %d "
438190445Sambrisko					     "%d %d %d %d %d %d\n",
439190445Sambrisko					     major, minor,
440190445Sambrisko					     (long long)pp->mediasize, pp->name,
441190445Sambrisko					     0, 0, 0, 0, 0,
442190445Sambrisko					     0, 0, 0, 0, 0, 0);
443190445Sambrisko				}
444190445Sambrisko			}
445190445Sambrisko	}
446190445Sambrisko	g_topology_unlock();
447190445Sambrisko
448190445Sambrisko	if (flep != NULL)
449190445Sambrisko		free(flep, M_TEMP);
450190445Sambrisko	return (error);
451190445Sambrisko}
452190445Sambrisko
453190445Sambrisko
454190445Sambrisko/*
45578113Sdes * Filler function for proc/stat
45678113Sdes */
45778025Sdesstatic int
45878025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
45965633Sdes{
460174070Speter	struct pcpu *pcpu;
461174070Speter	long cp_time[CPUSTATES];
462174070Speter	long *cp;
463123246Sdes	int i;
464120339Sdes
465174070Speter	read_cpu_time(cp_time);
466120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
467120339Sdes	    T2J(cp_time[CP_USER]),
468120339Sdes	    T2J(cp_time[CP_NICE]),
469120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
470120339Sdes	    T2J(cp_time[CP_IDLE]));
471209059Sjhb	CPU_FOREACH(i) {
472174070Speter		pcpu = pcpu_find(i);
473174070Speter		cp = pcpu->pc_cp_time;
474143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
475174070Speter		    T2J(cp[CP_USER]),
476174070Speter		    T2J(cp[CP_NICE]),
477174070Speter		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
478174070Speter		    T2J(cp[CP_IDLE]));
479174070Speter	}
48078025Sdes	sbuf_printf(sb,
48169799Sdes	    "disk 0 0 0 0\n"
48269799Sdes	    "page %u %u\n"
48369799Sdes	    "swap %u %u\n"
48469799Sdes	    "intr %u\n"
48569799Sdes	    "ctxt %u\n"
48685657Sdillon	    "btime %lld\n",
487170170Sattilio	    cnt.v_vnodepgsin,
488170170Sattilio	    cnt.v_vnodepgsout,
489170170Sattilio	    cnt.v_swappgsin,
490170170Sattilio	    cnt.v_swappgsout,
491170170Sattilio	    cnt.v_intr,
492170170Sattilio	    cnt.v_swtch,
493113574Sjhb	    (long long)boottime.tv_sec);
49478025Sdes	return (0);
49565633Sdes}
49665633Sdes
49778113Sdes/*
49878113Sdes * Filler function for proc/uptime
49978113Sdes */
50078025Sdesstatic int
50178025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
50265633Sdes{
503174070Speter	long cp_time[CPUSTATES];
50465633Sdes	struct timeval tv;
50565633Sdes
50665633Sdes	getmicrouptime(&tv);
507174070Speter	read_cpu_time(cp_time);
508206081Snetchild	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
509113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
510206081Snetchild	    T2S(cp_time[CP_IDLE] / mp_ncpus),
511206081Snetchild	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
51278025Sdes	return (0);
51365633Sdes}
51465633Sdes
51578113Sdes/*
516167159Sjkim * Get OS build date
517167159Sjkim */
518167159Sjkimstatic void
519167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
520167159Sjkim{
521167159Sjkim#if 0
522167159Sjkim	char osbuild[256];
523167159Sjkim	char *cp1, *cp2;
524167159Sjkim
525167159Sjkim	strncpy(osbuild, version, 256);
526167159Sjkim	osbuild[255] = '\0';
527167159Sjkim	cp1 = strstr(osbuild, "\n");
528167159Sjkim	cp2 = strstr(osbuild, ":");
529167159Sjkim	if (cp1 && cp2) {
530167159Sjkim		*cp1 = *cp2 = '\0';
531167159Sjkim		cp1 = strstr(osbuild, "#");
532167159Sjkim	} else
533167159Sjkim		cp1 = NULL;
534167159Sjkim	if (cp1)
535167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
536167159Sjkim	else
537167159Sjkim#endif
538167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
539167159Sjkim}
540167159Sjkim
541167159Sjkim/*
542167159Sjkim * Get OS builder
543167159Sjkim */
544167159Sjkimstatic void
545167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
546167159Sjkim{
547168762Sdes#if 0
548167159Sjkim	char builder[256];
549167159Sjkim	char *cp;
550167159Sjkim
551167159Sjkim	cp = strstr(version, "\n    ");
552167159Sjkim	if (cp) {
553167159Sjkim		strncpy(builder, cp + 5, 256);
554167159Sjkim		builder[255] = '\0';
555167159Sjkim		cp = strstr(builder, ":");
556167159Sjkim		if (cp)
557167159Sjkim			*cp = '\0';
558167159Sjkim	}
559167159Sjkim	if (cp)
560167159Sjkim		sbuf_cat(sb, builder);
561167159Sjkim	else
562168762Sdes#endif
563167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
564167159Sjkim}
565167159Sjkim
566167159Sjkim/*
56778113Sdes * Filler function for proc/version
56878113Sdes */
56978025Sdesstatic int
57078025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
57165633Sdes{
57287275Srwatson	char osname[LINUX_MAX_UTSNAME];
57387275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
57487275Srwatson
575112206Sjhb	linux_get_osname(td, osname);
576112206Sjhb	linux_get_osrelease(td, osrelease);
577167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
578167159Sjkim	linprocfs_osbuilder(td, sb);
579167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
580167159Sjkim	linprocfs_osbuild(td, sb);
581167159Sjkim	sbuf_cat(sb, "\n");
58287275Srwatson
58378025Sdes	return (0);
58465633Sdes}
58565633Sdes
58678113Sdes/*
58778113Sdes * Filler function for proc/loadavg
58878113Sdes */
58978025Sdesstatic int
59078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
59176839Sjlemon{
592168762Sdes
59378025Sdes	sbuf_printf(sb,
59476839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
59576839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
59676839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
59776839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
59876839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
59976839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
60076839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
60176839Sjlemon	    1,				/* number of running tasks */
60276839Sjlemon	    nprocs,			/* number of tasks */
60378116Sdes	    lastpid			/* the last pid */
60476839Sjlemon	);
60578025Sdes	return (0);
60676839Sjlemon}
60776839Sjlemon
60878113Sdes/*
60978113Sdes * Filler function for proc/pid/stat
61078113Sdes */
61178025Sdesstatic int
61278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
61367588Sdes{
61469995Sdes	struct kinfo_proc kp;
615166140Snetchild	char state;
616166140Snetchild	static int ratelimit = 0;
617206081Snetchild	vm_offset_t startcode, startdata;
61867588Sdes
61994307Sjhb	PROC_LOCK(p);
62069995Sdes	fill_kinfo_proc(p, &kp);
621206081Snetchild	if (p->p_vmspace) {
622206081Snetchild	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
623206081Snetchild	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
624206081Snetchild	} else {
625206081Snetchild	   startcode = 0;
626206081Snetchild	   startdata = 0;
627206081Snetchild	};
62878025Sdes	sbuf_printf(sb, "%d", p->p_pid);
62978025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
63067588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
631166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
632166140Snetchild		state = 'R';
633166140Snetchild
634166141Snetchild		if (ratelimit == 0) {
635166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
636166162Snetchild			    kp.ki_stat, sizeof(linux_state));
637166141Snetchild			++ratelimit;
638166141Snetchild		}
639166140Snetchild	} else
640166140Snetchild		state = linux_state[kp.ki_stat - 1];
641166140Snetchild	PS_ADD("state",		"%c",	state);
64273923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
64367588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
64467588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
64591140Stanimura	PROC_UNLOCK(p);
646206081Snetchild	PS_ADD("tty",		"%d",	kp.ki_tdev);
647159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
64867588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
649159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
650159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
651159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
652159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
653206081Snetchild	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
654206081Snetchild	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
655206081Snetchild	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
656206081Snetchild	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
657159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
658159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
659159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
660159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
661206081Snetchild	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
662159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
663159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
664159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
665206081Snetchild	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
666206081Snetchild	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
66767588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
668159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
669159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
670159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
671159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
672159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
673159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
67467588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
675159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
676159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
67769799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
678159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
679159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
680159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
68167588Sdes#undef PS_ADD
68278025Sdes	sbuf_putc(sb, '\n');
683119068Sdes
68478025Sdes	return (0);
68567588Sdes}
68667588Sdes
68767588Sdes/*
688119911Sdes * Filler function for proc/pid/statm
689119911Sdes */
690119911Sdesstatic int
691119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
692119911Sdes{
693119911Sdes	struct kinfo_proc kp;
694119911Sdes	segsz_t lsize;
695120340Sdes
696119911Sdes	PROC_LOCK(p);
697119911Sdes	fill_kinfo_proc(p, &kp);
698119911Sdes	PROC_UNLOCK(p);
699119911Sdes
700119911Sdes	/*
701119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
702119911Sdes	 * computation of lsize.
703119911Sdes	 */
704119911Sdes	/* size resident share trs drs lrs dt */
705119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
706119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
707119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
708119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
709119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
710119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
711119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
712119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
713119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
714119911Sdes
715119911Sdes	return (0);
716119911Sdes}
717119911Sdes
718119911Sdes/*
71978113Sdes * Filler function for proc/pid/status
72078113Sdes */
72178025Sdesstatic int
72278025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
72367588Sdes{
72469995Sdes	struct kinfo_proc kp;
72567588Sdes	char *state;
72669799Sdes	segsz_t lsize;
72799072Sjulian	struct thread *td2;
728114983Sjhb	struct sigacts *ps;
72974135Sjlemon	int i;
73067588Sdes
731113611Sjhb	PROC_LOCK(p);
73299072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
73399072Sjulian
73499072Sjulian	if (P_SHOULDSTOP(p)) {
73599072Sjulian		state = "T (stopped)";
73699072Sjulian	} else {
737170307Sjeff		PROC_SLOCK(p);
73899072Sjulian		switch(p->p_state) {
73999072Sjulian		case PRS_NEW:
74099072Sjulian			state = "I (idle)";
74199072Sjulian			break;
74299072Sjulian		case PRS_NORMAL:
74399072Sjulian			if (p->p_flag & P_WEXIT) {
74499072Sjulian				state = "X (exiting)";
74599072Sjulian				break;
74699072Sjulian			}
74799072Sjulian			switch(td2->td_state) {
748103216Sjulian			case TDS_INHIBITED:
74999072Sjulian				state = "S (sleeping)";
75099072Sjulian				break;
75199072Sjulian			case TDS_RUNQ:
75299072Sjulian			case TDS_RUNNING:
75399072Sjulian				state = "R (running)";
75499072Sjulian				break;
75599072Sjulian			default:
75699072Sjulian				state = "? (unknown)";
75799072Sjulian				break;
75899072Sjulian			}
75999072Sjulian			break;
76099072Sjulian		case PRS_ZOMBIE:
76199072Sjulian			state = "Z (zombie)";
76299072Sjulian			break;
76399072Sjulian		default:
76499072Sjulian			state = "? (unknown)";
76599072Sjulian			break;
76699072Sjulian		}
767170307Sjeff		PROC_SUNLOCK(p);
76899072Sjulian	}
76967588Sdes
77069995Sdes	fill_kinfo_proc(p, &kp);
77178025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
77278031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
77367588Sdes
77467588Sdes	/*
77567588Sdes	 * Credentials
77667588Sdes	 */
77778025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
77878025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
77973923Sjhb						p->p_pptr->p_pid : 0);
78078031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
78178031Sdes						p->p_ucred->cr_uid,
78278031Sdes						p->p_ucred->cr_svuid,
78378031Sdes						/* FreeBSD doesn't have fsuid */
78478031Sdes						p->p_ucred->cr_uid);
78578031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
78678031Sdes						p->p_ucred->cr_gid,
78778031Sdes						p->p_ucred->cr_svgid,
78878031Sdes						/* FreeBSD doesn't have fsgid */
78978031Sdes						p->p_ucred->cr_gid);
79078025Sdes	sbuf_cat(sb, "Groups:\t");
79167588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
79278031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
79371471Sjhb	PROC_UNLOCK(p);
79478025Sdes	sbuf_putc(sb, '\n');
795119068Sdes
79667588Sdes	/*
79767588Sdes	 * Memory
79869799Sdes	 *
79969799Sdes	 * While our approximation of VmLib may not be accurate (I
80069799Sdes	 * don't know of a simple way to verify it, and I'm not sure
80169799Sdes	 * it has much meaning anyway), I believe it's good enough.
80269799Sdes	 *
80369799Sdes	 * The same code that could (I think) accurately compute VmLib
80469799Sdes	 * could also compute VmLck, but I don't really care enough to
80569799Sdes	 * implement it. Submissions are welcome.
80667588Sdes	 */
807113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
80878025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
809206081Snetchild	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
810113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
811113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
812113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
81369995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
81469995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
815113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
81667588Sdes
81767588Sdes	/*
81867588Sdes	 * Signal masks
81967588Sdes	 *
82067588Sdes	 * We support up to 128 signals, while Linux supports 32,
82167588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
82267588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
82367588Sdes	 *
82467588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
82567588Sdes	 * supports 64 signals, but this code is a long way from
82667588Sdes	 * running on anything but i386, so ignore that for now.
82767588Sdes	 */
82871471Sjhb	PROC_LOCK(p);
829104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
83069799Sdes	/*
83169799Sdes	 * I can't seem to find out where the signal mask is in
83269799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
83369799Sdes	 */
83478025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
835114983Sjhb	ps = p->p_sigacts;
836114983Sjhb	mtx_lock(&ps->ps_mtx);
837114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
838114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
839114983Sjhb	mtx_unlock(&ps->ps_mtx);
84071471Sjhb	PROC_UNLOCK(p);
841119068Sdes
84267588Sdes	/*
84367588Sdes	 * Linux also prints the capability masks, but we don't have
84467588Sdes	 * capabilities yet, and when we do get them they're likely to
84567588Sdes	 * be meaningless to Linux programs, so we lie. XXX
84667588Sdes	 */
84778025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
84878025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
84978025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
850119068Sdes
85178025Sdes	return (0);
85267588Sdes}
85374135Sjlemon
854119911Sdes
85578113Sdes/*
856119911Sdes * Filler function for proc/pid/cwd
857119911Sdes */
858119911Sdesstatic int
859119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
860119911Sdes{
861119911Sdes	char *fullpath = "unknown";
862119911Sdes	char *freepath = NULL;
863119911Sdes
864119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
865119911Sdes	sbuf_printf(sb, "%s", fullpath);
866119911Sdes	if (freepath)
867119911Sdes		free(freepath, M_TEMP);
868119911Sdes	return (0);
869119911Sdes}
870119911Sdes
871119911Sdes/*
872119911Sdes * Filler function for proc/pid/root
873119911Sdes */
874119911Sdesstatic int
875119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
876119911Sdes{
877119911Sdes	struct vnode *rvp;
878119911Sdes	char *fullpath = "unknown";
879119911Sdes	char *freepath = NULL;
880119911Sdes
881119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
882119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
883119911Sdes	sbuf_printf(sb, "%s", fullpath);
884119911Sdes	if (freepath)
885119911Sdes		free(freepath, M_TEMP);
886119911Sdes	return (0);
887119911Sdes}
888119911Sdes
889119911Sdes/*
89078113Sdes * Filler function for proc/pid/cmdline
89178113Sdes */
89278025Sdesstatic int
89378113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
89478113Sdes{
89578113Sdes	struct ps_strings pstr;
896138281Scperciva	char **ps_argvstr;
89778113Sdes	int error, i;
89878113Sdes
89978113Sdes	/*
90078113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
90178113Sdes	 * revert back to the old way which only implements full cmdline
90278113Sdes	 * for the currept process and just p->p_comm for all other
90378113Sdes	 * processes.
90478113Sdes	 * Note that if the argv is no longer available, we deliberately
90578113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
90678113Sdes	 * Linux behaviour is to return zero-length in this case.
90778113Sdes	 */
90878113Sdes
90994620Sjhb	PROC_LOCK(p);
910127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
91194620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
91294620Sjhb		PROC_UNLOCK(p);
91394620Sjhb	} else if (p != td->td_proc) {
91494620Sjhb		PROC_UNLOCK(p);
91594620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
91694620Sjhb	} else {
91794620Sjhb		PROC_UNLOCK(p);
918103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
919103767Sjake		    sizeof(pstr));
92094620Sjhb		if (error)
92194620Sjhb			return (error);
922138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
923138281Scperciva			return (E2BIG);
924138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
925138281Scperciva		    M_TEMP, M_WAITOK);
926138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
927138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
928138281Scperciva		if (error) {
929138281Scperciva			free(ps_argvstr, M_TEMP);
930138281Scperciva			return (error);
931138281Scperciva		}
93294620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
933138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
93494620Sjhb			sbuf_printf(sb, "%c", '\0');
93578113Sdes		}
936138281Scperciva		free(ps_argvstr, M_TEMP);
93778113Sdes	}
93878113Sdes
93978113Sdes	return (0);
94078113Sdes}
94178113Sdes
94278113Sdes/*
943116173Sobrien * Filler function for proc/pid/environ
944116173Sobrien */
945116173Sobrienstatic int
946116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
947116173Sobrien{
948168762Sdes
949116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
950116173Sobrien	return (0);
951116173Sobrien}
952116173Sobrien
953116173Sobrien/*
954116173Sobrien * Filler function for proc/pid/maps
955116173Sobrien */
956116173Sobrienstatic int
957116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
958116173Sobrien{
959185984Skib	struct vmspace *vm;
960185984Skib	vm_map_t map;
961185765Skib	vm_map_entry_t entry, tmp_entry;
962121265Scognet	vm_object_t obj, tobj, lobj;
963185765Skib	vm_offset_t e_start, e_end;
964121265Scognet	vm_ooffset_t off = 0;
965185765Skib	vm_prot_t e_prot;
966185765Skib	unsigned int last_timestamp;
967121265Scognet	char *name = "", *freename = NULL;
968121265Scognet	ino_t ino;
969121265Scognet	int ref_count, shadow_count, flags;
970121265Scognet	int error;
971137507Sphk	struct vnode *vp;
972137507Sphk	struct vattr vat;
973161094Skib	int locked;
974168762Sdes
975121246Scognet	PROC_LOCK(p);
976121246Scognet	error = p_candebug(td, p);
977121246Scognet	PROC_UNLOCK(p);
978121246Scognet	if (error)
979121246Scognet		return (error);
980168762Sdes
981121246Scognet	if (uio->uio_rw != UIO_READ)
982121246Scognet		return (EOPNOTSUPP);
983168762Sdes
984121246Scognet	error = 0;
985185984Skib	vm = vmspace_acquire_ref(p);
986185984Skib	if (vm == NULL)
987185984Skib		return (ESRCH);
988185984Skib	map = &vm->vm_map;
989169156Salc	vm_map_lock_read(map);
990183600Skib	for (entry = map->header.next; entry != &map->header;
991121246Scognet	    entry = entry->next) {
992121265Scognet		name = "";
993121265Scognet		freename = NULL;
994121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
995121246Scognet			continue;
996185765Skib		e_prot = entry->protection;
997185765Skib		e_start = entry->start;
998185765Skib		e_end = entry->end;
999121246Scognet		obj = entry->object.vm_object;
1000169156Salc		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1001169156Salc			VM_OBJECT_LOCK(tobj);
1002169156Salc			if (lobj != obj)
1003169156Salc				VM_OBJECT_UNLOCK(lobj);
1004121246Scognet			lobj = tobj;
1005169156Salc		}
1006185765Skib		last_timestamp = map->timestamp;
1007185765Skib		vm_map_unlock_read(map);
1008121246Scognet		ino = 0;
1009121246Scognet		if (lobj) {
1010121246Scognet			off = IDX_TO_OFF(lobj->size);
1011161094Skib			if (lobj->type == OBJT_VNODE) {
1012161094Skib				vp = lobj->handle;
1013161094Skib				if (vp)
1014161094Skib					vref(vp);
1015121246Scognet			}
1016161094Skib			else
1017161094Skib				vp = NULL;
1018169156Salc			if (lobj != obj)
1019169156Salc				VM_OBJECT_UNLOCK(lobj);
1020121246Scognet			flags = obj->flags;
1021121246Scognet			ref_count = obj->ref_count;
1022121246Scognet			shadow_count = obj->shadow_count;
1023169156Salc			VM_OBJECT_UNLOCK(obj);
1024161094Skib			if (vp) {
1025161094Skib				vn_fullpath(td, vp, &name, &freename);
1026161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
1027175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
1028182371Sattilio				VOP_GETATTR(vp, &vat, td->td_ucred);
1029161094Skib				ino = vat.va_fileid;
1030161094Skib				vput(vp);
1031161094Skib				VFS_UNLOCK_GIANT(locked);
1032161094Skib			}
1033121246Scognet		} else {
1034121246Scognet			flags = 0;
1035121246Scognet			ref_count = 0;
1036121246Scognet			shadow_count = 0;
1037121246Scognet		}
1038168762Sdes
1039121246Scognet		/*
1040168762Sdes		 * format:
1041121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
1042121246Scognet		 */
1043183600Skib		error = sbuf_printf(sb,
1044121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1045185765Skib		    (u_long)e_start, (u_long)e_end,
1046185765Skib		    (e_prot & VM_PROT_READ)?"r":"-",
1047185765Skib		    (e_prot & VM_PROT_WRITE)?"w":"-",
1048185765Skib		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1049121246Scognet		    "p",
1050121265Scognet		    (u_long)off,
1051121246Scognet		    0,
1052121246Scognet		    0,
1053121265Scognet		    (u_long)ino,
1054121246Scognet		    *name ? "     " : "",
1055121246Scognet		    name
1056121246Scognet		    );
1057121246Scognet		if (freename)
1058121246Scognet			free(freename, M_TEMP);
1059185864Skib		vm_map_lock_read(map);
1060183600Skib		if (error == -1) {
1061183600Skib			error = 0;
1062121246Scognet			break;
1063169156Salc		}
1064186563Skib		if (last_timestamp != map->timestamp) {
1065185765Skib			/*
1066185765Skib			 * Look again for the entry because the map was
1067185765Skib			 * modified while it was unlocked.  Specifically,
1068185765Skib			 * the entry may have been clipped, merged, or deleted.
1069185765Skib			 */
1070185765Skib			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1071185765Skib			entry = tmp_entry;
1072185765Skib		}
1073121246Scognet	}
1074169156Salc	vm_map_unlock_read(map);
1075185984Skib	vmspace_free(vm);
1076168762Sdes
1077121246Scognet	return (error);
1078168762Sdes}
1079168762Sdes
1080116173Sobrien/*
108178113Sdes * Filler function for proc/net/dev
108278113Sdes */
108378025Sdesstatic int
108478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
108574135Sjlemon{
108685129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
108774135Sjlemon	struct ifnet *ifp;
108874135Sjlemon
108985129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
109083926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
109185129Sdes	    "bytes    packets errs drop fifo frame compressed",
109283926Sdes	    "bytes    packets errs drop fifo frame compressed");
109374135Sjlemon
1094196635Szec	CURVNET_SET(TD_TO_VNET(curthread));
1095108172Shsu	IFNET_RLOCK();
1096181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
109785129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
109885129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
109983926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
110083926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
110183926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
110283926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
110374135Sjlemon	}
1104108172Shsu	IFNET_RUNLOCK();
1105196635Szec	CURVNET_RESTORE();
1106119068Sdes
110778025Sdes	return (0);
110874135Sjlemon}
110974135Sjlemon
1110158311Sambrisko/*
1111167159Sjkim * Filler function for proc/sys/kernel/osrelease
1112167159Sjkim */
1113167159Sjkimstatic int
1114167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1115167159Sjkim{
1116167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1117167159Sjkim
1118167159Sjkim	linux_get_osrelease(td, osrelease);
1119167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1120167159Sjkim
1121167159Sjkim	return (0);
1122167159Sjkim}
1123167159Sjkim
1124167159Sjkim/*
1125167159Sjkim * Filler function for proc/sys/kernel/ostype
1126167159Sjkim */
1127167159Sjkimstatic int
1128167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1129167159Sjkim{
1130167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1131167159Sjkim
1132167159Sjkim	linux_get_osname(td, osname);
1133167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1134167159Sjkim
1135167159Sjkim	return (0);
1136167159Sjkim}
1137167159Sjkim
1138167159Sjkim/*
1139167159Sjkim * Filler function for proc/sys/kernel/version
1140167159Sjkim */
1141167159Sjkimstatic int
1142167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1143167159Sjkim{
1144168762Sdes
1145167159Sjkim	linprocfs_osbuild(td, sb);
1146167159Sjkim	sbuf_cat(sb, "\n");
1147167159Sjkim	return (0);
1148167159Sjkim}
1149167159Sjkim
1150167159Sjkim/*
1151164692Sjkim * Filler function for proc/sys/kernel/msgmni
1152164692Sjkim */
1153164692Sjkimstatic int
1154164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1155164692Sjkim{
1156164692Sjkim
1157168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1158164692Sjkim	return (0);
1159164692Sjkim}
1160164692Sjkim
1161164692Sjkim/*
1162163251Skeramida * Filler function for proc/sys/kernel/pid_max
1163163129Snetchild */
1164163129Snetchildstatic int
1165163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1166163129Snetchild{
1167163757Snetchild
1168163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1169163129Snetchild	return (0);
1170163129Snetchild}
1171163129Snetchild
1172163129Snetchild/*
1173164692Sjkim * Filler function for proc/sys/kernel/sem
1174164692Sjkim */
1175164692Sjkimstatic int
1176164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1177164692Sjkim{
1178164692Sjkim
1179168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1180168067Sjkim	    seminfo.semopm, seminfo.semmni);
1181164692Sjkim	return (0);
1182164692Sjkim}
1183164692Sjkim
1184164692Sjkim/*
1185158311Sambrisko * Filler function for proc/scsi/device_info
1186158311Sambrisko */
1187158311Sambriskostatic int
1188158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1189158311Sambrisko{
1190168762Sdes
1191158311Sambrisko	return (0);
1192158311Sambrisko}
1193158311Sambrisko
1194158311Sambrisko/*
1195158311Sambrisko * Filler function for proc/scsi/scsi
1196158311Sambrisko */
1197158311Sambriskostatic int
1198158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1199158311Sambrisko{
1200168762Sdes
1201158311Sambrisko	return (0);
1202158311Sambrisko}
1203158311Sambrisko
120485538Sphkextern struct cdevsw *cdevsw[];
120585538Sphk
120678113Sdes/*
120778113Sdes * Filler function for proc/devices
120878113Sdes */
120978025Sdesstatic int
121078025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
121174135Sjlemon{
1212158311Sambrisko	char *char_devices;
121378025Sdes	sbuf_printf(sb, "Character devices:\n");
121474135Sjlemon
1215158311Sambrisko	char_devices = linux_get_char_devices();
1216158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1217158311Sambrisko	linux_free_get_char_devices(char_devices);
121874135Sjlemon
121978025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1220119068Sdes
122178025Sdes	return (0);
122274135Sjlemon}
122374135Sjlemon
122478113Sdes/*
122578113Sdes * Filler function for proc/cmdline
122678113Sdes */
122778025Sdesstatic int
122878025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
122974135Sjlemon{
1230168762Sdes
123178025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
123278025Sdes	sbuf_printf(sb, " ro root=302\n");
123378025Sdes	return (0);
123478025Sdes}
123574135Sjlemon
1236205541Sjhb/*
1237205541Sjhb * Filler function for proc/filesystems
1238205541Sjhb */
1239205541Sjhbstatic int
1240205541Sjhblinprocfs_dofilesystems(PFS_FILL_ARGS)
1241205541Sjhb{
1242205541Sjhb	struct vfsconf *vfsp;
1243205541Sjhb
1244205592Sjhb	mtx_lock(&Giant);
1245205541Sjhb	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1246205541Sjhb		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1247205541Sjhb			sbuf_printf(sb, "nodev");
1248205541Sjhb		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1249205541Sjhb	}
1250205592Sjhb	mtx_unlock(&Giant);
1251205541Sjhb	return(0);
1252205541Sjhb}
1253205541Sjhb
125483926Sdes#if 0
125578025Sdes/*
125683926Sdes * Filler function for proc/modules
125783926Sdes */
125883926Sdesstatic int
125983926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
126083926Sdes{
126183926Sdes	struct linker_file *lf;
1262119068Sdes
126383926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
126483926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
126583926Sdes		    (unsigned long)lf->size, lf->refs);
126683926Sdes	}
126783926Sdes	return (0);
126883926Sdes}
126983926Sdes#endif
127083926Sdes
127183926Sdes/*
1272204825Sed * Filler function for proc/pid/fd
1273204825Sed */
1274204825Sedstatic int
1275204825Sedlinprocfs_dofdescfs(PFS_FILL_ARGS)
1276204825Sed{
1277204825Sed
1278204825Sed	if (p == curproc)
1279204825Sed		sbuf_printf(sb, "/dev/fd");
1280204825Sed	else
1281204825Sed		sbuf_printf(sb, "unknown");
1282204825Sed	return (0);
1283204825Sed}
1284204825Sed
1285204825Sed/*
128685129Sdes * Constructor
128778025Sdes */
128885129Sdesstatic int
128985129Sdeslinprocfs_init(PFS_INIT_ARGS)
129085129Sdes{
129185129Sdes	struct pfs_node *root;
129285129Sdes	struct pfs_node *dir;
129374135Sjlemon
129485129Sdes	root = pi->pi_root;
129578025Sdes
1296119923Sdes	/* /proc/... */
1297119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1298167482Sdes	    NULL, NULL, NULL, PFS_RD);
1299119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1300167482Sdes	    NULL, NULL, NULL, PFS_RD);
1301119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1302167482Sdes	    NULL, NULL, NULL, PFS_RD);
1303205541Sjhb	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1304205541Sjhb	    NULL, NULL, NULL, PFS_RD);
1305119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1306167482Sdes	    NULL, NULL, NULL, PFS_RD);
1307119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1308167482Sdes	    NULL, NULL, NULL, PFS_RD);
130983926Sdes#if 0
1310119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1311167482Sdes	    NULL, NULL, NULL, PFS_RD);
131283926Sdes#endif
1313158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1314167482Sdes	    NULL, NULL, NULL, PFS_RD);
1315119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1316167482Sdes	    NULL, NULL, NULL, PFS_RD);
1317190445Sambrisko	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1318190445Sambrisko	    NULL, NULL, NULL, PFS_RD);
131987543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1320167482Sdes	    NULL, NULL, NULL, 0);
1321119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1322167482Sdes	    NULL, NULL, NULL, PFS_RD);
1323119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1324167482Sdes	    NULL, NULL, NULL, PFS_RD);
1325119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1326167482Sdes	    NULL, NULL, NULL, PFS_RD);
132778025Sdes
1328119923Sdes	/* /proc/net/... */
1329167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
133085129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1331167482Sdes	    NULL, NULL, NULL, PFS_RD);
133278025Sdes
1333119923Sdes	/* /proc/<pid>/... */
1334167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
133585129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1336167482Sdes	    NULL, NULL, NULL, PFS_RD);
1337119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1338167482Sdes	    NULL, NULL, NULL, 0);
1339116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1340167482Sdes	    NULL, NULL, NULL, PFS_RD);
134187543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1342167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1343116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1344167482Sdes	    NULL, NULL, NULL, PFS_RD);
134585129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1346167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1347119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1348167482Sdes	    NULL, NULL, NULL, 0);
134985129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1350167482Sdes	    NULL, NULL, NULL, PFS_RD);
1351119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1352167482Sdes	    NULL, NULL, NULL, PFS_RD);
135385129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1354167482Sdes	    NULL, NULL, NULL, PFS_RD);
1355204825Sed	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1356204825Sed	    NULL, NULL, NULL, 0);
135785129Sdes
1358158311Sambrisko	/* /proc/scsi/... */
1359167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1360158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1361167482Sdes	    NULL, NULL, NULL, PFS_RD);
1362158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1363167482Sdes	    NULL, NULL, NULL, PFS_RD);
1364163129Snetchild
1365163129Snetchild	/* /proc/sys/... */
1366167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1367163129Snetchild	/* /proc/sys/kernel/... */
1368167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1369167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1370167482Sdes	    NULL, NULL, NULL, PFS_RD);
1371167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1372167482Sdes	    NULL, NULL, NULL, PFS_RD);
1373167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1374167482Sdes	    NULL, NULL, NULL, PFS_RD);
1375164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1376167482Sdes	    NULL, NULL, NULL, PFS_RD);
1377163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1378167482Sdes	    NULL, NULL, NULL, PFS_RD);
1379164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1380167482Sdes	    NULL, NULL, NULL, PFS_RD);
1381163129Snetchild
138285129Sdes	return (0);
138385129Sdes}
138485129Sdes
138585129Sdes/*
138685129Sdes * Destructor
138785129Sdes */
138885129Sdesstatic int
138985129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
139085129Sdes{
139185129Sdes
139285129Sdes	/* nothing to do, pseudofs will GC */
139385129Sdes	return (0);
139485129Sdes}
139585129Sdes
139685129SdesPSEUDOFS(linprocfs, 1);
139778025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
139878025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1399168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1400168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1401