linprocfs.c revision 139743
1139743Simp/*-
265577Sdes * 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
42116173Sobrien#include <sys/cdefs.h>
43116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 139743 2005-01-05 22:34:37Z imp $");
44116173Sobrien
4559412Smsmith#include <sys/param.h>
4683926Sdes#include <sys/queue.h>
4776166Smarkm#include <sys/blist.h>
4874135Sjlemon#include <sys/conf.h>
4983926Sdes#include <sys/exec.h>
50119911Sdes#include <sys/filedesc.h>
5176166Smarkm#include <sys/jail.h>
5265633Sdes#include <sys/kernel.h>
5383926Sdes#include <sys/linker.h>
5476166Smarkm#include <sys/lock.h>
5574135Sjlemon#include <sys/malloc.h>
5678025Sdes#include <sys/mount.h>
5776827Salfred#include <sys/mutex.h>
5885289Sdes#include <sys/namei.h>
5965633Sdes#include <sys/proc.h>
6065633Sdes#include <sys/resourcevar.h>
6169995Sdes#include <sys/sbuf.h>
62123246Sdes#include <sys/smp.h>
6383926Sdes#include <sys/socket.h>
6476839Sjlemon#include <sys/sysctl.h>
6583926Sdes#include <sys/systm.h>
6665633Sdes#include <sys/tty.h>
6783926Sdes#include <sys/user.h>
6883926Sdes#include <sys/vmmeter.h>
6959412Smsmith#include <sys/vnode.h>
7059412Smsmith
7183926Sdes#include <net/if.h>
7283926Sdes
7359412Smsmith#include <vm/vm.h>
7459412Smsmith#include <vm/pmap.h>
7567588Sdes#include <vm/vm_map.h>
7659412Smsmith#include <vm/vm_param.h>
7760860Sdes#include <vm/vm_object.h>
7859412Smsmith#include <vm/swap_pager.h>
7969799Sdes
8067589Sdes#include <machine/clock.h>
8178113Sdes
8278113Sdes#ifdef __alpha__
8378113Sdes#include <machine/alpha_cpu.h>
8478113Sdes#include <machine/cpuconf.h>
8578113Sdes#include <machine/rpb.h>
8678113Sdesextern int ncpus;
8778113Sdes#endif /* __alpha__ */
8878113Sdes
89133822Stjr#if defined(__i386__) || defined(__amd64__)
9067589Sdes#include <machine/cputypes.h>
9159412Smsmith#include <machine/md_var.h>
92133822Stjr#endif /* __i386__ || __amd64__ */
9359412Smsmith
94133822Stjr#include "opt_compat.h"
95133822Stjr#if !COMPAT_LINUX32				/* XXX */
9687275Srwatson#include <machine/../linux/linux.h>
97133822Stjr#else
98133822Stjr#include <machine/../linux32/linux.h>
99133822Stjr#endif
10085129Sdes#include <compat/linux/linux_ioctl.h>
10169995Sdes#include <compat/linux/linux_mib.h>
10285289Sdes#include <compat/linux/linux_util.h>
10378025Sdes#include <fs/pseudofs/pseudofs.h>
10484248Sdes#include <fs/procfs/procfs.h>
10559412Smsmith
10667588Sdes/*
10767588Sdes * Various conversion macros
10867588Sdes */
10976405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
11067588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11167588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11269799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11367588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11467588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11574135Sjlemon
11678113Sdes/*
11778113Sdes * Filler function for proc/meminfo
11878113Sdes */
11978025Sdesstatic int
12078025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
12159412Smsmith{
12259412Smsmith	unsigned long memtotal;		/* total memory in bytes */
12359412Smsmith	unsigned long memused;		/* used memory in bytes */
12459412Smsmith	unsigned long memfree;		/* free memory in bytes */
12559412Smsmith	unsigned long memshared;	/* shared memory ??? */
12659412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
127113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
128113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
129113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
13060860Sdes	vm_object_t object;
131117723Sphk	int i, j;
13259412Smsmith
13359412Smsmith	memtotal = physmem * PAGE_SIZE;
13459412Smsmith	/*
13559412Smsmith	 * The correct thing here would be:
13659412Smsmith	 *
13759412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13859412Smsmith	memused = memtotal - memfree;
13959412Smsmith	 *
14059412Smsmith	 * but it might mislead linux binaries into thinking there
14159412Smsmith	 * is very little memory left, so we cheat and tell them that
14259412Smsmith	 * all memory that isn't wired down is free.
14359412Smsmith	 */
14459412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
14559412Smsmith	memfree = memtotal - memused;
146117723Sphk	swap_pager_status(&i, &j);
147117723Sphk	swaptotal = i * PAGE_SIZE;
148117723Sphk	swapused = j * PAGE_SIZE;
149117723Sphk	swapfree = swaptotal - swapused;
15060860Sdes	memshared = 0;
151124082Salc	mtx_lock(&vm_object_list_mtx);
15271471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
15360860Sdes		if (object->shadow_count > 1)
15460860Sdes			memshared += object->resident_page_count;
155124082Salc	mtx_unlock(&vm_object_list_mtx);
15660860Sdes	memshared *= PAGE_SIZE;
15759412Smsmith	/*
15859412Smsmith	 * We'd love to be able to write:
15959412Smsmith	 *
16059412Smsmith	buffers = bufspace;
16159412Smsmith	 *
16259412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
16359412Smsmith	 * like unstaticizing it just for linprocfs's sake.
16459412Smsmith	 */
16559412Smsmith	buffers = 0;
16659412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
16759412Smsmith
16878025Sdes	sbuf_printf(sb,
16978031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
17069799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
17176839Sjlemon	    "Swap: %llu %llu %llu\n"
17269799Sdes	    "MemTotal: %9lu kB\n"
17369799Sdes	    "MemFree:  %9lu kB\n"
17469799Sdes	    "MemShared:%9lu kB\n"
17569799Sdes	    "Buffers:  %9lu kB\n"
17669799Sdes	    "Cached:   %9lu kB\n"
17776839Sjlemon	    "SwapTotal:%9llu kB\n"
17876839Sjlemon	    "SwapFree: %9llu kB\n",
17969799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
18069799Sdes	    swaptotal, swapused, swapfree,
18169799Sdes	    B2K(memtotal), B2K(memfree),
18269799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
18369799Sdes	    B2K(swaptotal), B2K(swapfree));
18459412Smsmith
18578025Sdes	return (0);
18659412Smsmith}
18759412Smsmith
18878113Sdes#ifdef __alpha__
189119008Smarcelextern struct rpb *hwrpb;
19078113Sdes/*
19178113Sdes * Filler function for proc/cpuinfo (Alpha version)
19278113Sdes */
19378025Sdesstatic int
19478025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
19559412Smsmith{
19678113Sdes	u_int64_t type, major;
19778113Sdes	struct pcs *pcsp;
19878113Sdes	const char *model, *sysname;
19978113Sdes
20078113Sdes	static const char *cpuname[] = {
20178113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
20278113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
20378113Sdes	};
20478113Sdes
20578113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
20678113Sdes	type = pcsp->pcs_proc_type;
20778113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20878113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20978113Sdes		model = cpuname[major - 1];
21078113Sdes	} else {
21178113Sdes		model = "unknown";
21278113Sdes	}
213119068Sdes
21478113Sdes	sysname = alpha_dsr_sysname();
215119068Sdes
21678113Sdes	sbuf_printf(sb,
21778113Sdes	    "cpu\t\t\t: Alpha\n"
21878113Sdes	    "cpu model\t\t: %s\n"
21978113Sdes	    "cpu variation\t\t: %ld\n"
220113574Sjhb	    "cpu revision\t\t: %d\n"
22178113Sdes	    "cpu serial number\t: %s\n"
22278113Sdes	    "system type\t\t: %s\n"
22378113Sdes	    "system variation\t: %s\n"
224113574Sjhb	    "system revision\t\t: %d\n"
22578113Sdes	    "system serial number\t: %s\n"
22678113Sdes	    "cycle frequency [Hz]\t: %lu\n"
227113574Sjhb	    "timer frequency [Hz]\t: %u\n"
22878113Sdes	    "page size [bytes]\t: %ld\n"
22978113Sdes	    "phys. address bits\t: %ld\n"
23078113Sdes	    "max. addr. space #\t: %ld\n"
231113574Sjhb	    "BogoMIPS\t\t: %u.%02u\n"
232113574Sjhb	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
233113574Sjhb	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
23478113Sdes	    "platform string\t\t: %s\n"
23578113Sdes	    "cpus detected\t\t: %d\n"
23678113Sdes	    ,
23778113Sdes	    model,
23878113Sdes	    pcsp->pcs_proc_var,
23978113Sdes	    *(int *)hwrpb->rpb_revision,
24078113Sdes	    " ",
24178113Sdes	    " ",
24278113Sdes	    "0",
24378113Sdes	    0,
24478113Sdes	    " ",
24578113Sdes	    hwrpb->rpb_cc_freq,
24678113Sdes	    hz,
24778113Sdes	    hwrpb->rpb_page_size,
24878113Sdes	    hwrpb->rpb_phys_addr_size,
24978113Sdes	    hwrpb->rpb_max_asn,
25078113Sdes	    0, 0,
25178113Sdes	    0, 0, 0,
25278113Sdes	    0, 0, 0,
25378113Sdes	    sysname,
25478113Sdes	    ncpus);
25578113Sdes	return (0);
25678113Sdes}
25778113Sdes#endif /* __alpha__ */
25878113Sdes
259133822Stjr#if defined(__i386__) || defined(__amd64__)
26078113Sdes/*
261133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
26278113Sdes */
26378113Sdesstatic int
26478113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
26578113Sdes{
266123246Sdes	int class, fqmhz, fqkhz;
267118421Sdes	int i;
26859412Smsmith
26969799Sdes	/*
27078031Sdes	 * We default the flags to include all non-conflicting flags,
27178031Sdes	 * and the Intel versions of conflicting flags.
27269799Sdes	 */
27378031Sdes	static char *flags[] = {
27478031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
27578031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
27678031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
27778031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
27878031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27978031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
28067589Sdes		"3dnowext", "3dnow"
28167589Sdes	};
28267589Sdes
28359412Smsmith	switch (cpu_class) {
284133822Stjr#ifdef __i386__
28559412Smsmith	case CPUCLASS_286:
28667589Sdes		class = 2;
28759412Smsmith		break;
28859412Smsmith	case CPUCLASS_386:
28967589Sdes		class = 3;
29059412Smsmith		break;
29159412Smsmith	case CPUCLASS_486:
29267589Sdes		class = 4;
29359412Smsmith		break;
29459412Smsmith	case CPUCLASS_586:
29567589Sdes		class = 5;
29659412Smsmith		break;
29759412Smsmith	case CPUCLASS_686:
29867589Sdes		class = 6;
29959412Smsmith		break;
30059412Smsmith	default:
30178031Sdes		class = 0;
30259412Smsmith		break;
303133822Stjr#else
304133822Stjr	default:
305133822Stjr		class = 6;
306133822Stjr		break;
307133822Stjr#endif
30859412Smsmith	}
30959412Smsmith
310123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
311118421Sdes		sbuf_printf(sb,
312118421Sdes		    "processor\t: %d\n"
313118421Sdes		    "vendor_id\t: %.20s\n"
314118421Sdes		    "cpu family\t: %d\n"
315118421Sdes		    "model\t\t: %d\n"
316118421Sdes		    "stepping\t: %d\n",
317118421Sdes		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
318118421Sdes		/* XXX per-cpu vendor / class / id? */
319118421Sdes	}
32059412Smsmith
32178031Sdes	sbuf_cat(sb,
32278031Sdes	    "flags\t\t:");
32367589Sdes
32478031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
32567589Sdes		flags[16] = "fcmov";
32678031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
32767589Sdes		flags[24] = "cxmmx";
32878031Sdes	}
329119068Sdes
33078031Sdes	for (i = 0; i < 32; i++)
33167589Sdes		if (cpu_feature & (1 << i))
33278025Sdes			sbuf_printf(sb, " %s", flags[i]);
33378025Sdes	sbuf_cat(sb, "\n");
33478031Sdes	if (class >= 5) {
33569799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
33669799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
33778025Sdes		sbuf_printf(sb,
33869799Sdes		    "cpu MHz\t\t: %d.%02d\n"
33969799Sdes		    "bogomips\t: %d.%02d\n",
34069799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
34178031Sdes	}
34269995Sdes
34378025Sdes	return (0);
34459412Smsmith}
345133822Stjr#endif /* __i386__ || __amd64__ */
34665633Sdes
34778113Sdes/*
34885289Sdes * Filler function for proc/mtab
34985289Sdes *
35085289Sdes * This file doesn't exist in Linux' procfs, but is included here so
35185289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
35285289Sdes */
35385289Sdesstatic int
35485289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
35585289Sdes{
35685289Sdes	struct nameidata nd;
35785289Sdes	struct mount *mp;
35891334Sjulian	const char *lep;
35991334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
36085289Sdes	size_t lep_len;
36185289Sdes	int error;
36285289Sdes
36385289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
36485289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
36585289Sdes	flep = NULL;
366124407Srwatson	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
36785289Sdes		lep = linux_emul_path;
36891334Sjulian	else
36991334Sjulian		lep = dlep;
37085289Sdes	lep_len = strlen(lep);
371119068Sdes
37285289Sdes	mtx_lock(&mountlist_mtx);
37385289Sdes	error = 0;
37485289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
37585289Sdes		/* determine device name */
37685289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
377119068Sdes
37885289Sdes		/* determine mount point */
37985289Sdes		mntto = mp->mnt_stat.f_mntonname;
38085289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
38185289Sdes		    mntto[lep_len] == '/')
38285289Sdes			mntto += lep_len;
38385289Sdes
38485289Sdes		/* determine fs type */
38585289Sdes		fstype = mp->mnt_stat.f_fstypename;
38685289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
38785289Sdes			mntfrom = fstype = "proc";
38885289Sdes		else if (strcmp(fstype, "procfs") == 0)
38985289Sdes			continue;
390119068Sdes
39185289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
39285289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
39385289Sdes#define ADD_OPTION(opt, name) \
39485289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
39585289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
39685289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
39785289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
39885289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
39985289Sdes		ADD_OPTION(MNT_UNION,		"union");
40085289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
40185289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
40285289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
40385289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
40485289Sdes#undef ADD_OPTION
40585289Sdes		/* a real Linux mtab will also show NFS options */
40685289Sdes		sbuf_printf(sb, " 0 0\n");
40785289Sdes	}
40885289Sdes	mtx_unlock(&mountlist_mtx);
40985289Sdes	if (flep != NULL)
41085289Sdes		free(flep, M_TEMP);
41185289Sdes	return (error);
41285289Sdes}
41385289Sdes
41485289Sdes/*
41578113Sdes * Filler function for proc/stat
41678113Sdes */
41778025Sdesstatic int
41878025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
41965633Sdes{
420123246Sdes	int i;
421120339Sdes
422120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
423120339Sdes	    T2J(cp_time[CP_USER]),
424120339Sdes	    T2J(cp_time[CP_NICE]),
425120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
426120339Sdes	    T2J(cp_time[CP_IDLE]));
427123246Sdes	if (mp_ncpus > 1)
428123246Sdes		for (i = 0; i < mp_ncpus; ++i)
429120340Sdes			sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
430123246Sdes			    T2J(cp_time[CP_USER]) / mp_ncpus,
431123246Sdes			    T2J(cp_time[CP_NICE]) / mp_ncpus,
432123246Sdes			    T2J(cp_time[CP_SYS]) / mp_ncpus,
433123246Sdes			    T2J(cp_time[CP_IDLE]) / mp_ncpus);
43478025Sdes	sbuf_printf(sb,
43569799Sdes	    "disk 0 0 0 0\n"
43669799Sdes	    "page %u %u\n"
43769799Sdes	    "swap %u %u\n"
43869799Sdes	    "intr %u\n"
43969799Sdes	    "ctxt %u\n"
44085657Sdillon	    "btime %lld\n",
44169799Sdes	    cnt.v_vnodepgsin,
44269799Sdes	    cnt.v_vnodepgsout,
44369799Sdes	    cnt.v_swappgsin,
44469799Sdes	    cnt.v_swappgsout,
44569799Sdes	    cnt.v_intr,
44669799Sdes	    cnt.v_swtch,
447113574Sjhb	    (long long)boottime.tv_sec);
44878025Sdes	return (0);
44965633Sdes}
45065633Sdes
45178113Sdes/*
45278113Sdes * Filler function for proc/uptime
45378113Sdes */
45478025Sdesstatic int
45578025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
45665633Sdes{
45765633Sdes	struct timeval tv;
45865633Sdes
45965633Sdes	getmicrouptime(&tv);
46085657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
461113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
46269799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
46378025Sdes	return (0);
46465633Sdes}
46565633Sdes
46678113Sdes/*
46778113Sdes * Filler function for proc/version
46878113Sdes */
46978025Sdesstatic int
47078025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
47165633Sdes{
47287275Srwatson	char osname[LINUX_MAX_UTSNAME];
47387275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
47487275Srwatson
475112206Sjhb	linux_get_osname(td, osname);
476112206Sjhb	linux_get_osrelease(td, osrelease);
47787275Srwatson
47878025Sdes	sbuf_printf(sb,
47969995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
48087275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
48178025Sdes	return (0);
48265633Sdes}
48365633Sdes
48478113Sdes/*
48578113Sdes * Filler function for proc/loadavg
48678113Sdes */
48778025Sdesstatic int
48878025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
48976839Sjlemon{
49078025Sdes	sbuf_printf(sb,
49176839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
49276839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
49376839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
49476839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
49576839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
49676839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
49776839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
49876839Sjlemon	    1,				/* number of running tasks */
49976839Sjlemon	    nprocs,			/* number of tasks */
50078116Sdes	    lastpid			/* the last pid */
50176839Sjlemon	);
502119068Sdes
50378025Sdes	return (0);
50476839Sjlemon}
50576839Sjlemon
50678113Sdes/*
50778113Sdes * Filler function for proc/pid/stat
50878113Sdes */
50978025Sdesstatic int
51078025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
51167588Sdes{
51269995Sdes	struct kinfo_proc kp;
51367588Sdes
51494307Sjhb	PROC_LOCK(p);
51569995Sdes	fill_kinfo_proc(p, &kp);
51678025Sdes	sbuf_printf(sb, "%d", p->p_pid);
51778025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
51867588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
51967588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
52073923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
52167588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
52267588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
52391140Stanimura	PROC_UNLOCK(p);
52467588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
52567588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
52667588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
52767588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
52867588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
52967588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
53067588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
53167588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
53267588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
53367588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
53467588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
53567588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
53667588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
53767588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
53867588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
53967588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
540113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
541113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
54267588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
54369995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
54467588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
54567588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
54669799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
54769799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
54867588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
54967588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
55067588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
55167588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
55267588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
55369799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
55469799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
55569799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
55669799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
55767588Sdes#undef PS_ADD
55878025Sdes	sbuf_putc(sb, '\n');
559119068Sdes
56078025Sdes	return (0);
56167588Sdes}
56267588Sdes
56367588Sdes/*
564119911Sdes * Filler function for proc/pid/statm
565119911Sdes */
566119911Sdesstatic int
567119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
568119911Sdes{
569119911Sdes	struct kinfo_proc kp;
570119911Sdes	segsz_t lsize;
571120340Sdes
572119911Sdes	PROC_LOCK(p);
573119911Sdes	fill_kinfo_proc(p, &kp);
574119911Sdes	PROC_UNLOCK(p);
575119911Sdes
576119911Sdes	/*
577119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
578119911Sdes	 * computation of lsize.
579119911Sdes	 */
580119911Sdes	/* size resident share trs drs lrs dt */
581119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
582119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
583119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
584119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
585119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
586119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
587119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
588119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
589119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
590119911Sdes
591119911Sdes	return (0);
592119911Sdes}
593119911Sdes
594119911Sdes/*
59578113Sdes * Filler function for proc/pid/status
59678113Sdes */
59778025Sdesstatic int
59878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
59967588Sdes{
60069995Sdes	struct kinfo_proc kp;
60167588Sdes	char *state;
60269799Sdes	segsz_t lsize;
60399072Sjulian	struct thread *td2;
604114983Sjhb	struct sigacts *ps;
60574135Sjlemon	int i;
60667588Sdes
607113611Sjhb	PROC_LOCK(p);
60899072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
60999072Sjulian
61099072Sjulian	if (P_SHOULDSTOP(p)) {
61199072Sjulian		state = "T (stopped)";
61299072Sjulian	} else {
613113611Sjhb		mtx_lock_spin(&sched_lock);
61499072Sjulian		switch(p->p_state) {
61599072Sjulian		case PRS_NEW:
61699072Sjulian			state = "I (idle)";
61799072Sjulian			break;
61899072Sjulian		case PRS_NORMAL:
61999072Sjulian			if (p->p_flag & P_WEXIT) {
62099072Sjulian				state = "X (exiting)";
62199072Sjulian				break;
62299072Sjulian			}
62399072Sjulian			switch(td2->td_state) {
624103216Sjulian			case TDS_INHIBITED:
62599072Sjulian				state = "S (sleeping)";
62699072Sjulian				break;
62799072Sjulian			case TDS_RUNQ:
62899072Sjulian			case TDS_RUNNING:
62999072Sjulian				state = "R (running)";
63099072Sjulian				break;
63199072Sjulian			default:
63299072Sjulian				state = "? (unknown)";
63399072Sjulian				break;
63499072Sjulian			}
63599072Sjulian			break;
63699072Sjulian		case PRS_ZOMBIE:
63799072Sjulian			state = "Z (zombie)";
63899072Sjulian			break;
63999072Sjulian		default:
64099072Sjulian			state = "? (unknown)";
64199072Sjulian			break;
64299072Sjulian		}
643113611Sjhb		mtx_unlock_spin(&sched_lock);
64499072Sjulian	}
64567588Sdes
64669995Sdes	fill_kinfo_proc(p, &kp);
64778025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
64878031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
64967588Sdes
65067588Sdes	/*
65167588Sdes	 * Credentials
65267588Sdes	 */
65378025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
65478025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
65573923Sjhb						p->p_pptr->p_pid : 0);
65678031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
65778031Sdes						p->p_ucred->cr_uid,
65878031Sdes						p->p_ucred->cr_svuid,
65978031Sdes						/* FreeBSD doesn't have fsuid */
66078031Sdes						p->p_ucred->cr_uid);
66178031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
66278031Sdes						p->p_ucred->cr_gid,
66378031Sdes						p->p_ucred->cr_svgid,
66478031Sdes						/* FreeBSD doesn't have fsgid */
66578031Sdes						p->p_ucred->cr_gid);
66678025Sdes	sbuf_cat(sb, "Groups:\t");
66767588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
66878031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
66971471Sjhb	PROC_UNLOCK(p);
67078025Sdes	sbuf_putc(sb, '\n');
671119068Sdes
67267588Sdes	/*
67367588Sdes	 * Memory
67469799Sdes	 *
67569799Sdes	 * While our approximation of VmLib may not be accurate (I
67669799Sdes	 * don't know of a simple way to verify it, and I'm not sure
67769799Sdes	 * it has much meaning anyway), I believe it's good enough.
67869799Sdes	 *
67969799Sdes	 * The same code that could (I think) accurately compute VmLib
68069799Sdes	 * could also compute VmLck, but I don't really care enough to
68169799Sdes	 * implement it. Submissions are welcome.
68267588Sdes	 */
683113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
68478025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
685113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
686113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
687113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
688113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
68969995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
69069995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
691113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
69267588Sdes
69367588Sdes	/*
69467588Sdes	 * Signal masks
69567588Sdes	 *
69667588Sdes	 * We support up to 128 signals, while Linux supports 32,
69767588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
69867588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
69967588Sdes	 *
70067588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
70167588Sdes	 * supports 64 signals, but this code is a long way from
70267588Sdes	 * running on anything but i386, so ignore that for now.
70367588Sdes	 */
70471471Sjhb	PROC_LOCK(p);
705104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
70669799Sdes	/*
70769799Sdes	 * I can't seem to find out where the signal mask is in
70869799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
70969799Sdes	 */
71078025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
711114983Sjhb	ps = p->p_sigacts;
712114983Sjhb	mtx_lock(&ps->ps_mtx);
713114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
714114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
715114983Sjhb	mtx_unlock(&ps->ps_mtx);
71671471Sjhb	PROC_UNLOCK(p);
717119068Sdes
71867588Sdes	/*
71967588Sdes	 * Linux also prints the capability masks, but we don't have
72067588Sdes	 * capabilities yet, and when we do get them they're likely to
72167588Sdes	 * be meaningless to Linux programs, so we lie. XXX
72267588Sdes	 */
72378025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
72478025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
72578025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
726119068Sdes
72778025Sdes	return (0);
72867588Sdes}
72974135Sjlemon
730119911Sdes
73178113Sdes/*
732119911Sdes * Filler function for proc/pid/cwd
733119911Sdes */
734119911Sdesstatic int
735119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
736119911Sdes{
737119911Sdes	char *fullpath = "unknown";
738119911Sdes	char *freepath = NULL;
739119911Sdes
740119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
741119911Sdes	sbuf_printf(sb, "%s", fullpath);
742119911Sdes	if (freepath)
743119911Sdes		free(freepath, M_TEMP);
744119911Sdes	return (0);
745119911Sdes}
746119911Sdes
747119911Sdes/*
748119911Sdes * Filler function for proc/pid/root
749119911Sdes */
750119911Sdesstatic int
751119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
752119911Sdes{
753119911Sdes	struct vnode *rvp;
754119911Sdes	char *fullpath = "unknown";
755119911Sdes	char *freepath = NULL;
756119911Sdes
757119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
758119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
759119911Sdes	sbuf_printf(sb, "%s", fullpath);
760119911Sdes	if (freepath)
761119911Sdes		free(freepath, M_TEMP);
762119911Sdes	return (0);
763119911Sdes}
764119911Sdes
765119911Sdes/*
76678113Sdes * Filler function for proc/pid/cmdline
76778113Sdes */
76878025Sdesstatic int
76978113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
77078113Sdes{
77178113Sdes	struct ps_strings pstr;
772138281Scperciva	char **ps_argvstr;
77378113Sdes	int error, i;
77478113Sdes
77578113Sdes	/*
77678113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
77778113Sdes	 * revert back to the old way which only implements full cmdline
77878113Sdes	 * for the currept process and just p->p_comm for all other
77978113Sdes	 * processes.
78078113Sdes	 * Note that if the argv is no longer available, we deliberately
78178113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
78278113Sdes	 * Linux behaviour is to return zero-length in this case.
78378113Sdes	 */
78478113Sdes
78594620Sjhb	PROC_LOCK(p);
786127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
78794620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
78894620Sjhb		PROC_UNLOCK(p);
78994620Sjhb	} else if (p != td->td_proc) {
79094620Sjhb		PROC_UNLOCK(p);
79194620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
79294620Sjhb	} else {
79394620Sjhb		PROC_UNLOCK(p);
794103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
795103767Sjake		    sizeof(pstr));
79694620Sjhb		if (error)
79794620Sjhb			return (error);
798138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
799138281Scperciva			return (E2BIG);
800138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
801138281Scperciva		    M_TEMP, M_WAITOK);
802138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
803138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
804138281Scperciva		if (error) {
805138281Scperciva			free(ps_argvstr, M_TEMP);
806138281Scperciva			return (error);
807138281Scperciva		}
80894620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
809138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
81094620Sjhb			sbuf_printf(sb, "%c", '\0');
81178113Sdes		}
812138281Scperciva		free(ps_argvstr, M_TEMP);
81378113Sdes	}
81478113Sdes
81578113Sdes	return (0);
81678113Sdes}
81778113Sdes
81878113Sdes/*
819116173Sobrien * Filler function for proc/pid/environ
820116173Sobrien */
821116173Sobrienstatic int
822116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
823116173Sobrien{
824116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
825116173Sobrien
826116173Sobrien	return (0);
827116173Sobrien}
828116173Sobrien
829116173Sobrien/*
830116173Sobrien * Filler function for proc/pid/maps
831116173Sobrien */
832116173Sobrienstatic int
833116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
834116173Sobrien{
835121265Scognet	char mebuffer[512];
836121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
837121246Scognet	vm_map_entry_t entry;
838121265Scognet	vm_object_t obj, tobj, lobj;
839121265Scognet	vm_ooffset_t off = 0;
840121265Scognet	char *name = "", *freename = NULL;
841121265Scognet	size_t len;
842121265Scognet	ino_t ino;
843121265Scognet	int ref_count, shadow_count, flags;
844121265Scognet	int error;
845137507Sphk	struct vnode *vp;
846137507Sphk	struct vattr vat;
847121246Scognet
848121246Scognet	PROC_LOCK(p);
849121246Scognet	error = p_candebug(td, p);
850121246Scognet	PROC_UNLOCK(p);
851121246Scognet	if (error)
852121246Scognet		return (error);
853121246Scognet
854121246Scognet	if (uio->uio_rw != UIO_READ)
855121246Scognet		return (EOPNOTSUPP);
856121246Scognet
857121246Scognet	if (uio->uio_offset != 0)
858121246Scognet		return (0);
859121246Scognet
860121246Scognet	error = 0;
861121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
862121246Scognet		vm_map_lock_read(map);
863121246Scognet        for (entry = map->header.next;
864121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
865121246Scognet	    entry = entry->next) {
866121265Scognet		name = "";
867121265Scognet		freename = NULL;
868121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
869121246Scognet			continue;
870121246Scognet		obj = entry->object.vm_object;
871121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
872121246Scognet			lobj = tobj;
873121246Scognet		ino = 0;
874121246Scognet		if (lobj) {
875137507Sphk			vp = lobj->handle;
876121246Scognet			VM_OBJECT_LOCK(lobj);
877121246Scognet			off = IDX_TO_OFF(lobj->size);
878121246Scognet			if (lobj->type == OBJT_VNODE && lobj->handle) {
879137507Sphk				vn_fullpath(td, vp, &name, &freename);
880137507Sphk				VOP_GETATTR(vp, &vat, td->td_ucred, td);
881137507Sphk				ino = vat.va_fileid;
882121246Scognet			}
883121246Scognet			flags = obj->flags;
884121246Scognet			ref_count = obj->ref_count;
885121246Scognet			shadow_count = obj->shadow_count;
886121246Scognet			VM_OBJECT_UNLOCK(lobj);
887121246Scognet		} else {
888121246Scognet			flags = 0;
889121246Scognet			ref_count = 0;
890121246Scognet			shadow_count = 0;
891121246Scognet		}
892121246Scognet
893121246Scognet		/*
894121246Scognet	     	 * format:
895121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
896121246Scognet		 */
897121246Scognet		snprintf(mebuffer, sizeof mebuffer,
898121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
899121246Scognet		    (u_long)entry->start, (u_long)entry->end,
900121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
901121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
902121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
903121246Scognet		    "p",
904121265Scognet		    (u_long)off,
905121246Scognet		    0,
906121246Scognet		    0,
907121265Scognet		    (u_long)ino,
908121246Scognet		    *name ? "     " : "",
909121246Scognet		    name
910121246Scognet		    );
911121246Scognet		if (freename)
912121246Scognet			free(freename, M_TEMP);
913121246Scognet		len = strlen(mebuffer);
914121246Scognet		if (len > uio->uio_resid)
915121246Scognet			len = uio->uio_resid; /*
916121246Scognet					       * XXX We should probably return
917121246Scognet					       * EFBIG here, as in procfs.
918121246Scognet					       */
919121246Scognet		error = uiomove(mebuffer, len, uio);
920121246Scognet		if (error)
921121246Scognet			break;
922121246Scognet	}
923121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
924121246Scognet		vm_map_unlock_read(map);
925121246Scognet
926121246Scognet	return (error);
927121246Scognet}
928121246Scognet
929116173Sobrien/*
93078113Sdes * Filler function for proc/net/dev
93178113Sdes */
93278025Sdesstatic int
93378025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
93474135Sjlemon{
93585129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
93674135Sjlemon	struct ifnet *ifp;
93774135Sjlemon
93885129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
93983926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
94085129Sdes	    "bytes    packets errs drop fifo frame compressed",
94183926Sdes	    "bytes    packets errs drop fifo frame compressed");
94274135Sjlemon
943108172Shsu	IFNET_RLOCK();
94474135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
94585129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
94685129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
94783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
94883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
94983926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
95083926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
95174135Sjlemon	}
952108172Shsu	IFNET_RUNLOCK();
953119068Sdes
95478025Sdes	return (0);
95574135Sjlemon}
95674135Sjlemon
95785538Sphk#if 0
95885538Sphkextern struct cdevsw *cdevsw[];
95985538Sphk
96078113Sdes/*
96178113Sdes * Filler function for proc/devices
96278113Sdes */
96378025Sdesstatic int
96478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
96574135Sjlemon{
96674135Sjlemon	int i;
96774135Sjlemon
96878025Sdes	sbuf_printf(sb, "Character devices:\n");
96974135Sjlemon
97078025Sdes	for (i = 0; i < NUMCDEVSW; i++)
97174135Sjlemon		if (cdevsw[i] != NULL)
97278025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
97374135Sjlemon
97478025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
975119068Sdes
97678025Sdes	return (0);
97774135Sjlemon}
97885538Sphk#endif
97974135Sjlemon
98078113Sdes/*
98178113Sdes * Filler function for proc/cmdline
98278113Sdes */
98378025Sdesstatic int
98478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
98574135Sjlemon{
98678025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
98778025Sdes	sbuf_printf(sb, " ro root=302\n");
98878025Sdes	return (0);
98978025Sdes}
99074135Sjlemon
99183926Sdes#if 0
99278025Sdes/*
99383926Sdes * Filler function for proc/modules
99483926Sdes */
99583926Sdesstatic int
99683926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
99783926Sdes{
99883926Sdes	struct linker_file *lf;
999119068Sdes
100083926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
100183926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
100283926Sdes		    (unsigned long)lf->size, lf->refs);
100383926Sdes	}
100483926Sdes	return (0);
100583926Sdes}
100683926Sdes#endif
100783926Sdes
100883926Sdes/*
100985129Sdes * Constructor
101078025Sdes */
101185129Sdesstatic int
101285129Sdeslinprocfs_init(PFS_INIT_ARGS)
101385129Sdes{
101485129Sdes	struct pfs_node *root;
101585129Sdes	struct pfs_node *dir;
101674135Sjlemon
101785129Sdes	root = pi->pi_root;
101878025Sdes
1019119923Sdes	/* /proc/... */
1020119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1021119911Sdes	    NULL, NULL, PFS_RD);
1022119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1023119911Sdes	    NULL, NULL, PFS_RD);
102485538Sphk#if 0
1025119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1026119911Sdes	    NULL, NULL, PFS_RD);
102785538Sphk#endif
1028119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1029119911Sdes	    NULL, NULL, PFS_RD);
1030119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1031119911Sdes	    NULL, NULL, PFS_RD);
103283926Sdes#if 0
1033119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1034119911Sdes	    NULL, NULL, PFS_RD);
103583926Sdes#endif
1036119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1037119911Sdes	    NULL, NULL, PFS_RD);
103887543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
103985129Sdes	    NULL, NULL, 0);
1040119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1041119911Sdes	    NULL, NULL, PFS_RD);
1042119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1043119911Sdes	    NULL, NULL, PFS_RD);
1044119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1045119911Sdes	    NULL, NULL, PFS_RD);
104678025Sdes
1047119923Sdes	/* /proc/net/... */
104885129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
104985129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
105085129Sdes	    NULL, NULL, PFS_RD);
105178025Sdes
1052119923Sdes	/* /proc/<pid>/... */
105385129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
105485129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
105585129Sdes	    NULL, NULL, PFS_RD);
1056119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1057119911Sdes	    NULL, NULL, 0);
1058116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1059116173Sobrien	    NULL, NULL, PFS_RD);
106087543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
106187543Sdes	    NULL, &procfs_notsystem, 0);
1062116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1063116173Sobrien	    NULL, NULL, PFS_RD);
106485129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
106585129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1066119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1067119911Sdes	    NULL, NULL, 0);
106885129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
106985129Sdes	    NULL, NULL, PFS_RD);
1070119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1071119911Sdes	    NULL, NULL, PFS_RD);
107285129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
107385129Sdes	    NULL, NULL, PFS_RD);
107485129Sdes
107585129Sdes	return (0);
107685129Sdes}
107785129Sdes
107885129Sdes/*
107985129Sdes * Destructor
108085129Sdes */
108185129Sdesstatic int
108285129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
108385129Sdes{
108485129Sdes
108585129Sdes	/* nothing to do, pseudofs will GC */
108685129Sdes	return (0);
108785129Sdes}
108885129Sdes
108985129SdesPSEUDOFS(linprocfs, 1);
109078025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
109178025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1092