linprocfs.c revision 205541
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 205541 2010-03-23 21:49:33Z 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 */
11376405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
11467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11567588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11669799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11767588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11867588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11974135Sjlemon
120159995Snetchild/**
121159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
122159995Snetchild *
123159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
124159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
125172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
126159995Snetchild * or stopped, or process is paging respectively.
127159995Snetchild *
128159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
129159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
130159995Snetchild *
131159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
132159995Snetchild * map our states to suitable linux states.
133159995Snetchild */
134166140Snetchildstatic char linux_state[] = "RRSTZDD";
135159995Snetchild
13678113Sdes/*
13778113Sdes * Filler function for proc/meminfo
13878113Sdes */
13978025Sdesstatic int
14078025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
14159412Smsmith{
14259412Smsmith	unsigned long memtotal;		/* total memory in bytes */
14359412Smsmith	unsigned long memused;		/* used memory in bytes */
14459412Smsmith	unsigned long memfree;		/* free memory in bytes */
14559412Smsmith	unsigned long memshared;	/* shared memory ??? */
14659412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
147113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
148113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
149113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
15060860Sdes	vm_object_t object;
151117723Sphk	int i, j;
15259412Smsmith
15359412Smsmith	memtotal = physmem * PAGE_SIZE;
15459412Smsmith	/*
15559412Smsmith	 * The correct thing here would be:
15659412Smsmith	 *
157170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
15859412Smsmith	memused = memtotal - memfree;
15959412Smsmith	 *
16059412Smsmith	 * but it might mislead linux binaries into thinking there
16159412Smsmith	 * is very little memory left, so we cheat and tell them that
16259412Smsmith	 * all memory that isn't wired down is free.
16359412Smsmith	 */
164170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
16559412Smsmith	memfree = memtotal - memused;
166117723Sphk	swap_pager_status(&i, &j);
167153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
168153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
169117723Sphk	swapfree = swaptotal - swapused;
17060860Sdes	memshared = 0;
171124082Salc	mtx_lock(&vm_object_list_mtx);
17271471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
17360860Sdes		if (object->shadow_count > 1)
17460860Sdes			memshared += object->resident_page_count;
175124082Salc	mtx_unlock(&vm_object_list_mtx);
17660860Sdes	memshared *= PAGE_SIZE;
17759412Smsmith	/*
17859412Smsmith	 * We'd love to be able to write:
17959412Smsmith	 *
18059412Smsmith	buffers = bufspace;
18159412Smsmith	 *
18259412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
18359412Smsmith	 * like unstaticizing it just for linprocfs's sake.
18459412Smsmith	 */
18559412Smsmith	buffers = 0;
186170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18759412Smsmith
18878025Sdes	sbuf_printf(sb,
18978031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
19069799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
19176839Sjlemon	    "Swap: %llu %llu %llu\n"
19269799Sdes	    "MemTotal: %9lu kB\n"
19369799Sdes	    "MemFree:  %9lu kB\n"
19469799Sdes	    "MemShared:%9lu kB\n"
19569799Sdes	    "Buffers:  %9lu kB\n"
19669799Sdes	    "Cached:   %9lu kB\n"
19776839Sjlemon	    "SwapTotal:%9llu kB\n"
19876839Sjlemon	    "SwapFree: %9llu kB\n",
19969799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
20069799Sdes	    swaptotal, swapused, swapfree,
20169799Sdes	    B2K(memtotal), B2K(memfree),
20269799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
20369799Sdes	    B2K(swaptotal), B2K(swapfree));
20459412Smsmith
20578025Sdes	return (0);
20659412Smsmith}
20759412Smsmith
208133822Stjr#if defined(__i386__) || defined(__amd64__)
20978113Sdes/*
210133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
21178113Sdes */
21278113Sdesstatic int
21378113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
21478113Sdes{
215159544Sdes	int hw_model[2];
216159544Sdes	char model[128];
217159544Sdes	size_t size;
218123246Sdes	int class, fqmhz, fqkhz;
219118421Sdes	int i;
22059412Smsmith
22169799Sdes	/*
22278031Sdes	 * We default the flags to include all non-conflicting flags,
22378031Sdes	 * and the Intel versions of conflicting flags.
22469799Sdes	 */
22578031Sdes	static char *flags[] = {
22678031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22778031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22878031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22978031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
23078031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
231183385Scognet		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
23267589Sdes		"3dnowext", "3dnow"
23367589Sdes	};
23467589Sdes
23559412Smsmith	switch (cpu_class) {
236133822Stjr#ifdef __i386__
23759412Smsmith	case CPUCLASS_286:
23867589Sdes		class = 2;
23959412Smsmith		break;
24059412Smsmith	case CPUCLASS_386:
24167589Sdes		class = 3;
24259412Smsmith		break;
24359412Smsmith	case CPUCLASS_486:
24467589Sdes		class = 4;
24559412Smsmith		break;
24659412Smsmith	case CPUCLASS_586:
24767589Sdes		class = 5;
24859412Smsmith		break;
24959412Smsmith	case CPUCLASS_686:
25067589Sdes		class = 6;
25159412Smsmith		break;
25259412Smsmith	default:
25378031Sdes		class = 0;
25459412Smsmith		break;
255159170Sdes#else /* __amd64__ */
256133822Stjr	default:
257159170Sdes		class = 15;
258133822Stjr		break;
259133822Stjr#endif
26059412Smsmith	}
26159412Smsmith
262159544Sdes	hw_model[0] = CTL_HW;
263159544Sdes	hw_model[1] = HW_MODEL;
264159544Sdes	model[0] = '\0';
265159544Sdes	size = sizeof(model);
266159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
267159544Sdes		strcpy(model, "unknown");
268123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
269118421Sdes		sbuf_printf(sb,
270118421Sdes		    "processor\t: %d\n"
271118421Sdes		    "vendor_id\t: %.20s\n"
272118421Sdes		    "cpu family\t: %d\n"
273118421Sdes		    "model\t\t: %d\n"
274159544Sdes		    "model name\t: %s\n"
275118421Sdes		    "stepping\t: %d\n",
276159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
277159544Sdes		/* XXX per-cpu vendor / class / model / id? */
278118421Sdes	}
27959412Smsmith
280185766Skib	sbuf_cat(sb, "flags\t\t:");
28167589Sdes
282187594Sjkim#ifdef __i386__
283187594Sjkim	switch (cpu_vendor_id) {
284187594Sjkim	case CPU_VENDOR_AMD:
285187594Sjkim		if (class < 6)
286187594Sjkim			flags[16] = "fcmov";
287187594Sjkim		break;
288187594Sjkim	case CPU_VENDOR_CYRIX:
28967589Sdes		flags[24] = "cxmmx";
290187594Sjkim		break;
29178031Sdes	}
292187594Sjkim#endif
293119068Sdes
29478031Sdes	for (i = 0; i < 32; i++)
29567589Sdes		if (cpu_feature & (1 << i))
29678025Sdes			sbuf_printf(sb, " %s", flags[i]);
29778025Sdes	sbuf_cat(sb, "\n");
29878031Sdes	if (class >= 5) {
29969799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
30069799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
30178025Sdes		sbuf_printf(sb,
30269799Sdes		    "cpu MHz\t\t: %d.%02d\n"
30369799Sdes		    "bogomips\t: %d.%02d\n",
30469799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
30578031Sdes	}
30669995Sdes
30778025Sdes	return (0);
30859412Smsmith}
309133822Stjr#endif /* __i386__ || __amd64__ */
31065633Sdes
31178113Sdes/*
31285289Sdes * Filler function for proc/mtab
31385289Sdes *
31485289Sdes * This file doesn't exist in Linux' procfs, but is included here so
31585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
31685289Sdes */
31785289Sdesstatic int
31885289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
31985289Sdes{
32085289Sdes	struct nameidata nd;
32185289Sdes	struct mount *mp;
32291334Sjulian	const char *lep;
32391334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
32485289Sdes	size_t lep_len;
32585289Sdes	int error;
32685289Sdes
32785289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
328168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
32985289Sdes	flep = NULL;
330168942Sdes	error = namei(&nd);
331184649Sjhb	lep = linux_emul_path;
332184649Sjhb	if (error == 0) {
333188579Sjhb		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
334184649Sjhb			lep = dlep;
335184649Sjhb		vrele(nd.ni_vp);
336184649Sjhb		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
337184649Sjhb	}
33885289Sdes	lep_len = strlen(lep);
339119068Sdes
34085289Sdes	mtx_lock(&mountlist_mtx);
34185289Sdes	error = 0;
34285289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
34385289Sdes		/* determine device name */
34485289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
345119068Sdes
34685289Sdes		/* determine mount point */
34785289Sdes		mntto = mp->mnt_stat.f_mntonname;
34885289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
34985289Sdes		    mntto[lep_len] == '/')
35085289Sdes			mntto += lep_len;
35185289Sdes
35285289Sdes		/* determine fs type */
35385289Sdes		fstype = mp->mnt_stat.f_fstypename;
35485289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
35585289Sdes			mntfrom = fstype = "proc";
35685289Sdes		else if (strcmp(fstype, "procfs") == 0)
35785289Sdes			continue;
358119068Sdes
359158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
360158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
361158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
362158311Sambrisko		} else {
363190445Sambrisko			/* For Linux msdosfs is called vfat */
364190445Sambrisko			if (strcmp(fstype, "msdosfs") == 0)
365190445Sambrisko				fstype = "vfat";
366158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
367158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
368158311Sambrisko		}
36985289Sdes#define ADD_OPTION(opt, name) \
37085289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
37185289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
37285289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
37385289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
37485289Sdes		ADD_OPTION(MNT_UNION,		"union");
37585289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
37685289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
37785289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
37885289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
37985289Sdes#undef ADD_OPTION
38085289Sdes		/* a real Linux mtab will also show NFS options */
38185289Sdes		sbuf_printf(sb, " 0 0\n");
38285289Sdes	}
38385289Sdes	mtx_unlock(&mountlist_mtx);
38485289Sdes	if (flep != NULL)
38585289Sdes		free(flep, M_TEMP);
38685289Sdes	return (error);
38785289Sdes}
38885289Sdes
38985289Sdes/*
390190445Sambrisko * Filler function for proc/partitions
391190445Sambrisko *
392190445Sambrisko */
393190445Sambriskostatic int
394190445Sambriskolinprocfs_dopartitions(PFS_FILL_ARGS)
395190445Sambrisko{
396190445Sambrisko	struct g_class *cp;
397190445Sambrisko	struct g_geom *gp;
398190445Sambrisko	struct g_provider *pp;
399190445Sambrisko	struct nameidata nd;
400190445Sambrisko	const char *lep;
401190445Sambrisko	char  *dlep, *flep;
402190445Sambrisko	size_t lep_len;
403190445Sambrisko	int error;
404190445Sambrisko	int major, minor;
405190445Sambrisko
406190445Sambrisko	/* resolve symlinks etc. in the emulation tree prefix */
407190445Sambrisko	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
408190445Sambrisko	flep = NULL;
409190445Sambrisko	error = namei(&nd);
410190445Sambrisko	lep = linux_emul_path;
411190445Sambrisko	if (error == 0) {
412190445Sambrisko		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
413190445Sambrisko			lep = dlep;
414190445Sambrisko		vrele(nd.ni_vp);
415190445Sambrisko		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
416190445Sambrisko	}
417190445Sambrisko	lep_len = strlen(lep);
418190445Sambrisko
419190445Sambrisko	g_topology_lock();
420190445Sambrisko	error = 0;
421190445Sambrisko	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
422190445Sambrisko	    "ruse wio wmerge wsect wuse running use aveq\n");
423190445Sambrisko
424190445Sambrisko	LIST_FOREACH(cp, &g_classes, class) {
425190445Sambrisko		if (strcmp(cp->name, "DISK") == 0 ||
426190445Sambrisko		    strcmp(cp->name, "PART") == 0)
427190445Sambrisko			LIST_FOREACH(gp, &cp->geom, geom) {
428190445Sambrisko				LIST_FOREACH(pp, &gp->provider, provider) {
429190445Sambrisko					if (linux_driver_get_major_minor(
430190445Sambrisko					    pp->name, &major, &minor) != 0) {
431190445Sambrisko						major = 0;
432190445Sambrisko						minor = 0;
433190445Sambrisko					}
434190445Sambrisko					sbuf_printf(sb, "%d %d %lld %s "
435190445Sambrisko					    "%d %d %d %d %d "
436190445Sambrisko					     "%d %d %d %d %d %d\n",
437190445Sambrisko					     major, minor,
438190445Sambrisko					     (long long)pp->mediasize, pp->name,
439190445Sambrisko					     0, 0, 0, 0, 0,
440190445Sambrisko					     0, 0, 0, 0, 0, 0);
441190445Sambrisko				}
442190445Sambrisko			}
443190445Sambrisko	}
444190445Sambrisko	g_topology_unlock();
445190445Sambrisko
446190445Sambrisko	if (flep != NULL)
447190445Sambrisko		free(flep, M_TEMP);
448190445Sambrisko	return (error);
449190445Sambrisko}
450190445Sambrisko
451190445Sambrisko
452190445Sambrisko/*
45378113Sdes * Filler function for proc/stat
45478113Sdes */
45578025Sdesstatic int
45678025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
45765633Sdes{
458174070Speter	struct pcpu *pcpu;
459174070Speter	long cp_time[CPUSTATES];
460174070Speter	long *cp;
461123246Sdes	int i;
462120339Sdes
463174070Speter	read_cpu_time(cp_time);
464120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
465120339Sdes	    T2J(cp_time[CP_USER]),
466120339Sdes	    T2J(cp_time[CP_NICE]),
467120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
468120339Sdes	    T2J(cp_time[CP_IDLE]));
469174070Speter	for (i = 0; i <= mp_maxid; ++i) {
470174070Speter		if (CPU_ABSENT(i))
471174070Speter			continue;
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);
50885657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
509113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
51069799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
51178025Sdes	return (0);
51265633Sdes}
51365633Sdes
51478113Sdes/*
515167159Sjkim * Get OS build date
516167159Sjkim */
517167159Sjkimstatic void
518167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
519167159Sjkim{
520167159Sjkim#if 0
521167159Sjkim	char osbuild[256];
522167159Sjkim	char *cp1, *cp2;
523167159Sjkim
524167159Sjkim	strncpy(osbuild, version, 256);
525167159Sjkim	osbuild[255] = '\0';
526167159Sjkim	cp1 = strstr(osbuild, "\n");
527167159Sjkim	cp2 = strstr(osbuild, ":");
528167159Sjkim	if (cp1 && cp2) {
529167159Sjkim		*cp1 = *cp2 = '\0';
530167159Sjkim		cp1 = strstr(osbuild, "#");
531167159Sjkim	} else
532167159Sjkim		cp1 = NULL;
533167159Sjkim	if (cp1)
534167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
535167159Sjkim	else
536167159Sjkim#endif
537167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
538167159Sjkim}
539167159Sjkim
540167159Sjkim/*
541167159Sjkim * Get OS builder
542167159Sjkim */
543167159Sjkimstatic void
544167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
545167159Sjkim{
546168762Sdes#if 0
547167159Sjkim	char builder[256];
548167159Sjkim	char *cp;
549167159Sjkim
550167159Sjkim	cp = strstr(version, "\n    ");
551167159Sjkim	if (cp) {
552167159Sjkim		strncpy(builder, cp + 5, 256);
553167159Sjkim		builder[255] = '\0';
554167159Sjkim		cp = strstr(builder, ":");
555167159Sjkim		if (cp)
556167159Sjkim			*cp = '\0';
557167159Sjkim	}
558167159Sjkim	if (cp)
559167159Sjkim		sbuf_cat(sb, builder);
560167159Sjkim	else
561168762Sdes#endif
562167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
563167159Sjkim}
564167159Sjkim
565167159Sjkim/*
56678113Sdes * Filler function for proc/version
56778113Sdes */
56878025Sdesstatic int
56978025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
57065633Sdes{
57187275Srwatson	char osname[LINUX_MAX_UTSNAME];
57287275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
57387275Srwatson
574112206Sjhb	linux_get_osname(td, osname);
575112206Sjhb	linux_get_osrelease(td, osrelease);
576167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
577167159Sjkim	linprocfs_osbuilder(td, sb);
578167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
579167159Sjkim	linprocfs_osbuild(td, sb);
580167159Sjkim	sbuf_cat(sb, "\n");
58187275Srwatson
58278025Sdes	return (0);
58365633Sdes}
58465633Sdes
58578113Sdes/*
58678113Sdes * Filler function for proc/loadavg
58778113Sdes */
58878025Sdesstatic int
58978025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
59076839Sjlemon{
591168762Sdes
59278025Sdes	sbuf_printf(sb,
59376839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
59476839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
59576839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
59676839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
59776839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
59876839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
59976839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
60076839Sjlemon	    1,				/* number of running tasks */
60176839Sjlemon	    nprocs,			/* number of tasks */
60278116Sdes	    lastpid			/* the last pid */
60376839Sjlemon	);
60478025Sdes	return (0);
60576839Sjlemon}
60676839Sjlemon
60778113Sdes/*
60878113Sdes * Filler function for proc/pid/stat
60978113Sdes */
61078025Sdesstatic int
61178025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
61267588Sdes{
61369995Sdes	struct kinfo_proc kp;
614166140Snetchild	char state;
615166140Snetchild	static int ratelimit = 0;
61667588Sdes
61794307Sjhb	PROC_LOCK(p);
61869995Sdes	fill_kinfo_proc(p, &kp);
61978025Sdes	sbuf_printf(sb, "%d", p->p_pid);
62078025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
62167588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
622166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
623166140Snetchild		state = 'R';
624166140Snetchild
625166141Snetchild		if (ratelimit == 0) {
626166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
627166162Snetchild			    kp.ki_stat, sizeof(linux_state));
628166141Snetchild			++ratelimit;
629166141Snetchild		}
630166140Snetchild	} else
631166140Snetchild		state = linux_state[kp.ki_stat - 1];
632166140Snetchild	PS_ADD("state",		"%c",	state);
63373923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
63467588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
63567588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
63691140Stanimura	PROC_UNLOCK(p);
63767588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
638159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
63967588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
640159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
641159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
642159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
643159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
644159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
645159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
646159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
647159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
648159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
649159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
650159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
651159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
652159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
653159995Snetchild	   It should be the number of jiffies between system boot and process
654159995Snetchild	   start. */
655159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
656159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
657159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
658159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
65969995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
66067588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
66167588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
662159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
663159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
664159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
665159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
666159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
667159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
66867588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
669159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
670159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
67169799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
672159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
673159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
674159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
67567588Sdes#undef PS_ADD
67678025Sdes	sbuf_putc(sb, '\n');
677119068Sdes
67878025Sdes	return (0);
67967588Sdes}
68067588Sdes
68167588Sdes/*
682119911Sdes * Filler function for proc/pid/statm
683119911Sdes */
684119911Sdesstatic int
685119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
686119911Sdes{
687119911Sdes	struct kinfo_proc kp;
688119911Sdes	segsz_t lsize;
689120340Sdes
690119911Sdes	PROC_LOCK(p);
691119911Sdes	fill_kinfo_proc(p, &kp);
692119911Sdes	PROC_UNLOCK(p);
693119911Sdes
694119911Sdes	/*
695119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
696119911Sdes	 * computation of lsize.
697119911Sdes	 */
698119911Sdes	/* size resident share trs drs lrs dt */
699119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
700119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
701119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
702119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
703119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
704119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
705119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
706119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
707119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
708119911Sdes
709119911Sdes	return (0);
710119911Sdes}
711119911Sdes
712119911Sdes/*
71378113Sdes * Filler function for proc/pid/status
71478113Sdes */
71578025Sdesstatic int
71678025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
71767588Sdes{
71869995Sdes	struct kinfo_proc kp;
71967588Sdes	char *state;
72069799Sdes	segsz_t lsize;
72199072Sjulian	struct thread *td2;
722114983Sjhb	struct sigacts *ps;
72374135Sjlemon	int i;
72467588Sdes
725113611Sjhb	PROC_LOCK(p);
72699072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
72799072Sjulian
72899072Sjulian	if (P_SHOULDSTOP(p)) {
72999072Sjulian		state = "T (stopped)";
73099072Sjulian	} else {
731170307Sjeff		PROC_SLOCK(p);
73299072Sjulian		switch(p->p_state) {
73399072Sjulian		case PRS_NEW:
73499072Sjulian			state = "I (idle)";
73599072Sjulian			break;
73699072Sjulian		case PRS_NORMAL:
73799072Sjulian			if (p->p_flag & P_WEXIT) {
73899072Sjulian				state = "X (exiting)";
73999072Sjulian				break;
74099072Sjulian			}
74199072Sjulian			switch(td2->td_state) {
742103216Sjulian			case TDS_INHIBITED:
74399072Sjulian				state = "S (sleeping)";
74499072Sjulian				break;
74599072Sjulian			case TDS_RUNQ:
74699072Sjulian			case TDS_RUNNING:
74799072Sjulian				state = "R (running)";
74899072Sjulian				break;
74999072Sjulian			default:
75099072Sjulian				state = "? (unknown)";
75199072Sjulian				break;
75299072Sjulian			}
75399072Sjulian			break;
75499072Sjulian		case PRS_ZOMBIE:
75599072Sjulian			state = "Z (zombie)";
75699072Sjulian			break;
75799072Sjulian		default:
75899072Sjulian			state = "? (unknown)";
75999072Sjulian			break;
76099072Sjulian		}
761170307Sjeff		PROC_SUNLOCK(p);
76299072Sjulian	}
76367588Sdes
76469995Sdes	fill_kinfo_proc(p, &kp);
76578025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
76678031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
76767588Sdes
76867588Sdes	/*
76967588Sdes	 * Credentials
77067588Sdes	 */
77178025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
77278025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
77373923Sjhb						p->p_pptr->p_pid : 0);
77478031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
77578031Sdes						p->p_ucred->cr_uid,
77678031Sdes						p->p_ucred->cr_svuid,
77778031Sdes						/* FreeBSD doesn't have fsuid */
77878031Sdes						p->p_ucred->cr_uid);
77978031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
78078031Sdes						p->p_ucred->cr_gid,
78178031Sdes						p->p_ucred->cr_svgid,
78278031Sdes						/* FreeBSD doesn't have fsgid */
78378031Sdes						p->p_ucred->cr_gid);
78478025Sdes	sbuf_cat(sb, "Groups:\t");
78567588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
78678031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
78771471Sjhb	PROC_UNLOCK(p);
78878025Sdes	sbuf_putc(sb, '\n');
789119068Sdes
79067588Sdes	/*
79167588Sdes	 * Memory
79269799Sdes	 *
79369799Sdes	 * While our approximation of VmLib may not be accurate (I
79469799Sdes	 * don't know of a simple way to verify it, and I'm not sure
79569799Sdes	 * it has much meaning anyway), I believe it's good enough.
79669799Sdes	 *
79769799Sdes	 * The same code that could (I think) accurately compute VmLib
79869799Sdes	 * could also compute VmLck, but I don't really care enough to
79969799Sdes	 * implement it. Submissions are welcome.
80067588Sdes	 */
801113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
80278025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
803113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
804113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
805113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
806113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
80769995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
80869995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
809113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
81067588Sdes
81167588Sdes	/*
81267588Sdes	 * Signal masks
81367588Sdes	 *
81467588Sdes	 * We support up to 128 signals, while Linux supports 32,
81567588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
81667588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
81767588Sdes	 *
81867588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
81967588Sdes	 * supports 64 signals, but this code is a long way from
82067588Sdes	 * running on anything but i386, so ignore that for now.
82167588Sdes	 */
82271471Sjhb	PROC_LOCK(p);
823104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
82469799Sdes	/*
82569799Sdes	 * I can't seem to find out where the signal mask is in
82669799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
82769799Sdes	 */
82878025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
829114983Sjhb	ps = p->p_sigacts;
830114983Sjhb	mtx_lock(&ps->ps_mtx);
831114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
832114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
833114983Sjhb	mtx_unlock(&ps->ps_mtx);
83471471Sjhb	PROC_UNLOCK(p);
835119068Sdes
83667588Sdes	/*
83767588Sdes	 * Linux also prints the capability masks, but we don't have
83867588Sdes	 * capabilities yet, and when we do get them they're likely to
83967588Sdes	 * be meaningless to Linux programs, so we lie. XXX
84067588Sdes	 */
84178025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
84278025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
84378025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
844119068Sdes
84578025Sdes	return (0);
84667588Sdes}
84774135Sjlemon
848119911Sdes
84978113Sdes/*
850119911Sdes * Filler function for proc/pid/cwd
851119911Sdes */
852119911Sdesstatic int
853119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
854119911Sdes{
855119911Sdes	char *fullpath = "unknown";
856119911Sdes	char *freepath = NULL;
857119911Sdes
858119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
859119911Sdes	sbuf_printf(sb, "%s", fullpath);
860119911Sdes	if (freepath)
861119911Sdes		free(freepath, M_TEMP);
862119911Sdes	return (0);
863119911Sdes}
864119911Sdes
865119911Sdes/*
866119911Sdes * Filler function for proc/pid/root
867119911Sdes */
868119911Sdesstatic int
869119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
870119911Sdes{
871119911Sdes	struct vnode *rvp;
872119911Sdes	char *fullpath = "unknown";
873119911Sdes	char *freepath = NULL;
874119911Sdes
875119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
876119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
877119911Sdes	sbuf_printf(sb, "%s", fullpath);
878119911Sdes	if (freepath)
879119911Sdes		free(freepath, M_TEMP);
880119911Sdes	return (0);
881119911Sdes}
882119911Sdes
883119911Sdes/*
88478113Sdes * Filler function for proc/pid/cmdline
88578113Sdes */
88678025Sdesstatic int
88778113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
88878113Sdes{
88978113Sdes	struct ps_strings pstr;
890138281Scperciva	char **ps_argvstr;
89178113Sdes	int error, i;
89278113Sdes
89378113Sdes	/*
89478113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
89578113Sdes	 * revert back to the old way which only implements full cmdline
89678113Sdes	 * for the currept process and just p->p_comm for all other
89778113Sdes	 * processes.
89878113Sdes	 * Note that if the argv is no longer available, we deliberately
89978113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
90078113Sdes	 * Linux behaviour is to return zero-length in this case.
90178113Sdes	 */
90278113Sdes
90394620Sjhb	PROC_LOCK(p);
904127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
90594620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
90694620Sjhb		PROC_UNLOCK(p);
90794620Sjhb	} else if (p != td->td_proc) {
90894620Sjhb		PROC_UNLOCK(p);
90994620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
91094620Sjhb	} else {
91194620Sjhb		PROC_UNLOCK(p);
912103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
913103767Sjake		    sizeof(pstr));
91494620Sjhb		if (error)
91594620Sjhb			return (error);
916138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
917138281Scperciva			return (E2BIG);
918138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
919138281Scperciva		    M_TEMP, M_WAITOK);
920138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
921138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
922138281Scperciva		if (error) {
923138281Scperciva			free(ps_argvstr, M_TEMP);
924138281Scperciva			return (error);
925138281Scperciva		}
92694620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
927138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
92894620Sjhb			sbuf_printf(sb, "%c", '\0');
92978113Sdes		}
930138281Scperciva		free(ps_argvstr, M_TEMP);
93178113Sdes	}
93278113Sdes
93378113Sdes	return (0);
93478113Sdes}
93578113Sdes
93678113Sdes/*
937116173Sobrien * Filler function for proc/pid/environ
938116173Sobrien */
939116173Sobrienstatic int
940116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
941116173Sobrien{
942168762Sdes
943116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
944116173Sobrien	return (0);
945116173Sobrien}
946116173Sobrien
947116173Sobrien/*
948116173Sobrien * Filler function for proc/pid/maps
949116173Sobrien */
950116173Sobrienstatic int
951116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
952116173Sobrien{
953185984Skib	struct vmspace *vm;
954185984Skib	vm_map_t map;
955185765Skib	vm_map_entry_t entry, tmp_entry;
956121265Scognet	vm_object_t obj, tobj, lobj;
957185765Skib	vm_offset_t e_start, e_end;
958121265Scognet	vm_ooffset_t off = 0;
959185765Skib	vm_prot_t e_prot;
960185765Skib	unsigned int last_timestamp;
961121265Scognet	char *name = "", *freename = NULL;
962121265Scognet	ino_t ino;
963121265Scognet	int ref_count, shadow_count, flags;
964121265Scognet	int error;
965137507Sphk	struct vnode *vp;
966137507Sphk	struct vattr vat;
967161094Skib	int locked;
968168762Sdes
969121246Scognet	PROC_LOCK(p);
970121246Scognet	error = p_candebug(td, p);
971121246Scognet	PROC_UNLOCK(p);
972121246Scognet	if (error)
973121246Scognet		return (error);
974168762Sdes
975121246Scognet	if (uio->uio_rw != UIO_READ)
976121246Scognet		return (EOPNOTSUPP);
977168762Sdes
978121246Scognet	error = 0;
979185984Skib	vm = vmspace_acquire_ref(p);
980185984Skib	if (vm == NULL)
981185984Skib		return (ESRCH);
982185984Skib	map = &vm->vm_map;
983169156Salc	vm_map_lock_read(map);
984183600Skib	for (entry = map->header.next; entry != &map->header;
985121246Scognet	    entry = entry->next) {
986121265Scognet		name = "";
987121265Scognet		freename = NULL;
988121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
989121246Scognet			continue;
990185765Skib		e_prot = entry->protection;
991185765Skib		e_start = entry->start;
992185765Skib		e_end = entry->end;
993121246Scognet		obj = entry->object.vm_object;
994169156Salc		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
995169156Salc			VM_OBJECT_LOCK(tobj);
996169156Salc			if (lobj != obj)
997169156Salc				VM_OBJECT_UNLOCK(lobj);
998121246Scognet			lobj = tobj;
999169156Salc		}
1000185765Skib		last_timestamp = map->timestamp;
1001185765Skib		vm_map_unlock_read(map);
1002121246Scognet		ino = 0;
1003121246Scognet		if (lobj) {
1004121246Scognet			off = IDX_TO_OFF(lobj->size);
1005161094Skib			if (lobj->type == OBJT_VNODE) {
1006161094Skib				vp = lobj->handle;
1007161094Skib				if (vp)
1008161094Skib					vref(vp);
1009121246Scognet			}
1010161094Skib			else
1011161094Skib				vp = NULL;
1012169156Salc			if (lobj != obj)
1013169156Salc				VM_OBJECT_UNLOCK(lobj);
1014121246Scognet			flags = obj->flags;
1015121246Scognet			ref_count = obj->ref_count;
1016121246Scognet			shadow_count = obj->shadow_count;
1017169156Salc			VM_OBJECT_UNLOCK(obj);
1018161094Skib			if (vp) {
1019161094Skib				vn_fullpath(td, vp, &name, &freename);
1020161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
1021175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
1022182371Sattilio				VOP_GETATTR(vp, &vat, td->td_ucred);
1023161094Skib				ino = vat.va_fileid;
1024161094Skib				vput(vp);
1025161094Skib				VFS_UNLOCK_GIANT(locked);
1026161094Skib			}
1027121246Scognet		} else {
1028121246Scognet			flags = 0;
1029121246Scognet			ref_count = 0;
1030121246Scognet			shadow_count = 0;
1031121246Scognet		}
1032168762Sdes
1033121246Scognet		/*
1034168762Sdes		 * format:
1035121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
1036121246Scognet		 */
1037183600Skib		error = sbuf_printf(sb,
1038121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1039185765Skib		    (u_long)e_start, (u_long)e_end,
1040185765Skib		    (e_prot & VM_PROT_READ)?"r":"-",
1041185765Skib		    (e_prot & VM_PROT_WRITE)?"w":"-",
1042185765Skib		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1043121246Scognet		    "p",
1044121265Scognet		    (u_long)off,
1045121246Scognet		    0,
1046121246Scognet		    0,
1047121265Scognet		    (u_long)ino,
1048121246Scognet		    *name ? "     " : "",
1049121246Scognet		    name
1050121246Scognet		    );
1051121246Scognet		if (freename)
1052121246Scognet			free(freename, M_TEMP);
1053185864Skib		vm_map_lock_read(map);
1054183600Skib		if (error == -1) {
1055183600Skib			error = 0;
1056121246Scognet			break;
1057169156Salc		}
1058186563Skib		if (last_timestamp != map->timestamp) {
1059185765Skib			/*
1060185765Skib			 * Look again for the entry because the map was
1061185765Skib			 * modified while it was unlocked.  Specifically,
1062185765Skib			 * the entry may have been clipped, merged, or deleted.
1063185765Skib			 */
1064185765Skib			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1065185765Skib			entry = tmp_entry;
1066185765Skib		}
1067121246Scognet	}
1068169156Salc	vm_map_unlock_read(map);
1069185984Skib	vmspace_free(vm);
1070168762Sdes
1071121246Scognet	return (error);
1072168762Sdes}
1073168762Sdes
1074116173Sobrien/*
107578113Sdes * Filler function for proc/net/dev
107678113Sdes */
107778025Sdesstatic int
107878025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
107974135Sjlemon{
108085129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
108174135Sjlemon	struct ifnet *ifp;
108274135Sjlemon
108385129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
108483926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
108585129Sdes	    "bytes    packets errs drop fifo frame compressed",
108683926Sdes	    "bytes    packets errs drop fifo frame compressed");
108774135Sjlemon
1088196635Szec	CURVNET_SET(TD_TO_VNET(curthread));
1089108172Shsu	IFNET_RLOCK();
1090181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
109185129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
109285129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
109383926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
109483926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
109583926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
109683926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
109774135Sjlemon	}
1098108172Shsu	IFNET_RUNLOCK();
1099196635Szec	CURVNET_RESTORE();
1100119068Sdes
110178025Sdes	return (0);
110274135Sjlemon}
110374135Sjlemon
1104158311Sambrisko/*
1105167159Sjkim * Filler function for proc/sys/kernel/osrelease
1106167159Sjkim */
1107167159Sjkimstatic int
1108167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1109167159Sjkim{
1110167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1111167159Sjkim
1112167159Sjkim	linux_get_osrelease(td, osrelease);
1113167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1114167159Sjkim
1115167159Sjkim	return (0);
1116167159Sjkim}
1117167159Sjkim
1118167159Sjkim/*
1119167159Sjkim * Filler function for proc/sys/kernel/ostype
1120167159Sjkim */
1121167159Sjkimstatic int
1122167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1123167159Sjkim{
1124167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1125167159Sjkim
1126167159Sjkim	linux_get_osname(td, osname);
1127167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1128167159Sjkim
1129167159Sjkim	return (0);
1130167159Sjkim}
1131167159Sjkim
1132167159Sjkim/*
1133167159Sjkim * Filler function for proc/sys/kernel/version
1134167159Sjkim */
1135167159Sjkimstatic int
1136167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1137167159Sjkim{
1138168762Sdes
1139167159Sjkim	linprocfs_osbuild(td, sb);
1140167159Sjkim	sbuf_cat(sb, "\n");
1141167159Sjkim	return (0);
1142167159Sjkim}
1143167159Sjkim
1144167159Sjkim/*
1145164692Sjkim * Filler function for proc/sys/kernel/msgmni
1146164692Sjkim */
1147164692Sjkimstatic int
1148164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1149164692Sjkim{
1150164692Sjkim
1151168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1152164692Sjkim	return (0);
1153164692Sjkim}
1154164692Sjkim
1155164692Sjkim/*
1156163251Skeramida * Filler function for proc/sys/kernel/pid_max
1157163129Snetchild */
1158163129Snetchildstatic int
1159163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1160163129Snetchild{
1161163757Snetchild
1162163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1163163129Snetchild	return (0);
1164163129Snetchild}
1165163129Snetchild
1166163129Snetchild/*
1167164692Sjkim * Filler function for proc/sys/kernel/sem
1168164692Sjkim */
1169164692Sjkimstatic int
1170164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1171164692Sjkim{
1172164692Sjkim
1173168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1174168067Sjkim	    seminfo.semopm, seminfo.semmni);
1175164692Sjkim	return (0);
1176164692Sjkim}
1177164692Sjkim
1178164692Sjkim/*
1179158311Sambrisko * Filler function for proc/scsi/device_info
1180158311Sambrisko */
1181158311Sambriskostatic int
1182158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1183158311Sambrisko{
1184168762Sdes
1185158311Sambrisko	return (0);
1186158311Sambrisko}
1187158311Sambrisko
1188158311Sambrisko/*
1189158311Sambrisko * Filler function for proc/scsi/scsi
1190158311Sambrisko */
1191158311Sambriskostatic int
1192158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1193158311Sambrisko{
1194168762Sdes
1195158311Sambrisko	return (0);
1196158311Sambrisko}
1197158311Sambrisko
119885538Sphkextern struct cdevsw *cdevsw[];
119985538Sphk
120078113Sdes/*
120178113Sdes * Filler function for proc/devices
120278113Sdes */
120378025Sdesstatic int
120478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
120574135Sjlemon{
1206158311Sambrisko	char *char_devices;
120778025Sdes	sbuf_printf(sb, "Character devices:\n");
120874135Sjlemon
1209158311Sambrisko	char_devices = linux_get_char_devices();
1210158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1211158311Sambrisko	linux_free_get_char_devices(char_devices);
121274135Sjlemon
121378025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1214119068Sdes
121578025Sdes	return (0);
121674135Sjlemon}
121774135Sjlemon
121878113Sdes/*
121978113Sdes * Filler function for proc/cmdline
122078113Sdes */
122178025Sdesstatic int
122278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
122374135Sjlemon{
1224168762Sdes
122578025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
122678025Sdes	sbuf_printf(sb, " ro root=302\n");
122778025Sdes	return (0);
122878025Sdes}
122974135Sjlemon
1230205541Sjhb/*
1231205541Sjhb * Filler function for proc/filesystems
1232205541Sjhb */
1233205541Sjhbstatic int
1234205541Sjhblinprocfs_dofilesystems(PFS_FILL_ARGS)
1235205541Sjhb{
1236205541Sjhb	struct vfsconf *vfsp;
1237205541Sjhb
1238205541Sjhb	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1239205541Sjhb		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1240205541Sjhb			sbuf_printf(sb, "nodev");
1241205541Sjhb		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1242205541Sjhb	}
1243205541Sjhb	return(0);
1244205541Sjhb}
1245205541Sjhb
124683926Sdes#if 0
124778025Sdes/*
124883926Sdes * Filler function for proc/modules
124983926Sdes */
125083926Sdesstatic int
125183926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
125283926Sdes{
125383926Sdes	struct linker_file *lf;
1254119068Sdes
125583926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
125683926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
125783926Sdes		    (unsigned long)lf->size, lf->refs);
125883926Sdes	}
125983926Sdes	return (0);
126083926Sdes}
126183926Sdes#endif
126283926Sdes
126383926Sdes/*
1264204825Sed * Filler function for proc/pid/fd
1265204825Sed */
1266204825Sedstatic int
1267204825Sedlinprocfs_dofdescfs(PFS_FILL_ARGS)
1268204825Sed{
1269204825Sed
1270204825Sed	if (p == curproc)
1271204825Sed		sbuf_printf(sb, "/dev/fd");
1272204825Sed	else
1273204825Sed		sbuf_printf(sb, "unknown");
1274204825Sed	return (0);
1275204825Sed}
1276204825Sed
1277204825Sed/*
127885129Sdes * Constructor
127978025Sdes */
128085129Sdesstatic int
128185129Sdeslinprocfs_init(PFS_INIT_ARGS)
128285129Sdes{
128385129Sdes	struct pfs_node *root;
128485129Sdes	struct pfs_node *dir;
128574135Sjlemon
128685129Sdes	root = pi->pi_root;
128778025Sdes
1288119923Sdes	/* /proc/... */
1289119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1290167482Sdes	    NULL, NULL, NULL, PFS_RD);
1291119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1292167482Sdes	    NULL, NULL, NULL, PFS_RD);
1293119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1294167482Sdes	    NULL, NULL, NULL, PFS_RD);
1295205541Sjhb	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1296205541Sjhb	    NULL, NULL, NULL, PFS_RD);
1297119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1298167482Sdes	    NULL, NULL, NULL, PFS_RD);
1299119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1300167482Sdes	    NULL, NULL, NULL, PFS_RD);
130183926Sdes#if 0
1302119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1303167482Sdes	    NULL, NULL, NULL, PFS_RD);
130483926Sdes#endif
1305158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1306167482Sdes	    NULL, NULL, NULL, PFS_RD);
1307119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1308167482Sdes	    NULL, NULL, NULL, PFS_RD);
1309190445Sambrisko	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1310190445Sambrisko	    NULL, NULL, NULL, PFS_RD);
131187543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1312167482Sdes	    NULL, NULL, NULL, 0);
1313119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1314167482Sdes	    NULL, NULL, NULL, PFS_RD);
1315119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1316167482Sdes	    NULL, NULL, NULL, PFS_RD);
1317119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1318167482Sdes	    NULL, NULL, NULL, PFS_RD);
131978025Sdes
1320119923Sdes	/* /proc/net/... */
1321167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
132285129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1323167482Sdes	    NULL, NULL, NULL, PFS_RD);
132478025Sdes
1325119923Sdes	/* /proc/<pid>/... */
1326167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
132785129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1328167482Sdes	    NULL, NULL, NULL, PFS_RD);
1329119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1330167482Sdes	    NULL, NULL, NULL, 0);
1331116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1332167482Sdes	    NULL, NULL, NULL, PFS_RD);
133387543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1334167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1335116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1336167482Sdes	    NULL, NULL, NULL, PFS_RD);
133785129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1338167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1339119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1340167482Sdes	    NULL, NULL, NULL, 0);
134185129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1342167482Sdes	    NULL, NULL, NULL, PFS_RD);
1343119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1344167482Sdes	    NULL, NULL, NULL, PFS_RD);
134585129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1346167482Sdes	    NULL, NULL, NULL, PFS_RD);
1347204825Sed	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1348204825Sed	    NULL, NULL, NULL, 0);
134985129Sdes
1350158311Sambrisko	/* /proc/scsi/... */
1351167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1352158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1353167482Sdes	    NULL, NULL, NULL, PFS_RD);
1354158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1355167482Sdes	    NULL, NULL, NULL, PFS_RD);
1356163129Snetchild
1357163129Snetchild	/* /proc/sys/... */
1358167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1359163129Snetchild	/* /proc/sys/kernel/... */
1360167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1361167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1362167482Sdes	    NULL, NULL, NULL, PFS_RD);
1363167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1364167482Sdes	    NULL, NULL, NULL, PFS_RD);
1365167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1366167482Sdes	    NULL, NULL, NULL, PFS_RD);
1367164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1368167482Sdes	    NULL, NULL, NULL, PFS_RD);
1369163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1370167482Sdes	    NULL, NULL, NULL, PFS_RD);
1371164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1372167482Sdes	    NULL, NULL, NULL, PFS_RD);
1373163129Snetchild
137485129Sdes	return (0);
137585129Sdes}
137685129Sdes
137785129Sdes/*
137885129Sdes * Destructor
137985129Sdes */
138085129Sdesstatic int
138185129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
138285129Sdes{
138385129Sdes
138485129Sdes	/* nothing to do, pseudofs will GC */
138585129Sdes	return (0);
138685129Sdes}
138785129Sdes
138885129SdesPSEUDOFS(linprocfs, 1);
138978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
139078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1391168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1392168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1393