linprocfs.c revision 166162
139213Sgibbs/*-
239213Sgibbs * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
339213Sgibbs * Copyright (c) 1999 Pierre Beyssac
439213Sgibbs * Copyright (c) 1993 Jan-Simon Pendry
539213Sgibbs * Copyright (c) 1993
639213Sgibbs *	The Regents of the University of California.  All rights reserved.
739213Sgibbs *
839213Sgibbs * This code is derived from software contributed to Berkeley by
939213Sgibbs * Jan-Simon Pendry.
1039213Sgibbs *
1139213Sgibbs * Redistribution and use in source and binary forms, with or without
1239213Sgibbs * modification, are permitted provided that the following conditions
1339213Sgibbs * are met:
1439213Sgibbs * 1. Redistributions of source code must retain the above copyright
1539213Sgibbs *    notice, this list of conditions and the following disclaimer.
1639213Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1739213Sgibbs *    notice, this list of conditions and the following disclaimer in the
1839213Sgibbs *    documentation and/or other materials provided with the distribution.
1939213Sgibbs * 3. All advertising materials mentioning features or use of this software
2039213Sgibbs *    must display the following acknowledgement:
2139213Sgibbs *	This product includes software developed by the University of
2239213Sgibbs *	California, Berkeley and its contributors.
2339213Sgibbs * 4. Neither the name of the University nor the names of its contributors
2439213Sgibbs *    may be used to endorse or promote products derived from this software
2539213Sgibbs *    without specific prior written permission.
2639213Sgibbs *
2739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2839213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29116162Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30116162Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31116162Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3239213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3339213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3439213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3539213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3760041Sphk * SUCH DAMAGE.
3839213Sgibbs *
3939213Sgibbs *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
4039213Sgibbs */
4150073Sken
4239213Sgibbs#include <sys/cdefs.h>
4339213Sgibbs__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 166162 2007-01-21 13:18:52Z netchild $");
4439213Sgibbs
4539213Sgibbs#include <sys/param.h>
4639213Sgibbs#include <sys/queue.h>
4739213Sgibbs#include <sys/blist.h>
4839213Sgibbs#include <sys/conf.h>
4939213Sgibbs#include <sys/exec.h>
5039213Sgibbs#include <sys/filedesc.h>
5139213Sgibbs#include <sys/jail.h>
5239213Sgibbs#include <sys/kernel.h>
5350073Sken#include <sys/linker.h>
5450073Sken#include <sys/lock.h>
5539213Sgibbs#include <sys/malloc.h>
5639213Sgibbs#include <sys/mount.h>
5739213Sgibbs#include <sys/mutex.h>
5839213Sgibbs#include <sys/namei.h>
5939213Sgibbs#include <sys/proc.h>
6039213Sgibbs#include <sys/resourcevar.h>
6139213Sgibbs#include <sys/sbuf.h>
6239213Sgibbs#include <sys/smp.h>
6339213Sgibbs#include <sys/socket.h>
6439213Sgibbs#include <sys/sysctl.h>
6539213Sgibbs#include <sys/systm.h>
6639213Sgibbs#include <sys/time.h>
6739213Sgibbs#include <sys/tty.h>
6839213Sgibbs#include <sys/user.h>
6939213Sgibbs#include <sys/vmmeter.h>
7039213Sgibbs#include <sys/vnode.h>
7139213Sgibbs
7239213Sgibbs#include <net/if.h>
7339213Sgibbs
7439213Sgibbs#include <vm/vm.h>
7539213Sgibbs#include <vm/pmap.h>
7639213Sgibbs#include <vm/vm_map.h>
7739213Sgibbs#include <vm/vm_param.h>
7839213Sgibbs#include <vm/vm_object.h>
7959249Sphk#include <vm/swap_pager.h>
80112006Sphk
8160938Sjake#include <machine/clock.h>
8239213Sgibbs
8339213Sgibbs#if defined(__i386__) || defined(__amd64__)
8439213Sgibbs#include <machine/cputypes.h>
8550073Sken#include <machine/md_var.h>
8653257Sken#endif /* __i386__ || __amd64__ */
8739213Sgibbs
8839213Sgibbs#include "opt_compat.h"
8939213Sgibbs#ifdef COMPAT_LINUX32				/* XXX */
9039213Sgibbs#include <machine/../linux32/linux.h>
9139213Sgibbs#else
9239213Sgibbs#include <machine/../linux/linux.h>
9339213Sgibbs#endif
9439213Sgibbs#include <compat/linux/linux_ioctl.h>
9539213Sgibbs#include <compat/linux/linux_mib.h>
9640603Sken#include <compat/linux/linux_util.h>
9739213Sgibbs#include <fs/pseudofs/pseudofs.h>
9839213Sgibbs#include <fs/procfs/procfs.h>
9939213Sgibbs
10039213Sgibbs/*
10150073Sken * Various conversion macros
10239213Sgibbs */
10339213Sgibbs#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10439213Sgibbs#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10539213Sgibbs#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10639213Sgibbs#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10739213Sgibbs#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10839213Sgibbs#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
10939213Sgibbs
11039213Sgibbs/**
11139213Sgibbs * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
11239213Sgibbs *
11339213Sgibbs * The linux procfs state field displays one of the characters RSDZTW to
11439213Sgibbs * denote running, sleeping in an interruptible wait, waiting in an
11539213Sgibbs * uninteruptible disk sleep, a zombie process, process is being traced
11639213Sgibbs * or stopped, or process is paging respectively.
11772119Speter *
11839213Sgibbs * Our struct kinfo_proc contains the variable ki_stat which contains a
11939213Sgibbs * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
12047625Sphk *
121126080Sphk * This character array is used with ki_stati-1 as an index and tries to
122126080Sphk * map our states to suitable linux states.
123111815Sphk */
124111815Sphkstatic char linux_state[] = "RRSTZDD";
125111815Sphk
126111815Sphk/*
127111815Sphk * Filler function for proc/meminfo
128111815Sphk */
129111815Sphkstatic int
13039213Sgibbslinprocfs_domeminfo(PFS_FILL_ARGS)
13139213Sgibbs{
13250073Sken	unsigned long memtotal;		/* total memory in bytes */
13350073Sken	unsigned long memused;		/* used memory in bytes */
13450073Sken	unsigned long memfree;		/* free memory in bytes */
13550073Sken	unsigned long memshared;	/* shared memory ??? */
13639213Sgibbs	unsigned long buffers, cached;	/* buffer / cache memory ??? */
13783366Sjulian	unsigned long long swaptotal;	/* total swap space in bytes */
13839213Sgibbs	unsigned long long swapused;	/* used swap space in bytes */
13939213Sgibbs	unsigned long long swapfree;	/* free swap space in bytes */
14039213Sgibbs	vm_object_t object;
14139213Sgibbs	int i, j;
14239213Sgibbs
14340603Sken	memtotal = physmem * PAGE_SIZE;
14439213Sgibbs	/*
14539213Sgibbs	 * The correct thing here would be:
146101940Snjl	 *
14739213Sgibbs	memfree = cnt.v_free_count * PAGE_SIZE;
14839213Sgibbs	memused = memtotal - memfree;
14939213Sgibbs	 *
15039213Sgibbs	 * but it might mislead linux binaries into thinking there
15139213Sgibbs	 * is very little memory left, so we cheat and tell them that
15240603Sken	 * all memory that isn't wired down is free.
15340603Sken	 */
15440603Sken	memused = cnt.v_wire_count * PAGE_SIZE;
15540603Sken	memfree = memtotal - memused;
15640603Sken	swap_pager_status(&i, &j);
15740603Sken	swaptotal = (unsigned long long)i * PAGE_SIZE;
15839213Sgibbs	swapused = (unsigned long long)j * PAGE_SIZE;
15949982Sbillf	swapfree = swaptotal - swapused;
16039213Sgibbs	memshared = 0;
16141297Sken	mtx_lock(&vm_object_list_mtx);
16241297Sken	TAILQ_FOREACH(object, &vm_object_list, object_list)
16339213Sgibbs		if (object->shadow_count > 1)
16441297Sken			memshared += object->resident_page_count;
16539213Sgibbs	mtx_unlock(&vm_object_list_mtx);
16641297Sken	memshared *= PAGE_SIZE;
16741297Sken	/*
16839213Sgibbs	 * We'd love to be able to write:
16939213Sgibbs	 *
17039213Sgibbs	buffers = bufspace;
17139213Sgibbs	 *
17239213Sgibbs	 * but bufspace is internal to vfs_bio.c and we don't feel
17339213Sgibbs	 * like unstaticizing it just for linprocfs's sake.
17439213Sgibbs	 */
17539213Sgibbs	buffers = 0;
17639213Sgibbs	cached = cnt.v_cache_count * PAGE_SIZE;
17739213Sgibbs
17839213Sgibbs	sbuf_printf(sb,
17939213Sgibbs	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18039213Sgibbs	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18183366Sjulian	    "Swap: %llu %llu %llu\n"
18239213Sgibbs	    "MemTotal: %9lu kB\n"
18339213Sgibbs	    "MemFree:  %9lu kB\n"
18439213Sgibbs	    "MemShared:%9lu kB\n"
18539213Sgibbs	    "Buffers:  %9lu kB\n"
18639213Sgibbs	    "Cached:   %9lu kB\n"
187101940Snjl	    "SwapTotal:%9llu kB\n"
18839213Sgibbs	    "SwapFree: %9llu kB\n",
18939213Sgibbs	    memtotal, memused, memfree, memshared, buffers, cached,
19039213Sgibbs	    swaptotal, swapused, swapfree,
19139213Sgibbs	    B2K(memtotal), B2K(memfree),
19239213Sgibbs	    B2K(memshared), B2K(buffers), B2K(cached),
19339213Sgibbs	    B2K(swaptotal), B2K(swapfree));
19439213Sgibbs
19539213Sgibbs	return (0);
19639213Sgibbs}
19739213Sgibbs
19839213Sgibbs#if defined(__i386__) || defined(__amd64__)
19939213Sgibbs/*
20039213Sgibbs * Filler function for proc/cpuinfo (i386 & amd64 version)
20139213Sgibbs */
20239213Sgibbsstatic int
20339213Sgibbslinprocfs_docpuinfo(PFS_FILL_ARGS)
20439213Sgibbs{
20539213Sgibbs	int hw_model[2];
20639213Sgibbs	char model[128];
20739213Sgibbs	size_t size;
20859249Sphk	int class, fqmhz, fqkhz;
20939213Sgibbs	int i;
21039213Sgibbs
21139213Sgibbs	/*
21239213Sgibbs	 * We default the flags to include all non-conflicting flags,
21339213Sgibbs	 * and the Intel versions of conflicting flags.
214101940Snjl	 */
21576362Sphk	static char *flags[] = {
21639213Sgibbs		"fpu",	    "vme",     "de",	   "pse",      "tsc",
21776362Sphk		"msr",	    "pae",     "mce",	   "cx8",      "apic",
21876362Sphk		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
21939213Sgibbs		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22039213Sgibbs		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22139213Sgibbs		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22239213Sgibbs		"3dnowext", "3dnow"
22339213Sgibbs	};
22439213Sgibbs
22539213Sgibbs	switch (cpu_class) {
22639213Sgibbs#ifdef __i386__
22739213Sgibbs	case CPUCLASS_286:
22839213Sgibbs		class = 2;
22939213Sgibbs		break;
23039213Sgibbs	case CPUCLASS_386:
23139213Sgibbs		class = 3;
23239213Sgibbs		break;
23339213Sgibbs	case CPUCLASS_486:
23476362Sphk		class = 4;
23576362Sphk		break;
23639213Sgibbs	case CPUCLASS_586:
23739213Sgibbs		class = 5;
23839213Sgibbs		break;
23939213Sgibbs	case CPUCLASS_686:
24039213Sgibbs		class = 6;
24159249Sphk		break;
24239213Sgibbs	default:
24339213Sgibbs		class = 0;
24439213Sgibbs		break;
24539213Sgibbs#else /* __amd64__ */
24639213Sgibbs	default:
24739213Sgibbs		class = 15;
24839213Sgibbs		break;
24939213Sgibbs#endif
25039213Sgibbs	}
25139213Sgibbs
25239213Sgibbs	hw_model[0] = CTL_HW;
25339213Sgibbs	hw_model[1] = HW_MODEL;
25439213Sgibbs	model[0] = '\0';
25539213Sgibbs	size = sizeof(model);
25639213Sgibbs	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
25739213Sgibbs		strcpy(model, "unknown");
25839213Sgibbs	for (i = 0; i < mp_ncpus; ++i) {
25939213Sgibbs		sbuf_printf(sb,
26039213Sgibbs		    "processor\t: %d\n"
26139213Sgibbs		    "vendor_id\t: %.20s\n"
26239213Sgibbs		    "cpu family\t: %d\n"
26339213Sgibbs		    "model\t\t: %d\n"
26439213Sgibbs		    "model name\t: %s\n"
26539213Sgibbs		    "stepping\t: %d\n",
26639213Sgibbs		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
26739213Sgibbs		/* XXX per-cpu vendor / class / model / id? */
26839213Sgibbs	}
26939213Sgibbs
27039213Sgibbs	sbuf_cat(sb,
27139213Sgibbs	    "flags\t\t:");
27239213Sgibbs
27339213Sgibbs	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
27439213Sgibbs		flags[16] = "fcmov";
27539213Sgibbs	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
27639213Sgibbs		flags[24] = "cxmmx";
27739213Sgibbs	}
27839213Sgibbs
27939213Sgibbs	for (i = 0; i < 32; i++)
28039213Sgibbs		if (cpu_feature & (1 << i))
28139213Sgibbs			sbuf_printf(sb, " %s", flags[i]);
28239213Sgibbs	sbuf_cat(sb, "\n");
28339213Sgibbs	if (class >= 5) {
28439213Sgibbs		fqmhz = (tsc_freq + 4999) / 1000000;
28539213Sgibbs		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
28639213Sgibbs		sbuf_printf(sb,
28739213Sgibbs		    "cpu MHz\t\t: %d.%02d\n"
28839213Sgibbs		    "bogomips\t: %d.%02d\n",
28939213Sgibbs		    fqmhz, fqkhz, fqmhz, fqkhz);
29039213Sgibbs	}
29139213Sgibbs
29239213Sgibbs	return (0);
29339213Sgibbs}
29439213Sgibbs#endif /* __i386__ || __amd64__ */
29539213Sgibbs
29639213Sgibbs/*
29739213Sgibbs * Filler function for proc/mtab
29839213Sgibbs *
29939213Sgibbs * This file doesn't exist in Linux' procfs, but is included here so
30039213Sgibbs * users can symlink /compat/linux/etc/mtab to /proc/mtab
30139213Sgibbs */
30239213Sgibbsstatic int
30339213Sgibbslinprocfs_domtab(PFS_FILL_ARGS)
30439213Sgibbs{
30539213Sgibbs	struct nameidata nd;
30639213Sgibbs	struct mount *mp;
30739213Sgibbs	const char *lep;
30839213Sgibbs	char *dlep, *flep, *mntto, *mntfrom, *fstype;
30939213Sgibbs	size_t lep_len;
31039213Sgibbs	int error;
31139213Sgibbs
31239213Sgibbs	/* resolve symlinks etc. in the emulation tree prefix */
31339213Sgibbs	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
31459249Sphk	flep = NULL;
31539213Sgibbs	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
31650073Sken		lep = linux_emul_path;
31750073Sken	else
31839213Sgibbs		lep = dlep;
31939213Sgibbs	lep_len = strlen(lep);
320112006Sphk
32139213Sgibbs	mtx_lock(&mountlist_mtx);
32239213Sgibbs	error = 0;
32356148Smjacob	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
32443819Sken		/* determine device name */
32539213Sgibbs		mntfrom = mp->mnt_stat.f_mntfromname;
32653257Sken
32753257Sken		/* determine mount point */
32853257Sken		mntto = mp->mnt_stat.f_mntonname;
329101940Snjl		if (strncmp(mntto, lep, lep_len) == 0 &&
330101940Snjl		    mntto[lep_len] == '/')
33139213Sgibbs			mntto += lep_len;
33239213Sgibbs
33339213Sgibbs		/* determine fs type */
33439213Sgibbs		fstype = mp->mnt_stat.f_fstypename;
33539213Sgibbs		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
33639213Sgibbs			mntfrom = fstype = "proc";
33739213Sgibbs		else if (strcmp(fstype, "procfs") == 0)
33839213Sgibbs			continue;
33939213Sgibbs
34039213Sgibbs		if (strcmp(fstype, "linsysfs") == 0) {
34139213Sgibbs			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
34239213Sgibbs			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
34339213Sgibbs		} else {
34439213Sgibbs			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
34539213Sgibbs			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
34639213Sgibbs		}
34739213Sgibbs#define ADD_OPTION(opt, name) \
34839213Sgibbs	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
34939213Sgibbs		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
35039213Sgibbs		ADD_OPTION(MNT_NOEXEC,		"noexec");
35139213Sgibbs		ADD_OPTION(MNT_NOSUID,		"nosuid");
35239213Sgibbs		ADD_OPTION(MNT_UNION,		"union");
35340603Sken		ADD_OPTION(MNT_ASYNC,		"async");
35440603Sken		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
35540603Sken		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
35640603Sken		ADD_OPTION(MNT_NOATIME,		"noatime");
35740603Sken#undef ADD_OPTION
35840603Sken		/* a real Linux mtab will also show NFS options */
35940603Sken		sbuf_printf(sb, " 0 0\n");
36040603Sken	}
36140603Sken	mtx_unlock(&mountlist_mtx);
36240603Sken	if (flep != NULL)
36340603Sken		free(flep, M_TEMP);
36440603Sken	return (error);
36540603Sken}
36640603Sken
36740603Sken/*
36840603Sken * Filler function for proc/stat
36940603Sken */
37040603Skenstatic int
37140603Skenlinprocfs_dostat(PFS_FILL_ARGS)
37240603Sken{
37340603Sken	int i;
37440603Sken
37540603Sken	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
37640603Sken	    T2J(cp_time[CP_USER]),
37740603Sken	    T2J(cp_time[CP_NICE]),
37840603Sken	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
37940603Sken	    T2J(cp_time[CP_IDLE]));
38040603Sken	for (i = 0; i < mp_ncpus; ++i)
38140603Sken		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
38240603Sken		    T2J(cp_time[CP_USER]) / mp_ncpus,
38340603Sken		    T2J(cp_time[CP_NICE]) / mp_ncpus,
38440603Sken		    T2J(cp_time[CP_SYS]) / mp_ncpus,
38540603Sken		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
386112946Sphk	sbuf_printf(sb,
38740603Sken	    "disk 0 0 0 0\n"
38840603Sken	    "page %u %u\n"
38940603Sken	    "swap %u %u\n"
39040603Sken	    "intr %u\n"
39140603Sken	    "ctxt %u\n"
39240603Sken	    "btime %lld\n",
39340603Sken	    cnt.v_vnodepgsin,
39440603Sken	    cnt.v_vnodepgsout,
39539213Sgibbs	    cnt.v_swappgsin,
39639213Sgibbs	    cnt.v_swappgsout,
39740603Sken	    cnt.v_intr,
39840603Sken	    cnt.v_swtch,
39940603Sken	    (long long)boottime.tv_sec);
40040603Sken	return (0);
401112006Sphk}
40240603Sken
40353257Sken/*
40453257Sken * Filler function for proc/uptime
40539213Sgibbs */
40639213Sgibbsstatic int
40740603Skenlinprocfs_douptime(PFS_FILL_ARGS)
40839213Sgibbs{
40939213Sgibbs	struct timeval tv;
41039213Sgibbs
41139213Sgibbs	getmicrouptime(&tv);
41239213Sgibbs	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
41339213Sgibbs	    (long long)tv.tv_sec, tv.tv_usec / 10000,
41439213Sgibbs	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
41539213Sgibbs	return (0);
41639213Sgibbs}
41739213Sgibbs
41839213Sgibbs/*
41939213Sgibbs * Filler function for proc/version
42039213Sgibbs */
42139213Sgibbsstatic int
42239213Sgibbslinprocfs_doversion(PFS_FILL_ARGS)
42379177Smjacob{
42479177Smjacob	char osname[LINUX_MAX_UTSNAME];
42539213Sgibbs	char osrelease[LINUX_MAX_UTSNAME];
42656148Smjacob
42739213Sgibbs	linux_get_osname(td, osname);
42839213Sgibbs	linux_get_osrelease(td, osrelease);
42939213Sgibbs
43039213Sgibbs	sbuf_printf(sb,
43139213Sgibbs	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
43239213Sgibbs	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
43339213Sgibbs	return (0);
43440603Sken}
43540603Sken
43640603Sken/*
43740603Sken * Filler function for proc/loadavg
43839213Sgibbs */
43939213Sgibbsstatic int
44039213Sgibbslinprocfs_doloadavg(PFS_FILL_ARGS)
44139213Sgibbs{
44239213Sgibbs	sbuf_printf(sb,
44339213Sgibbs	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
44439213Sgibbs	    (int)(averunnable.ldavg[0] / averunnable.fscale),
44539213Sgibbs	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
44639213Sgibbs	    (int)(averunnable.ldavg[1] / averunnable.fscale),
44739213Sgibbs	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
44839213Sgibbs	    (int)(averunnable.ldavg[2] / averunnable.fscale),
44939213Sgibbs	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
45039213Sgibbs	    1,				/* number of running tasks */
45139213Sgibbs	    nprocs,			/* number of tasks */
45239213Sgibbs	    lastpid			/* the last pid */
45339213Sgibbs	);
45439213Sgibbs
45539213Sgibbs	return (0);
45639213Sgibbs}
45739213Sgibbs
45839213Sgibbs/*
45971999Sphk * Filler function for proc/pid/stat
46039213Sgibbs */
46139213Sgibbsstatic int
46239213Sgibbslinprocfs_doprocstat(PFS_FILL_ARGS)
463115562Sphk{
46439213Sgibbs	struct kinfo_proc kp;
46547413Sgibbs	char state;
46639213Sgibbs	static int ratelimit = 0;
46739213Sgibbs
46839213Sgibbs	PROC_LOCK(p);
46939213Sgibbs	fill_kinfo_proc(p, &kp);
47039213Sgibbs	sbuf_printf(sb, "%d", p->p_pid);
47139213Sgibbs#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
47239213Sgibbs	PS_ADD("comm",		"(%s)",	p->p_comm);
47339213Sgibbs	if (kp.ki_stat > sizeof(linux_state)) {
47459249Sphk		state = 'R';
47539213Sgibbs
47639213Sgibbs		if (ratelimit == 0) {
47739213Sgibbs			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
47839213Sgibbs			    kp.ki_stat, sizeof(linux_state));
47939213Sgibbs			++ratelimit;
48039213Sgibbs		}
48139213Sgibbs	} else
48239213Sgibbs		state = linux_state[kp.ki_stat - 1];
48359249Sphk	PS_ADD("state",		"%c",	state);
48439213Sgibbs	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
48539213Sgibbs	PS_ADD("pgrp",		"%d",	p->p_pgid);
48639213Sgibbs	PS_ADD("session",	"%d",	p->p_session->s_sid);
48739213Sgibbs	PROC_UNLOCK(p);
48839213Sgibbs	PS_ADD("tty",		"%d",	0); /* XXX */
48939213Sgibbs	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
49039213Sgibbs	PS_ADD("flags",		"%u",	0); /* XXX */
49139213Sgibbs	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
49239213Sgibbs	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
49339213Sgibbs	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
49439213Sgibbs	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
49539213Sgibbs	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
49639213Sgibbs	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
49739213Sgibbs	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
49839213Sgibbs	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
49959249Sphk	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
50039213Sgibbs	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
501112260Sphk	PS_ADD("0",		"%d",	0); /* removed field */
50239213Sgibbs	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
50339213Sgibbs	/* XXX: starttime is not right, it is the _same_ for _every_ process.
50439213Sgibbs	   It should be the number of jiffies between system boot and process
50539213Sgibbs	   start. */
50639213Sgibbs	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
50759249Sphk	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
50839213Sgibbs	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
50959249Sphk	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
51059249Sphk	PS_ADD("startcode",	"%u",	(unsigned)0);
51139213Sgibbs	PS_ADD("endcode",	"%u",	0); /* XXX */
51250073Sken	PS_ADD("startstack",	"%u",	0); /* XXX */
51339213Sgibbs	PS_ADD("kstkesp",	"%u",	0); /* XXX */
51476192Sken	PS_ADD("kstkeip",	"%u",	0); /* XXX */
51539213Sgibbs	PS_ADD("signal",	"%u",	0); /* XXX */
51639213Sgibbs	PS_ADD("blocked",	"%u",	0); /* XXX */
51739213Sgibbs	PS_ADD("sigignore",	"%u",	0); /* XXX */
51839213Sgibbs	PS_ADD("sigcatch",	"%u",	0); /* XXX */
51939213Sgibbs	PS_ADD("wchan",		"%u",	0); /* XXX */
52039213Sgibbs	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
52139213Sgibbs	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
52239213Sgibbs	PS_ADD("exitsignal",	"%d",	0); /* XXX */
52339213Sgibbs	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
52439213Sgibbs	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
52539213Sgibbs	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
52659249Sphk#undef PS_ADD
52739213Sgibbs	sbuf_putc(sb, '\n');
52839213Sgibbs
52939213Sgibbs	return (0);
53039213Sgibbs}
53139213Sgibbs
53239213Sgibbs/*
53339213Sgibbs * Filler function for proc/pid/statm
53439213Sgibbs */
53539213Sgibbsstatic int
53639213Sgibbslinprocfs_doprocstatm(PFS_FILL_ARGS)
53739213Sgibbs{
53839213Sgibbs	struct kinfo_proc kp;
53939213Sgibbs	segsz_t lsize;
54039213Sgibbs
54139213Sgibbs	PROC_LOCK(p);
54239213Sgibbs	fill_kinfo_proc(p, &kp);
54339213Sgibbs	PROC_UNLOCK(p);
54439213Sgibbs
54539213Sgibbs	/*
54639213Sgibbs	 * See comments in linprocfs_doprocstatus() regarding the
54739213Sgibbs	 * computation of lsize.
54839213Sgibbs	 */
54939213Sgibbs	/* size resident share trs drs lrs dt */
55059249Sphk	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
55139213Sgibbs	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
55239213Sgibbs	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
55359249Sphk	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
55439213Sgibbs	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
55539213Sgibbs	lsize = B2P(kp.ki_size) - kp.ki_dsize -
55639213Sgibbs	    kp.ki_ssize - kp.ki_tsize - 1;
55739213Sgibbs	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
55839213Sgibbs	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
55939213Sgibbs
56039213Sgibbs	return (0);
56139213Sgibbs}
56239213Sgibbs
56339213Sgibbs/*
56474840Sken * Filler function for proc/pid/status
56574840Sken */
56639213Sgibbsstatic int
56739213Sgibbslinprocfs_doprocstatus(PFS_FILL_ARGS)
56839213Sgibbs{
56939213Sgibbs	struct kinfo_proc kp;
57039213Sgibbs	char *state;
57139213Sgibbs	segsz_t lsize;
57239213Sgibbs	struct thread *td2;
57339213Sgibbs	struct sigacts *ps;
57439213Sgibbs	int i;
57539213Sgibbs
57639213Sgibbs	PROC_LOCK(p);
57739213Sgibbs	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
57839213Sgibbs
57939213Sgibbs	if (P_SHOULDSTOP(p)) {
58039213Sgibbs		state = "T (stopped)";
58139213Sgibbs	} else {
58239213Sgibbs		mtx_lock_spin(&sched_lock);
58339213Sgibbs		switch(p->p_state) {
58439213Sgibbs		case PRS_NEW:
58539213Sgibbs			state = "I (idle)";
58639213Sgibbs			break;
58739213Sgibbs		case PRS_NORMAL:
58839213Sgibbs			if (p->p_flag & P_WEXIT) {
58939213Sgibbs				state = "X (exiting)";
590112946Sphk				break;
59139213Sgibbs			}
59259249Sphk			switch(td2->td_state) {
59359249Sphk			case TDS_INHIBITED:
59459249Sphk				state = "S (sleeping)";
59539213Sgibbs				break;
59659249Sphk			case TDS_RUNQ:
59759249Sphk			case TDS_RUNNING:
59859249Sphk				state = "R (running)";
59939213Sgibbs				break;
60059249Sphk			default:
60139213Sgibbs				state = "? (unknown)";
60239213Sgibbs				break;
60339213Sgibbs			}
60439213Sgibbs			break;
60539213Sgibbs		case PRS_ZOMBIE:
60639213Sgibbs			state = "Z (zombie)";
60739213Sgibbs			break;
60839213Sgibbs		default:
60939213Sgibbs			state = "? (unknown)";
61059249Sphk			break;
61159249Sphk		}
61259249Sphk		mtx_unlock_spin(&sched_lock);
61339213Sgibbs	}
61439213Sgibbs
61539213Sgibbs	fill_kinfo_proc(p, &kp);
61639213Sgibbs	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
61739213Sgibbs	sbuf_printf(sb, "State:\t%s\n",		state);
61839213Sgibbs
61939213Sgibbs	/*
62039213Sgibbs	 * Credentials
62139213Sgibbs	 */
62239213Sgibbs	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
623112006Sphk	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
62439213Sgibbs						p->p_pptr->p_pid : 0);
62539213Sgibbs	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
62639213Sgibbs						p->p_ucred->cr_uid,
62739213Sgibbs						p->p_ucred->cr_svuid,
62839213Sgibbs						/* FreeBSD doesn't have fsuid */
62939213Sgibbs						p->p_ucred->cr_uid);
63039213Sgibbs	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
63139213Sgibbs						p->p_ucred->cr_gid,
63239213Sgibbs						p->p_ucred->cr_svgid,
63339213Sgibbs						/* FreeBSD doesn't have fsgid */
63439213Sgibbs						p->p_ucred->cr_gid);
63539213Sgibbs	sbuf_cat(sb, "Groups:\t");
63639213Sgibbs	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
63739213Sgibbs		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
63839213Sgibbs	PROC_UNLOCK(p);
63939213Sgibbs	sbuf_putc(sb, '\n');
64039213Sgibbs
64139213Sgibbs	/*
64239213Sgibbs	 * Memory
64339213Sgibbs	 *
64439213Sgibbs	 * While our approximation of VmLib may not be accurate (I
64539213Sgibbs	 * don't know of a simple way to verify it, and I'm not sure
64639213Sgibbs	 * it has much meaning anyway), I believe it's good enough.
64750073Sken	 *
64883366Sjulian	 * The same code that could (I think) accurately compute VmLib
64950073Sken	 * could also compute VmLck, but I don't really care enough to
65050073Sken	 * implement it. Submissions are welcome.
65150073Sken	 */
65250073Sken	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
65350073Sken	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
654101940Snjl	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
65550073Sken	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
65650073Sken	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
65750073Sken	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
65850073Sken	lsize = B2P(kp.ki_size) - kp.ki_dsize -
65950073Sken	    kp.ki_ssize - kp.ki_tsize - 1;
66050073Sken	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
66150073Sken
66250073Sken	/*
66350073Sken	 * Signal masks
66450073Sken	 *
66550073Sken	 * We support up to 128 signals, while Linux supports 32,
66650073Sken	 * but we only define 32 (the same 32 as Linux, to boot), so
66750073Sken	 * just show the lower 32 bits of each mask. XXX hack.
66850073Sken	 *
66950073Sken	 * NB: on certain platforms (Sparc at least) Linux actually
67050073Sken	 * supports 64 signals, but this code is a long way from
67150073Sken	 * running on anything but i386, so ignore that for now.
67250073Sken	 */
67350073Sken	PROC_LOCK(p);
67450073Sken	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
67550073Sken	/*
67650073Sken	 * I can't seem to find out where the signal mask is in
67750073Sken	 * relation to struct proc, so SigBlk is left unimplemented.
67850073Sken	 */
67950073Sken	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
68050073Sken	ps = p->p_sigacts;
68150073Sken	mtx_lock(&ps->ps_mtx);
68250073Sken	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
68350073Sken	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
68450073Sken	mtx_unlock(&ps->ps_mtx);
68550073Sken	PROC_UNLOCK(p);
68650073Sken
68750073Sken	/*
68850073Sken	 * Linux also prints the capability masks, but we don't have
68950073Sken	 * capabilities yet, and when we do get them they're likely to
69050073Sken	 * be meaningless to Linux programs, so we lie. XXX
69150073Sken	 */
69250073Sken	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
69350073Sken	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
69450073Sken	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
69550073Sken
69639213Sgibbs	return (0);
69739213Sgibbs}
69839213Sgibbs
69939213Sgibbs
70039213Sgibbs/*
70139213Sgibbs * Filler function for proc/pid/cwd
70239213Sgibbs */
70339213Sgibbsstatic int
70439213Sgibbslinprocfs_doproccwd(PFS_FILL_ARGS)
70539213Sgibbs{
70639213Sgibbs	char *fullpath = "unknown";
70739213Sgibbs	char *freepath = NULL;
70839213Sgibbs
70939213Sgibbs	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
71039213Sgibbs	sbuf_printf(sb, "%s", fullpath);
71139213Sgibbs	if (freepath)
71239213Sgibbs		free(freepath, M_TEMP);
71339213Sgibbs	return (0);
71439213Sgibbs}
71539213Sgibbs
71639213Sgibbs/*
71739213Sgibbs * Filler function for proc/pid/root
71839213Sgibbs */
71939213Sgibbsstatic int
72039213Sgibbslinprocfs_doprocroot(PFS_FILL_ARGS)
72139213Sgibbs{
722	struct vnode *rvp;
723	char *fullpath = "unknown";
724	char *freepath = NULL;
725
726	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
727	vn_fullpath(td, rvp, &fullpath, &freepath);
728	sbuf_printf(sb, "%s", fullpath);
729	if (freepath)
730		free(freepath, M_TEMP);
731	return (0);
732}
733
734/*
735 * Filler function for proc/pid/cmdline
736 */
737static int
738linprocfs_doproccmdline(PFS_FILL_ARGS)
739{
740	struct ps_strings pstr;
741	char **ps_argvstr;
742	int error, i;
743
744	/*
745	 * If we are using the ps/cmdline caching, use that.  Otherwise
746	 * revert back to the old way which only implements full cmdline
747	 * for the currept process and just p->p_comm for all other
748	 * processes.
749	 * Note that if the argv is no longer available, we deliberately
750	 * don't fall back on p->p_comm or return an error: the authentic
751	 * Linux behaviour is to return zero-length in this case.
752	 */
753
754	PROC_LOCK(p);
755	if (p->p_args && p_cansee(td, p) == 0) {
756		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
757		PROC_UNLOCK(p);
758	} else if (p != td->td_proc) {
759		PROC_UNLOCK(p);
760		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
761	} else {
762		PROC_UNLOCK(p);
763		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
764		    sizeof(pstr));
765		if (error)
766			return (error);
767		if (pstr.ps_nargvstr > ARG_MAX)
768			return (E2BIG);
769		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
770		    M_TEMP, M_WAITOK);
771		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
772		    pstr.ps_nargvstr * sizeof(char *));
773		if (error) {
774			free(ps_argvstr, M_TEMP);
775			return (error);
776		}
777		for (i = 0; i < pstr.ps_nargvstr; i++) {
778			sbuf_copyin(sb, ps_argvstr[i], 0);
779			sbuf_printf(sb, "%c", '\0');
780		}
781		free(ps_argvstr, M_TEMP);
782	}
783
784	return (0);
785}
786
787/*
788 * Filler function for proc/pid/environ
789 */
790static int
791linprocfs_doprocenviron(PFS_FILL_ARGS)
792{
793	sbuf_printf(sb, "doprocenviron\n%c", '\0');
794
795	return (0);
796}
797
798/*
799 * Filler function for proc/pid/maps
800 */
801static int
802linprocfs_doprocmaps(PFS_FILL_ARGS)
803{
804	char mebuffer[512];
805	vm_map_t map = &p->p_vmspace->vm_map;
806	vm_map_entry_t entry;
807	vm_object_t obj, tobj, lobj;
808	vm_ooffset_t off = 0;
809	char *name = "", *freename = NULL;
810	size_t len;
811	ino_t ino;
812	int ref_count, shadow_count, flags;
813	int error;
814	struct vnode *vp;
815	struct vattr vat;
816	int locked;
817
818	PROC_LOCK(p);
819	error = p_candebug(td, p);
820	PROC_UNLOCK(p);
821	if (error)
822		return (error);
823
824	if (uio->uio_rw != UIO_READ)
825		return (EOPNOTSUPP);
826
827	if (uio->uio_offset != 0)
828		return (0);
829
830	error = 0;
831	if (map != &curthread->td_proc->p_vmspace->vm_map)
832		vm_map_lock_read(map);
833        for (entry = map->header.next;
834	    ((uio->uio_resid > 0) && (entry != &map->header));
835	    entry = entry->next) {
836		name = "";
837		freename = NULL;
838		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
839			continue;
840		obj = entry->object.vm_object;
841		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
842			lobj = tobj;
843		ino = 0;
844		if (lobj) {
845			VM_OBJECT_LOCK(lobj);
846			off = IDX_TO_OFF(lobj->size);
847			if (lobj->type == OBJT_VNODE) {
848				vp = lobj->handle;
849				if (vp)
850					vref(vp);
851			}
852			else
853				vp = NULL;
854			flags = obj->flags;
855			ref_count = obj->ref_count;
856			shadow_count = obj->shadow_count;
857			VM_OBJECT_UNLOCK(lobj);
858			if (vp) {
859				vn_fullpath(td, vp, &name, &freename);
860				locked = VFS_LOCK_GIANT(vp->v_mount);
861				vn_lock(vp, LK_SHARED | LK_RETRY, td);
862				VOP_GETATTR(vp, &vat, td->td_ucred, td);
863				ino = vat.va_fileid;
864				vput(vp);
865				VFS_UNLOCK_GIANT(locked);
866			}
867		} else {
868			flags = 0;
869			ref_count = 0;
870			shadow_count = 0;
871		}
872
873		/*
874	     	 * format:
875		 *  start, end, access, offset, major, minor, inode, name.
876		 */
877		snprintf(mebuffer, sizeof mebuffer,
878		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
879		    (u_long)entry->start, (u_long)entry->end,
880		    (entry->protection & VM_PROT_READ)?"r":"-",
881		    (entry->protection & VM_PROT_WRITE)?"w":"-",
882		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
883		    "p",
884		    (u_long)off,
885		    0,
886		    0,
887		    (u_long)ino,
888		    *name ? "     " : "",
889		    name
890		    );
891		if (freename)
892			free(freename, M_TEMP);
893		len = strlen(mebuffer);
894		if (len > uio->uio_resid)
895			len = uio->uio_resid; /*
896					       * XXX We should probably return
897					       * EFBIG here, as in procfs.
898					       */
899		error = uiomove(mebuffer, len, uio);
900		if (error)
901			break;
902	}
903	if (map != &curthread->td_proc->p_vmspace->vm_map)
904		vm_map_unlock_read(map);
905
906	return (error);
907}
908
909/*
910 * Filler function for proc/net/dev
911 */
912static int
913linprocfs_donetdev(PFS_FILL_ARGS)
914{
915	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
916	struct ifnet *ifp;
917
918	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
919	    "Inter-", "   Receive", "  Transmit", " face",
920	    "bytes    packets errs drop fifo frame compressed",
921	    "bytes    packets errs drop fifo frame compressed");
922
923	IFNET_RLOCK();
924	TAILQ_FOREACH(ifp, &ifnet, if_link) {
925		linux_ifname(ifp, ifname, sizeof ifname);
926			sbuf_printf(sb, "%6.6s:", ifname);
927		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
928		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
929		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
930		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
931	}
932	IFNET_RUNLOCK();
933
934	return (0);
935}
936
937/*
938 * Filler function for proc/sys/kernel/msgmni
939 */
940static int
941linprocfs_domsgmni(PFS_FILL_ARGS)
942{
943	int msgmni;
944	size_t size;
945
946	size = sizeof(msgmni);
947	if (kernel_sysctlbyname(td, "kern.ipc.msgmni", &msgmni, &size,
948	    0, 0, 0, 0) != 0)
949		msgmni = 0;
950	sbuf_printf(sb, "%i\n", msgmni);
951
952	return (0);
953}
954
955/*
956 * Filler function for proc/sys/kernel/pid_max
957 */
958static int
959linprocfs_dopid_max(PFS_FILL_ARGS)
960{
961
962	sbuf_printf(sb, "%i\n", PID_MAX);
963
964	return (0);
965}
966
967/*
968 * Filler function for proc/sys/kernel/sem
969 */
970static int
971linprocfs_dosem(PFS_FILL_ARGS)
972{
973	int semmsl, semmns, semopm, semmni;
974	size_t size;
975
976	/* Field 1: SEMMSL */
977	size = sizeof(semmsl);
978	if (kernel_sysctlbyname(td, "kern.ipc.semmsl", &semmsl, &size,
979	    0, 0, 0, 0) != 0)
980		semmsl = 0;
981
982	/* Field 2: SEMMNS */
983	size = sizeof(semmns);
984	if (kernel_sysctlbyname(td, "kern.ipc.semmns", &semmns, &size,
985	    0, 0, 0, 0) != 0)
986		semmns = 0;
987
988	/* Field 3: SEMOPM */
989	size = sizeof(semopm);
990	if (kernel_sysctlbyname(td, "kern.ipc.semopm", &semopm, &size,
991	    0, 0, 0, 0) != 0)
992		semopm = 0;
993
994	/* Field 4: SEMMNI */
995	size = sizeof(semmni);
996	if (kernel_sysctlbyname(td, "kern.ipc.semmni", &semmni, &size,
997	    0, 0, 0, 0) != 0)
998		semmni = 0;
999
1000	sbuf_printf(sb, "%i %i %i %i\n", semmsl, semmns, semopm, semmni);
1001
1002	return (0);
1003}
1004
1005/*
1006 * Filler function for proc/scsi/device_info
1007 */
1008static int
1009linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1010{
1011	return (0);
1012}
1013
1014/*
1015 * Filler function for proc/scsi/scsi
1016 */
1017static int
1018linprocfs_doscsiscsi(PFS_FILL_ARGS)
1019{
1020	return (0);
1021}
1022
1023extern struct cdevsw *cdevsw[];
1024
1025/*
1026 * Filler function for proc/devices
1027 */
1028static int
1029linprocfs_dodevices(PFS_FILL_ARGS)
1030{
1031	char *char_devices;
1032	sbuf_printf(sb, "Character devices:\n");
1033
1034	char_devices = linux_get_char_devices();
1035	sbuf_printf(sb, "%s", char_devices);
1036	linux_free_get_char_devices(char_devices);
1037
1038	sbuf_printf(sb, "\nBlock devices:\n");
1039
1040	return (0);
1041}
1042
1043/*
1044 * Filler function for proc/cmdline
1045 */
1046static int
1047linprocfs_docmdline(PFS_FILL_ARGS)
1048{
1049	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1050	sbuf_printf(sb, " ro root=302\n");
1051	return (0);
1052}
1053
1054#if 0
1055/*
1056 * Filler function for proc/modules
1057 */
1058static int
1059linprocfs_domodules(PFS_FILL_ARGS)
1060{
1061	struct linker_file *lf;
1062
1063	TAILQ_FOREACH(lf, &linker_files, link) {
1064		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1065		    (unsigned long)lf->size, lf->refs);
1066	}
1067	return (0);
1068}
1069#endif
1070
1071/*
1072 * Constructor
1073 */
1074static int
1075linprocfs_init(PFS_INIT_ARGS)
1076{
1077	struct pfs_node *root;
1078	struct pfs_node *dir;
1079
1080	root = pi->pi_root;
1081
1082	/* /proc/... */
1083	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1084	    NULL, NULL, PFS_RD);
1085	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1086	    NULL, NULL, PFS_RD);
1087	pfs_create_file(root, "devices", &linprocfs_dodevices,
1088	    NULL, NULL, PFS_RD);
1089	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1090	    NULL, NULL, PFS_RD);
1091	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1092	    NULL, NULL, PFS_RD);
1093#if 0
1094	pfs_create_file(root, "modules", &linprocfs_domodules,
1095	    NULL, NULL, PFS_RD);
1096#endif
1097	pfs_create_file(root, "mounts", &linprocfs_domtab,
1098	    NULL, NULL, PFS_RD);
1099	pfs_create_file(root, "mtab", &linprocfs_domtab,
1100	    NULL, NULL, PFS_RD);
1101	pfs_create_link(root, "self", &procfs_docurproc,
1102	    NULL, NULL, 0);
1103	pfs_create_file(root, "stat", &linprocfs_dostat,
1104	    NULL, NULL, PFS_RD);
1105	pfs_create_file(root, "uptime", &linprocfs_douptime,
1106	    NULL, NULL, PFS_RD);
1107	pfs_create_file(root, "version", &linprocfs_doversion,
1108	    NULL, NULL, PFS_RD);
1109
1110	/* /proc/net/... */
1111	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1112	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1113	    NULL, NULL, PFS_RD);
1114
1115	/* /proc/<pid>/... */
1116	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1117	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1118	    NULL, NULL, PFS_RD);
1119	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1120	    NULL, NULL, 0);
1121	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1122	    NULL, NULL, PFS_RD);
1123	pfs_create_link(dir, "exe", &procfs_doprocfile,
1124	    NULL, &procfs_notsystem, 0);
1125	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1126	    NULL, NULL, PFS_RD);
1127	pfs_create_file(dir, "mem", &procfs_doprocmem,
1128	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1129	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1130	    NULL, NULL, 0);
1131	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1132	    NULL, NULL, PFS_RD);
1133	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1134	    NULL, NULL, PFS_RD);
1135	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1136	    NULL, NULL, PFS_RD);
1137
1138	/* /proc/scsi/... */
1139	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1140	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1141	    NULL, NULL, PFS_RD);
1142	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1143	    NULL, NULL, PFS_RD);
1144
1145	/* /proc/sys/... */
1146	dir = pfs_create_dir(root, "sys", NULL, NULL, 0);
1147	/* /proc/sys/kernel/... */
1148	dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0);
1149	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1150	    NULL, NULL, PFS_RD);
1151	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1152	    NULL, NULL, PFS_RD);
1153	pfs_create_file(dir, "sem", &linprocfs_dosem,
1154	    NULL, NULL, PFS_RD);
1155
1156	return (0);
1157}
1158
1159/*
1160 * Destructor
1161 */
1162static int
1163linprocfs_uninit(PFS_INIT_ARGS)
1164{
1165
1166	/* nothing to do, pseudofs will GC */
1167	return (0);
1168}
1169
1170PSEUDOFS(linprocfs, 1);
1171MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1172MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1173