linprocfs.c revision 121265
159412Smsmith/*
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 121265 2003-10-20 04:10:20Z cognet $");
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>
6283926Sdes#include <sys/socket.h>
6376839Sjlemon#include <sys/sysctl.h>
6483926Sdes#include <sys/systm.h>
6565633Sdes#include <sys/tty.h>
6683926Sdes#include <sys/user.h>
6783926Sdes#include <sys/vmmeter.h>
6859412Smsmith#include <sys/vnode.h>
6959412Smsmith
7083926Sdes#include <net/if.h>
7183926Sdes
7259412Smsmith#include <vm/vm.h>
7359412Smsmith#include <vm/pmap.h>
7467588Sdes#include <vm/vm_map.h>
7559412Smsmith#include <vm/vm_param.h>
7660860Sdes#include <vm/vm_object.h>
7759412Smsmith#include <vm/swap_pager.h>
7869799Sdes
7967589Sdes#include <machine/clock.h>
8078113Sdes
8178113Sdes#ifdef __alpha__
8278113Sdes#include <machine/alpha_cpu.h>
8378113Sdes#include <machine/cpuconf.h>
8478113Sdes#include <machine/rpb.h>
8578113Sdesextern int ncpus;
8678113Sdes#endif /* __alpha__ */
8778113Sdes
8878113Sdes#ifdef __i386__
8967589Sdes#include <machine/cputypes.h>
9059412Smsmith#include <machine/md_var.h>
9178113Sdes#endif /* __i386__ */
9259412Smsmith
9387275Srwatson#include <machine/../linux/linux.h>
9485129Sdes#include <compat/linux/linux_ioctl.h>
9569995Sdes#include <compat/linux/linux_mib.h>
9685289Sdes#include <compat/linux/linux_util.h>
9778025Sdes#include <fs/pseudofs/pseudofs.h>
9884248Sdes#include <fs/procfs/procfs.h>
9959412Smsmith
10067588Sdes/*
10167588Sdes * Various conversion macros
10267588Sdes */
10376405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10567588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10669799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10767588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10867588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
10974135Sjlemon
11078113Sdes/*
11178113Sdes * Filler function for proc/meminfo
11278113Sdes */
11378025Sdesstatic int
11478025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
11559412Smsmith{
11659412Smsmith	unsigned long memtotal;		/* total memory in bytes */
11759412Smsmith	unsigned long memused;		/* used memory in bytes */
11859412Smsmith	unsigned long memfree;		/* free memory in bytes */
11959412Smsmith	unsigned long memshared;	/* shared memory ??? */
12059412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
121113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
122113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
123113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
12460860Sdes	vm_object_t object;
125117723Sphk	int i, j;
12659412Smsmith
12759412Smsmith	memtotal = physmem * PAGE_SIZE;
12859412Smsmith	/*
12959412Smsmith	 * The correct thing here would be:
13059412Smsmith	 *
13159412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13259412Smsmith	memused = memtotal - memfree;
13359412Smsmith	 *
13459412Smsmith	 * but it might mislead linux binaries into thinking there
13559412Smsmith	 * is very little memory left, so we cheat and tell them that
13659412Smsmith	 * all memory that isn't wired down is free.
13759412Smsmith	 */
13859412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
13959412Smsmith	memfree = memtotal - memused;
140117723Sphk	swap_pager_status(&i, &j);
141117723Sphk	swaptotal = i * PAGE_SIZE;
142117723Sphk	swapused = j * PAGE_SIZE;
143117723Sphk	swapfree = swaptotal - swapused;
14460860Sdes	memshared = 0;
14571471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14660860Sdes		if (object->shadow_count > 1)
14760860Sdes			memshared += object->resident_page_count;
14860860Sdes	memshared *= PAGE_SIZE;
14959412Smsmith	/*
15059412Smsmith	 * We'd love to be able to write:
15159412Smsmith	 *
15259412Smsmith	buffers = bufspace;
15359412Smsmith	 *
15459412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
15559412Smsmith	 * like unstaticizing it just for linprocfs's sake.
15659412Smsmith	 */
15759412Smsmith	buffers = 0;
15859412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
15959412Smsmith
16078025Sdes	sbuf_printf(sb,
16178031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
16269799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
16376839Sjlemon	    "Swap: %llu %llu %llu\n"
16469799Sdes	    "MemTotal: %9lu kB\n"
16569799Sdes	    "MemFree:  %9lu kB\n"
16669799Sdes	    "MemShared:%9lu kB\n"
16769799Sdes	    "Buffers:  %9lu kB\n"
16869799Sdes	    "Cached:   %9lu kB\n"
16976839Sjlemon	    "SwapTotal:%9llu kB\n"
17076839Sjlemon	    "SwapFree: %9llu kB\n",
17169799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
17269799Sdes	    swaptotal, swapused, swapfree,
17369799Sdes	    B2K(memtotal), B2K(memfree),
17469799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
17569799Sdes	    B2K(swaptotal), B2K(swapfree));
17659412Smsmith
17778025Sdes	return (0);
17859412Smsmith}
17959412Smsmith
18078113Sdes#ifdef __alpha__
181119008Smarcelextern struct rpb *hwrpb;
18278113Sdes/*
18378113Sdes * Filler function for proc/cpuinfo (Alpha version)
18478113Sdes */
18578025Sdesstatic int
18678025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
18759412Smsmith{
18878113Sdes	u_int64_t type, major;
18978113Sdes	struct pcs *pcsp;
19078113Sdes	const char *model, *sysname;
19178113Sdes
19278113Sdes	static const char *cpuname[] = {
19378113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
19478113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
19578113Sdes	};
19678113Sdes
19778113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
19878113Sdes	type = pcsp->pcs_proc_type;
19978113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20078113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20178113Sdes		model = cpuname[major - 1];
20278113Sdes	} else {
20378113Sdes		model = "unknown";
20478113Sdes	}
205119068Sdes
20678113Sdes	sysname = alpha_dsr_sysname();
207119068Sdes
20878113Sdes	sbuf_printf(sb,
20978113Sdes	    "cpu\t\t\t: Alpha\n"
21078113Sdes	    "cpu model\t\t: %s\n"
21178113Sdes	    "cpu variation\t\t: %ld\n"
212113574Sjhb	    "cpu revision\t\t: %d\n"
21378113Sdes	    "cpu serial number\t: %s\n"
21478113Sdes	    "system type\t\t: %s\n"
21578113Sdes	    "system variation\t: %s\n"
216113574Sjhb	    "system revision\t\t: %d\n"
21778113Sdes	    "system serial number\t: %s\n"
21878113Sdes	    "cycle frequency [Hz]\t: %lu\n"
219113574Sjhb	    "timer frequency [Hz]\t: %u\n"
22078113Sdes	    "page size [bytes]\t: %ld\n"
22178113Sdes	    "phys. address bits\t: %ld\n"
22278113Sdes	    "max. addr. space #\t: %ld\n"
223113574Sjhb	    "BogoMIPS\t\t: %u.%02u\n"
224113574Sjhb	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
225113574Sjhb	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
22678113Sdes	    "platform string\t\t: %s\n"
22778113Sdes	    "cpus detected\t\t: %d\n"
22878113Sdes	    ,
22978113Sdes	    model,
23078113Sdes	    pcsp->pcs_proc_var,
23178113Sdes	    *(int *)hwrpb->rpb_revision,
23278113Sdes	    " ",
23378113Sdes	    " ",
23478113Sdes	    "0",
23578113Sdes	    0,
23678113Sdes	    " ",
23778113Sdes	    hwrpb->rpb_cc_freq,
23878113Sdes	    hz,
23978113Sdes	    hwrpb->rpb_page_size,
24078113Sdes	    hwrpb->rpb_phys_addr_size,
24178113Sdes	    hwrpb->rpb_max_asn,
24278113Sdes	    0, 0,
24378113Sdes	    0, 0, 0,
24478113Sdes	    0, 0, 0,
24578113Sdes	    sysname,
24678113Sdes	    ncpus);
24778113Sdes	return (0);
24878113Sdes}
24978113Sdes#endif /* __alpha__ */
25078113Sdes
25178113Sdes#ifdef __i386__
25278113Sdes/*
25378113Sdes * Filler function for proc/cpuinfo (i386 version)
25478113Sdes */
25578113Sdesstatic int
25678113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
25778113Sdes{
258118421Sdes	int class, fqmhz, fqkhz, ncpu;
259118421Sdes	int name[2], olen, plen;
260118421Sdes	int i;
26159412Smsmith
262118421Sdes	name[0] = CTL_HW;
263118421Sdes	name[1] = HW_NCPU;
264118421Sdes	if (kernel_sysctl(td, name, 2, &ncpu, &olen, NULL, 0, &plen) != 0)
265118421Sdes		ncpu = 1;
266118421Sdes
26769799Sdes	/*
26878031Sdes	 * We default the flags to include all non-conflicting flags,
26978031Sdes	 * and the Intel versions of conflicting flags.
27069799Sdes	 */
27178031Sdes	static char *flags[] = {
27278031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
27378031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
27478031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
27578031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
27678031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27778031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
27867589Sdes		"3dnowext", "3dnow"
27967589Sdes	};
28067589Sdes
28159412Smsmith	switch (cpu_class) {
28259412Smsmith	case CPUCLASS_286:
28367589Sdes		class = 2;
28459412Smsmith		break;
28559412Smsmith	case CPUCLASS_386:
28667589Sdes		class = 3;
28759412Smsmith		break;
28859412Smsmith	case CPUCLASS_486:
28967589Sdes		class = 4;
29059412Smsmith		break;
29159412Smsmith	case CPUCLASS_586:
29267589Sdes		class = 5;
29359412Smsmith		break;
29459412Smsmith	case CPUCLASS_686:
29567589Sdes		class = 6;
29659412Smsmith		break;
29759412Smsmith	default:
29878031Sdes		class = 0;
29959412Smsmith		break;
30059412Smsmith	}
30159412Smsmith
302118421Sdes	for (i = 0; i < ncpu; ++i) {
303118421Sdes		sbuf_printf(sb,
304118421Sdes		    "processor\t: %d\n"
305118421Sdes		    "vendor_id\t: %.20s\n"
306118421Sdes		    "cpu family\t: %d\n"
307118421Sdes		    "model\t\t: %d\n"
308118421Sdes		    "stepping\t: %d\n",
309118421Sdes		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
310118421Sdes		/* XXX per-cpu vendor / class / id? */
311118421Sdes	}
31259412Smsmith
31378031Sdes	sbuf_cat(sb,
31478031Sdes	    "flags\t\t:");
31567589Sdes
31678031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
31767589Sdes		flags[16] = "fcmov";
31878031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
31967589Sdes		flags[24] = "cxmmx";
32078031Sdes	}
321119068Sdes
32278031Sdes	for (i = 0; i < 32; i++)
32367589Sdes		if (cpu_feature & (1 << i))
32478025Sdes			sbuf_printf(sb, " %s", flags[i]);
32578025Sdes	sbuf_cat(sb, "\n");
32678031Sdes	if (class >= 5) {
32769799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
32869799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
32978025Sdes		sbuf_printf(sb,
33069799Sdes		    "cpu MHz\t\t: %d.%02d\n"
33169799Sdes		    "bogomips\t: %d.%02d\n",
33269799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
33378031Sdes	}
33469995Sdes
33578025Sdes	return (0);
33659412Smsmith}
33778113Sdes#endif /* __i386__ */
33865633Sdes
33978113Sdes/*
34085289Sdes * Filler function for proc/mtab
34185289Sdes *
34285289Sdes * This file doesn't exist in Linux' procfs, but is included here so
34385289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
34485289Sdes */
34585289Sdesstatic int
34685289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
34785289Sdes{
34885289Sdes	struct nameidata nd;
34985289Sdes	struct mount *mp;
35091334Sjulian	const char *lep;
35191334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
35285289Sdes	size_t lep_len;
35385289Sdes	int error;
35485289Sdes
35585289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
35685289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
35785289Sdes	flep = NULL;
35891334Sjulian	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
35985289Sdes		lep = linux_emul_path;
36091334Sjulian	else
36191334Sjulian		lep = dlep;
36285289Sdes	lep_len = strlen(lep);
363119068Sdes
36485289Sdes	mtx_lock(&mountlist_mtx);
36585289Sdes	error = 0;
36685289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
36785289Sdes		error = VFS_STATFS(mp, &mp->mnt_stat, td);
36885289Sdes		if (error)
36985289Sdes			break;
37085289Sdes
37185289Sdes		/* determine device name */
37285289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
373119068Sdes
37485289Sdes		/* determine mount point */
37585289Sdes		mntto = mp->mnt_stat.f_mntonname;
37685289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
37785289Sdes		    mntto[lep_len] == '/')
37885289Sdes			mntto += lep_len;
37985289Sdes
38085289Sdes		/* determine fs type */
38185289Sdes		fstype = mp->mnt_stat.f_fstypename;
38285289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
38385289Sdes			mntfrom = fstype = "proc";
38485289Sdes		else if (strcmp(fstype, "procfs") == 0)
38585289Sdes			continue;
386119068Sdes
38785289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
38885289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
38985289Sdes#define ADD_OPTION(opt, name) \
39085289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
39185289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
39285289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
39385289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
39485289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
39585289Sdes		ADD_OPTION(MNT_UNION,		"union");
39685289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
39785289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
39885289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
39985289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
40085289Sdes#undef ADD_OPTION
40185289Sdes		/* a real Linux mtab will also show NFS options */
40285289Sdes		sbuf_printf(sb, " 0 0\n");
40385289Sdes	}
40485289Sdes	mtx_unlock(&mountlist_mtx);
40585289Sdes	if (flep != NULL)
40685289Sdes		free(flep, M_TEMP);
40785289Sdes	return (error);
40885289Sdes}
40985289Sdes
41085289Sdes/*
41178113Sdes * Filler function for proc/stat
41278113Sdes */
41378025Sdesstatic int
41478025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
41565633Sdes{
416120912Sgallatin	size_t olen, plen;
417120605Sdes	int name[2];
418120339Sdes	int i, ncpu;
419120339Sdes
420120339Sdes	name[0] = CTL_HW;
421120339Sdes	name[1] = HW_NCPU;
422120339Sdes	if (kernel_sysctl(td, name, 2, &ncpu, &olen, NULL, 0, &plen) != 0)
423120340Sdes		ncpu = 1;
424120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
425120339Sdes	    T2J(cp_time[CP_USER]),
426120339Sdes	    T2J(cp_time[CP_NICE]),
427120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
428120339Sdes	    T2J(cp_time[CP_IDLE]));
429120340Sdes	if (ncpu > 1)
430120340Sdes		for (i = 0; i < ncpu; ++i)
431120340Sdes			sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
432120340Sdes			    T2J(cp_time[CP_USER]) / ncpu,
433120340Sdes			    T2J(cp_time[CP_NICE]) / ncpu,
434120340Sdes			    T2J(cp_time[CP_SYS]) / ncpu,
435120340Sdes			    T2J(cp_time[CP_IDLE]) / ncpu);
43678025Sdes	sbuf_printf(sb,
43769799Sdes	    "disk 0 0 0 0\n"
43869799Sdes	    "page %u %u\n"
43969799Sdes	    "swap %u %u\n"
44069799Sdes	    "intr %u\n"
44169799Sdes	    "ctxt %u\n"
44285657Sdillon	    "btime %lld\n",
44369799Sdes	    cnt.v_vnodepgsin,
44469799Sdes	    cnt.v_vnodepgsout,
44569799Sdes	    cnt.v_swappgsin,
44669799Sdes	    cnt.v_swappgsout,
44769799Sdes	    cnt.v_intr,
44869799Sdes	    cnt.v_swtch,
449113574Sjhb	    (long long)boottime.tv_sec);
45078025Sdes	return (0);
45165633Sdes}
45265633Sdes
45378113Sdes/*
45478113Sdes * Filler function for proc/uptime
45578113Sdes */
45678025Sdesstatic int
45778025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
45865633Sdes{
45965633Sdes	struct timeval tv;
46065633Sdes
46165633Sdes	getmicrouptime(&tv);
46285657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
463113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
46469799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
46578025Sdes	return (0);
46665633Sdes}
46765633Sdes
46878113Sdes/*
46978113Sdes * Filler function for proc/version
47078113Sdes */
47178025Sdesstatic int
47278025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
47365633Sdes{
47487275Srwatson	char osname[LINUX_MAX_UTSNAME];
47587275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
47687275Srwatson
477112206Sjhb	linux_get_osname(td, osname);
478112206Sjhb	linux_get_osrelease(td, osrelease);
47987275Srwatson
48078025Sdes	sbuf_printf(sb,
48169995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
48287275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
48378025Sdes	return (0);
48465633Sdes}
48565633Sdes
48678113Sdes/*
48778113Sdes * Filler function for proc/loadavg
48878113Sdes */
48978025Sdesstatic int
49078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
49176839Sjlemon{
49278025Sdes	sbuf_printf(sb,
49376839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
49476839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
49576839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
49676839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
49776839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
49876839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
49976839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
50076839Sjlemon	    1,				/* number of running tasks */
50176839Sjlemon	    nprocs,			/* number of tasks */
50278116Sdes	    lastpid			/* the last pid */
50376839Sjlemon	);
504119068Sdes
50578025Sdes	return (0);
50676839Sjlemon}
50776839Sjlemon
50878113Sdes/*
50978113Sdes * Filler function for proc/pid/stat
51078113Sdes */
51178025Sdesstatic int
51278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
51367588Sdes{
51469995Sdes	struct kinfo_proc kp;
51567588Sdes
51694307Sjhb	PROC_LOCK(p);
51769995Sdes	fill_kinfo_proc(p, &kp);
51878025Sdes	sbuf_printf(sb, "%d", p->p_pid);
51978025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
52067588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
52167588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
52273923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
52367588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
52467588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
52591140Stanimura	PROC_UNLOCK(p);
52667588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
52767588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
52867588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
52967588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
53067588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
53167588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
53267588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
53367588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
53467588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
53567588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
53667588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
53767588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
53867588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
53967588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
54067588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
54167588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
542113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
543113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
54467588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
54569995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
54667588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
54767588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
54869799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
54969799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
55067588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
55167588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
55267588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
55367588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
55467588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
55569799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
55669799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
55769799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
55869799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
55967588Sdes#undef PS_ADD
56078025Sdes	sbuf_putc(sb, '\n');
561119068Sdes
56278025Sdes	return (0);
56367588Sdes}
56467588Sdes
56567588Sdes/*
566119911Sdes * Filler function for proc/pid/statm
567119911Sdes */
568119911Sdesstatic int
569119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
570119911Sdes{
571119911Sdes	struct kinfo_proc kp;
572119911Sdes	segsz_t lsize;
573120340Sdes
574119911Sdes	PROC_LOCK(p);
575119911Sdes	fill_kinfo_proc(p, &kp);
576119911Sdes	PROC_UNLOCK(p);
577119911Sdes
578119911Sdes	/*
579119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
580119911Sdes	 * computation of lsize.
581119911Sdes	 */
582119911Sdes	/* size resident share trs drs lrs dt */
583119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
584119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
585119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
586119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
587119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
588119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
589119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
590119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
591119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
592119911Sdes
593119911Sdes	return (0);
594119911Sdes}
595119911Sdes
596119911Sdes/*
59778113Sdes * Filler function for proc/pid/status
59878113Sdes */
59978025Sdesstatic int
60078025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
60167588Sdes{
60269995Sdes	struct kinfo_proc kp;
60367588Sdes	char *state;
60469799Sdes	segsz_t lsize;
60599072Sjulian	struct thread *td2;
606114983Sjhb	struct sigacts *ps;
60774135Sjlemon	int i;
60867588Sdes
609113611Sjhb	PROC_LOCK(p);
61099072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
61199072Sjulian
61299072Sjulian	if (P_SHOULDSTOP(p)) {
61399072Sjulian		state = "T (stopped)";
61499072Sjulian	} else {
615113611Sjhb		mtx_lock_spin(&sched_lock);
61699072Sjulian		switch(p->p_state) {
61799072Sjulian		case PRS_NEW:
61899072Sjulian			state = "I (idle)";
61999072Sjulian			break;
62099072Sjulian		case PRS_NORMAL:
62199072Sjulian			if (p->p_flag & P_WEXIT) {
62299072Sjulian				state = "X (exiting)";
62399072Sjulian				break;
62499072Sjulian			}
62599072Sjulian			switch(td2->td_state) {
626103216Sjulian			case TDS_INHIBITED:
62799072Sjulian				state = "S (sleeping)";
62899072Sjulian				break;
62999072Sjulian			case TDS_RUNQ:
63099072Sjulian			case TDS_RUNNING:
63199072Sjulian				state = "R (running)";
63299072Sjulian				break;
63399072Sjulian			default:
63499072Sjulian				state = "? (unknown)";
63599072Sjulian				break;
63699072Sjulian			}
63799072Sjulian			break;
63899072Sjulian		case PRS_ZOMBIE:
63999072Sjulian			state = "Z (zombie)";
64099072Sjulian			break;
64199072Sjulian		default:
64299072Sjulian			state = "? (unknown)";
64399072Sjulian			break;
64499072Sjulian		}
645113611Sjhb		mtx_unlock_spin(&sched_lock);
64699072Sjulian	}
64767588Sdes
64869995Sdes	fill_kinfo_proc(p, &kp);
64978025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
65078031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
65167588Sdes
65267588Sdes	/*
65367588Sdes	 * Credentials
65467588Sdes	 */
65578025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
65678025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
65773923Sjhb						p->p_pptr->p_pid : 0);
65878031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
65978031Sdes						p->p_ucred->cr_uid,
66078031Sdes						p->p_ucred->cr_svuid,
66178031Sdes						/* FreeBSD doesn't have fsuid */
66278031Sdes						p->p_ucred->cr_uid);
66378031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
66478031Sdes						p->p_ucred->cr_gid,
66578031Sdes						p->p_ucred->cr_svgid,
66678031Sdes						/* FreeBSD doesn't have fsgid */
66778031Sdes						p->p_ucred->cr_gid);
66878025Sdes	sbuf_cat(sb, "Groups:\t");
66967588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
67078031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
67171471Sjhb	PROC_UNLOCK(p);
67278025Sdes	sbuf_putc(sb, '\n');
673119068Sdes
67467588Sdes	/*
67567588Sdes	 * Memory
67669799Sdes	 *
67769799Sdes	 * While our approximation of VmLib may not be accurate (I
67869799Sdes	 * don't know of a simple way to verify it, and I'm not sure
67969799Sdes	 * it has much meaning anyway), I believe it's good enough.
68069799Sdes	 *
68169799Sdes	 * The same code that could (I think) accurately compute VmLib
68269799Sdes	 * could also compute VmLck, but I don't really care enough to
68369799Sdes	 * implement it. Submissions are welcome.
68467588Sdes	 */
685113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
68678025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
687113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
688113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
689113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
690113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
69169995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
69269995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
693113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
69467588Sdes
69567588Sdes	/*
69667588Sdes	 * Signal masks
69767588Sdes	 *
69867588Sdes	 * We support up to 128 signals, while Linux supports 32,
69967588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
70067588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
70167588Sdes	 *
70267588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
70367588Sdes	 * supports 64 signals, but this code is a long way from
70467588Sdes	 * running on anything but i386, so ignore that for now.
70567588Sdes	 */
70671471Sjhb	PROC_LOCK(p);
707104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
70869799Sdes	/*
70969799Sdes	 * I can't seem to find out where the signal mask is in
71069799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
71169799Sdes	 */
71278025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
713114983Sjhb	ps = p->p_sigacts;
714114983Sjhb	mtx_lock(&ps->ps_mtx);
715114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
716114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
717114983Sjhb	mtx_unlock(&ps->ps_mtx);
71871471Sjhb	PROC_UNLOCK(p);
719119068Sdes
72067588Sdes	/*
72167588Sdes	 * Linux also prints the capability masks, but we don't have
72267588Sdes	 * capabilities yet, and when we do get them they're likely to
72367588Sdes	 * be meaningless to Linux programs, so we lie. XXX
72467588Sdes	 */
72578025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
72678025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
72778025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
728119068Sdes
72978025Sdes	return (0);
73067588Sdes}
73174135Sjlemon
732119911Sdes
73378113Sdes/*
734119911Sdes * Filler function for proc/pid/cwd
735119911Sdes */
736119911Sdesstatic int
737119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
738119911Sdes{
739119911Sdes	char *fullpath = "unknown";
740119911Sdes	char *freepath = NULL;
741119911Sdes
742119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
743119911Sdes	sbuf_printf(sb, "%s", fullpath);
744119911Sdes	if (freepath)
745119911Sdes		free(freepath, M_TEMP);
746119911Sdes	return (0);
747119911Sdes}
748119911Sdes
749119911Sdes/*
750119911Sdes * Filler function for proc/pid/root
751119911Sdes */
752119911Sdesstatic int
753119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
754119911Sdes{
755119911Sdes	struct vnode *rvp;
756119911Sdes	char *fullpath = "unknown";
757119911Sdes	char *freepath = NULL;
758119911Sdes
759119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
760119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
761119911Sdes	sbuf_printf(sb, "%s", fullpath);
762119911Sdes	if (freepath)
763119911Sdes		free(freepath, M_TEMP);
764119911Sdes	return (0);
765119911Sdes}
766119911Sdes
767119911Sdes/*
76878113Sdes * Filler function for proc/pid/cmdline
76978113Sdes */
77078025Sdesstatic int
77178113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
77278113Sdes{
77378113Sdes	struct ps_strings pstr;
77478113Sdes	int error, i;
77578113Sdes
77678113Sdes	/*
77778113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
77878113Sdes	 * revert back to the old way which only implements full cmdline
77978113Sdes	 * for the currept process and just p->p_comm for all other
78078113Sdes	 * processes.
78178113Sdes	 * Note that if the argv is no longer available, we deliberately
78278113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
78378113Sdes	 * Linux behaviour is to return zero-length in this case.
78478113Sdes	 */
78578113Sdes
78694620Sjhb	PROC_LOCK(p);
78796886Sjhb	if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
78894620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
78994620Sjhb		PROC_UNLOCK(p);
79094620Sjhb	} else if (p != td->td_proc) {
79194620Sjhb		PROC_UNLOCK(p);
79294620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
79394620Sjhb	} else {
79494620Sjhb		PROC_UNLOCK(p);
795103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
796103767Sjake		    sizeof(pstr));
79794620Sjhb		if (error)
79894620Sjhb			return (error);
79994620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
80094620Sjhb			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
80194620Sjhb			sbuf_printf(sb, "%c", '\0');
80278113Sdes		}
80378113Sdes	}
80478113Sdes
80578113Sdes	return (0);
80678113Sdes}
80778113Sdes
80878113Sdes/*
809116173Sobrien * Filler function for proc/pid/environ
810116173Sobrien */
811116173Sobrienstatic int
812116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
813116173Sobrien{
814116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
815116173Sobrien
816116173Sobrien	return (0);
817116173Sobrien}
818116173Sobrien
819116173Sobrien/*
820116173Sobrien * Filler function for proc/pid/maps
821116173Sobrien */
822116173Sobrienstatic int
823116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
824116173Sobrien{
825121265Scognet	char mebuffer[512];
826121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
827121246Scognet	vm_map_entry_t entry;
828121265Scognet	vm_object_t obj, tobj, lobj;
829121265Scognet	vm_ooffset_t off = 0;
830121265Scognet	char *name = "", *freename = NULL;
831121265Scognet	size_t len;
832121265Scognet	ino_t ino;
833121265Scognet	int ref_count, shadow_count, flags;
834121265Scognet	int error;
835121246Scognet
836121246Scognet	PROC_LOCK(p);
837121246Scognet	error = p_candebug(td, p);
838121246Scognet	PROC_UNLOCK(p);
839121246Scognet	if (error)
840121246Scognet		return (error);
841121246Scognet
842121246Scognet	if (uio->uio_rw != UIO_READ)
843121246Scognet		return (EOPNOTSUPP);
844121246Scognet
845121246Scognet	if (uio->uio_offset != 0)
846121246Scognet		return (0);
847121246Scognet
848121246Scognet	error = 0;
849121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
850121246Scognet		vm_map_lock_read(map);
851121246Scognet        for (entry = map->header.next;
852121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
853121246Scognet	    entry = entry->next) {
854121265Scognet		name = "";
855121265Scognet		freename = NULL;
856121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
857121246Scognet			continue;
858121246Scognet		obj = entry->object.vm_object;
859121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
860121246Scognet			lobj = tobj;
861121246Scognet		ino = 0;
862121246Scognet		if (lobj) {
863121246Scognet			VM_OBJECT_LOCK(lobj);
864121246Scognet			off = IDX_TO_OFF(lobj->size);
865121246Scognet			if (lobj->type == OBJT_VNODE && lobj->handle) {
866121246Scognet				vn_fullpath(td, (struct vnode *)lobj->handle,
867121246Scognet				    &name, &freename);
868121246Scognet				ino = ((struct vnode *)
869121246Scognet				    lobj->handle)->v_cachedid;
870121246Scognet			}
871121246Scognet			flags = obj->flags;
872121246Scognet			ref_count = obj->ref_count;
873121246Scognet			shadow_count = obj->shadow_count;
874121246Scognet			VM_OBJECT_UNLOCK(lobj);
875121246Scognet		} else {
876121246Scognet			flags = 0;
877121246Scognet			ref_count = 0;
878121246Scognet			shadow_count = 0;
879121246Scognet		}
880121246Scognet
881121246Scognet		/*
882121246Scognet	     	 * format:
883121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
884121246Scognet		 */
885121246Scognet		snprintf(mebuffer, sizeof mebuffer,
886121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
887121246Scognet		    (u_long)entry->start, (u_long)entry->end,
888121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
889121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
890121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
891121246Scognet		    "p",
892121265Scognet		    (u_long)off,
893121246Scognet		    0,
894121246Scognet		    0,
895121265Scognet		    (u_long)ino,
896121246Scognet		    *name ? "     " : "",
897121246Scognet		    name
898121246Scognet		    );
899121246Scognet		if (freename)
900121246Scognet			free(freename, M_TEMP);
901121246Scognet		len = strlen(mebuffer);
902121246Scognet		if (len > uio->uio_resid)
903121246Scognet			len = uio->uio_resid; /*
904121246Scognet					       * XXX We should probably return
905121246Scognet					       * EFBIG here, as in procfs.
906121246Scognet					       */
907121246Scognet		error = uiomove(mebuffer, len, uio);
908121246Scognet		if (error)
909121246Scognet			break;
910121246Scognet	}
911121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
912121246Scognet		vm_map_unlock_read(map);
913121246Scognet
914121246Scognet	return (error);
915121246Scognet}
916121246Scognet
917116173Sobrien/*
91878113Sdes * Filler function for proc/net/dev
91978113Sdes */
92078025Sdesstatic int
92178025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
92274135Sjlemon{
92385129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
92474135Sjlemon	struct ifnet *ifp;
92574135Sjlemon
92685129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
92783926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
92885129Sdes	    "bytes    packets errs drop fifo frame compressed",
92983926Sdes	    "bytes    packets errs drop fifo frame compressed");
93074135Sjlemon
931108172Shsu	IFNET_RLOCK();
93274135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
93385129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
93485129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
93583926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
93683926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
93783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
93883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
93974135Sjlemon	}
940108172Shsu	IFNET_RUNLOCK();
941119068Sdes
94278025Sdes	return (0);
94374135Sjlemon}
94474135Sjlemon
94585538Sphk#if 0
94685538Sphkextern struct cdevsw *cdevsw[];
94785538Sphk
94878113Sdes/*
94978113Sdes * Filler function for proc/devices
95078113Sdes */
95178025Sdesstatic int
95278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
95374135Sjlemon{
95474135Sjlemon	int i;
95574135Sjlemon
95678025Sdes	sbuf_printf(sb, "Character devices:\n");
95774135Sjlemon
95878025Sdes	for (i = 0; i < NUMCDEVSW; i++)
95974135Sjlemon		if (cdevsw[i] != NULL)
96078025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
96174135Sjlemon
96278025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
963119068Sdes
96478025Sdes	return (0);
96574135Sjlemon}
96685538Sphk#endif
96774135Sjlemon
96878113Sdes/*
96978113Sdes * Filler function for proc/cmdline
97078113Sdes */
97178025Sdesstatic int
97278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
97374135Sjlemon{
97478025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
97578025Sdes	sbuf_printf(sb, " ro root=302\n");
97678025Sdes	return (0);
97778025Sdes}
97874135Sjlemon
97983926Sdes#if 0
98078025Sdes/*
98183926Sdes * Filler function for proc/modules
98283926Sdes */
98383926Sdesstatic int
98483926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
98583926Sdes{
98683926Sdes	struct linker_file *lf;
987119068Sdes
98883926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
98983926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
99083926Sdes		    (unsigned long)lf->size, lf->refs);
99183926Sdes	}
99283926Sdes	return (0);
99383926Sdes}
99483926Sdes#endif
99583926Sdes
99683926Sdes/*
99785129Sdes * Constructor
99878025Sdes */
99985129Sdesstatic int
100085129Sdeslinprocfs_init(PFS_INIT_ARGS)
100185129Sdes{
100285129Sdes	struct pfs_node *root;
100385129Sdes	struct pfs_node *dir;
100474135Sjlemon
100585129Sdes	root = pi->pi_root;
100678025Sdes
1007119923Sdes	/* /proc/... */
1008119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1009119911Sdes	    NULL, NULL, PFS_RD);
1010119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1011119911Sdes	    NULL, NULL, PFS_RD);
101285538Sphk#if 0
1013119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1014119911Sdes	    NULL, NULL, PFS_RD);
101585538Sphk#endif
1016119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1017119911Sdes	    NULL, NULL, PFS_RD);
1018119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1019119911Sdes	    NULL, NULL, PFS_RD);
102083926Sdes#if 0
1021119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1022119911Sdes	    NULL, NULL, PFS_RD);
102383926Sdes#endif
1024119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1025119911Sdes	    NULL, NULL, PFS_RD);
102687543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
102785129Sdes	    NULL, NULL, 0);
1028119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1029119911Sdes	    NULL, NULL, PFS_RD);
1030119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1031119911Sdes	    NULL, NULL, PFS_RD);
1032119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1033119911Sdes	    NULL, NULL, PFS_RD);
103478025Sdes
1035119923Sdes	/* /proc/net/... */
103685129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
103785129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
103885129Sdes	    NULL, NULL, PFS_RD);
103978025Sdes
1040119923Sdes	/* /proc/<pid>/... */
104185129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
104285129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
104385129Sdes	    NULL, NULL, PFS_RD);
1044119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1045119911Sdes	    NULL, NULL, 0);
1046116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1047116173Sobrien	    NULL, NULL, PFS_RD);
104887543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
104987543Sdes	    NULL, &procfs_notsystem, 0);
1050116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1051116173Sobrien	    NULL, NULL, PFS_RD);
105285129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
105385129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1054119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1055119911Sdes	    NULL, NULL, 0);
105685129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
105785129Sdes	    NULL, NULL, PFS_RD);
1058119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1059119911Sdes	    NULL, NULL, PFS_RD);
106085129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
106185129Sdes	    NULL, NULL, PFS_RD);
106285129Sdes
106385129Sdes	return (0);
106485129Sdes}
106585129Sdes
106685129Sdes/*
106785129Sdes * Destructor
106885129Sdes */
106985129Sdesstatic int
107085129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
107185129Sdes{
107285129Sdes
107385129Sdes	/* nothing to do, pseudofs will GC */
107485129Sdes	return (0);
107585129Sdes}
107685129Sdes
107785129SdesPSEUDOFS(linprocfs, 1);
107878025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
107978025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1080