linprocfs.c revision 127694
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 127694 2004-04-01 00:04:23Z pjd $");
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
8978113Sdes#ifdef __i386__
9067589Sdes#include <machine/cputypes.h>
9159412Smsmith#include <machine/md_var.h>
9278113Sdes#endif /* __i386__ */
9359412Smsmith
9487275Srwatson#include <machine/../linux/linux.h>
9585129Sdes#include <compat/linux/linux_ioctl.h>
9669995Sdes#include <compat/linux/linux_mib.h>
9785289Sdes#include <compat/linux/linux_util.h>
9878025Sdes#include <fs/pseudofs/pseudofs.h>
9984248Sdes#include <fs/procfs/procfs.h>
10059412Smsmith
10167588Sdes/*
10267588Sdes * Various conversion macros
10367588Sdes */
10476405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10567588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10667588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10769799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10867588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10967588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11074135Sjlemon
11178113Sdes/*
11278113Sdes * Filler function for proc/meminfo
11378113Sdes */
11478025Sdesstatic int
11578025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
11659412Smsmith{
11759412Smsmith	unsigned long memtotal;		/* total memory in bytes */
11859412Smsmith	unsigned long memused;		/* used memory in bytes */
11959412Smsmith	unsigned long memfree;		/* free memory in bytes */
12059412Smsmith	unsigned long memshared;	/* shared memory ??? */
12159412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
122113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
123113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
124113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
12560860Sdes	vm_object_t object;
126117723Sphk	int i, j;
12759412Smsmith
12859412Smsmith	memtotal = physmem * PAGE_SIZE;
12959412Smsmith	/*
13059412Smsmith	 * The correct thing here would be:
13159412Smsmith	 *
13259412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13359412Smsmith	memused = memtotal - memfree;
13459412Smsmith	 *
13559412Smsmith	 * but it might mislead linux binaries into thinking there
13659412Smsmith	 * is very little memory left, so we cheat and tell them that
13759412Smsmith	 * all memory that isn't wired down is free.
13859412Smsmith	 */
13959412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
14059412Smsmith	memfree = memtotal - memused;
141117723Sphk	swap_pager_status(&i, &j);
142117723Sphk	swaptotal = i * PAGE_SIZE;
143117723Sphk	swapused = j * PAGE_SIZE;
144117723Sphk	swapfree = swaptotal - swapused;
14560860Sdes	memshared = 0;
146124082Salc	mtx_lock(&vm_object_list_mtx);
14771471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14860860Sdes		if (object->shadow_count > 1)
14960860Sdes			memshared += object->resident_page_count;
150124082Salc	mtx_unlock(&vm_object_list_mtx);
15160860Sdes	memshared *= PAGE_SIZE;
15259412Smsmith	/*
15359412Smsmith	 * We'd love to be able to write:
15459412Smsmith	 *
15559412Smsmith	buffers = bufspace;
15659412Smsmith	 *
15759412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
15859412Smsmith	 * like unstaticizing it just for linprocfs's sake.
15959412Smsmith	 */
16059412Smsmith	buffers = 0;
16159412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
16259412Smsmith
16378025Sdes	sbuf_printf(sb,
16478031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
16569799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
16676839Sjlemon	    "Swap: %llu %llu %llu\n"
16769799Sdes	    "MemTotal: %9lu kB\n"
16869799Sdes	    "MemFree:  %9lu kB\n"
16969799Sdes	    "MemShared:%9lu kB\n"
17069799Sdes	    "Buffers:  %9lu kB\n"
17169799Sdes	    "Cached:   %9lu kB\n"
17276839Sjlemon	    "SwapTotal:%9llu kB\n"
17376839Sjlemon	    "SwapFree: %9llu kB\n",
17469799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
17569799Sdes	    swaptotal, swapused, swapfree,
17669799Sdes	    B2K(memtotal), B2K(memfree),
17769799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
17869799Sdes	    B2K(swaptotal), B2K(swapfree));
17959412Smsmith
18078025Sdes	return (0);
18159412Smsmith}
18259412Smsmith
18378113Sdes#ifdef __alpha__
184119008Smarcelextern struct rpb *hwrpb;
18578113Sdes/*
18678113Sdes * Filler function for proc/cpuinfo (Alpha version)
18778113Sdes */
18878025Sdesstatic int
18978025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
19059412Smsmith{
19178113Sdes	u_int64_t type, major;
19278113Sdes	struct pcs *pcsp;
19378113Sdes	const char *model, *sysname;
19478113Sdes
19578113Sdes	static const char *cpuname[] = {
19678113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
19778113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
19878113Sdes	};
19978113Sdes
20078113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
20178113Sdes	type = pcsp->pcs_proc_type;
20278113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20378113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20478113Sdes		model = cpuname[major - 1];
20578113Sdes	} else {
20678113Sdes		model = "unknown";
20778113Sdes	}
208119068Sdes
20978113Sdes	sysname = alpha_dsr_sysname();
210119068Sdes
21178113Sdes	sbuf_printf(sb,
21278113Sdes	    "cpu\t\t\t: Alpha\n"
21378113Sdes	    "cpu model\t\t: %s\n"
21478113Sdes	    "cpu variation\t\t: %ld\n"
215113574Sjhb	    "cpu revision\t\t: %d\n"
21678113Sdes	    "cpu serial number\t: %s\n"
21778113Sdes	    "system type\t\t: %s\n"
21878113Sdes	    "system variation\t: %s\n"
219113574Sjhb	    "system revision\t\t: %d\n"
22078113Sdes	    "system serial number\t: %s\n"
22178113Sdes	    "cycle frequency [Hz]\t: %lu\n"
222113574Sjhb	    "timer frequency [Hz]\t: %u\n"
22378113Sdes	    "page size [bytes]\t: %ld\n"
22478113Sdes	    "phys. address bits\t: %ld\n"
22578113Sdes	    "max. addr. space #\t: %ld\n"
226113574Sjhb	    "BogoMIPS\t\t: %u.%02u\n"
227113574Sjhb	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
228113574Sjhb	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
22978113Sdes	    "platform string\t\t: %s\n"
23078113Sdes	    "cpus detected\t\t: %d\n"
23178113Sdes	    ,
23278113Sdes	    model,
23378113Sdes	    pcsp->pcs_proc_var,
23478113Sdes	    *(int *)hwrpb->rpb_revision,
23578113Sdes	    " ",
23678113Sdes	    " ",
23778113Sdes	    "0",
23878113Sdes	    0,
23978113Sdes	    " ",
24078113Sdes	    hwrpb->rpb_cc_freq,
24178113Sdes	    hz,
24278113Sdes	    hwrpb->rpb_page_size,
24378113Sdes	    hwrpb->rpb_phys_addr_size,
24478113Sdes	    hwrpb->rpb_max_asn,
24578113Sdes	    0, 0,
24678113Sdes	    0, 0, 0,
24778113Sdes	    0, 0, 0,
24878113Sdes	    sysname,
24978113Sdes	    ncpus);
25078113Sdes	return (0);
25178113Sdes}
25278113Sdes#endif /* __alpha__ */
25378113Sdes
25478113Sdes#ifdef __i386__
25578113Sdes/*
25678113Sdes * Filler function for proc/cpuinfo (i386 version)
25778113Sdes */
25878113Sdesstatic int
25978113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
26078113Sdes{
261123246Sdes	int class, fqmhz, fqkhz;
262118421Sdes	int i;
26359412Smsmith
26469799Sdes	/*
26578031Sdes	 * We default the flags to include all non-conflicting flags,
26678031Sdes	 * and the Intel versions of conflicting flags.
26769799Sdes	 */
26878031Sdes	static char *flags[] = {
26978031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
27078031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
27178031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
27278031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
27378031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27478031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
27567589Sdes		"3dnowext", "3dnow"
27667589Sdes	};
27767589Sdes
27859412Smsmith	switch (cpu_class) {
27959412Smsmith	case CPUCLASS_286:
28067589Sdes		class = 2;
28159412Smsmith		break;
28259412Smsmith	case CPUCLASS_386:
28367589Sdes		class = 3;
28459412Smsmith		break;
28559412Smsmith	case CPUCLASS_486:
28667589Sdes		class = 4;
28759412Smsmith		break;
28859412Smsmith	case CPUCLASS_586:
28967589Sdes		class = 5;
29059412Smsmith		break;
29159412Smsmith	case CPUCLASS_686:
29267589Sdes		class = 6;
29359412Smsmith		break;
29459412Smsmith	default:
29578031Sdes		class = 0;
29659412Smsmith		break;
29759412Smsmith	}
29859412Smsmith
299123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
300118421Sdes		sbuf_printf(sb,
301118421Sdes		    "processor\t: %d\n"
302118421Sdes		    "vendor_id\t: %.20s\n"
303118421Sdes		    "cpu family\t: %d\n"
304118421Sdes		    "model\t\t: %d\n"
305118421Sdes		    "stepping\t: %d\n",
306118421Sdes		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
307118421Sdes		/* XXX per-cpu vendor / class / id? */
308118421Sdes	}
30959412Smsmith
31078031Sdes	sbuf_cat(sb,
31178031Sdes	    "flags\t\t:");
31267589Sdes
31378031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
31467589Sdes		flags[16] = "fcmov";
31578031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
31667589Sdes		flags[24] = "cxmmx";
31778031Sdes	}
318119068Sdes
31978031Sdes	for (i = 0; i < 32; i++)
32067589Sdes		if (cpu_feature & (1 << i))
32178025Sdes			sbuf_printf(sb, " %s", flags[i]);
32278025Sdes	sbuf_cat(sb, "\n");
32378031Sdes	if (class >= 5) {
32469799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
32569799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
32678025Sdes		sbuf_printf(sb,
32769799Sdes		    "cpu MHz\t\t: %d.%02d\n"
32869799Sdes		    "bogomips\t: %d.%02d\n",
32969799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
33078031Sdes	}
33169995Sdes
33278025Sdes	return (0);
33359412Smsmith}
33478113Sdes#endif /* __i386__ */
33565633Sdes
33678113Sdes/*
33785289Sdes * Filler function for proc/mtab
33885289Sdes *
33985289Sdes * This file doesn't exist in Linux' procfs, but is included here so
34085289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
34185289Sdes */
34285289Sdesstatic int
34385289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
34485289Sdes{
34585289Sdes	struct nameidata nd;
34685289Sdes	struct mount *mp;
34791334Sjulian	const char *lep;
34891334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
34985289Sdes	size_t lep_len;
35085289Sdes	int error;
35185289Sdes
35285289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
35385289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
35485289Sdes	flep = NULL;
355124407Srwatson	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
35685289Sdes		lep = linux_emul_path;
35791334Sjulian	else
35891334Sjulian		lep = dlep;
35985289Sdes	lep_len = strlen(lep);
360119068Sdes
36185289Sdes	mtx_lock(&mountlist_mtx);
36285289Sdes	error = 0;
36385289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
36485289Sdes		/* determine device name */
36585289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
366119068Sdes
36785289Sdes		/* determine mount point */
36885289Sdes		mntto = mp->mnt_stat.f_mntonname;
36985289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
37085289Sdes		    mntto[lep_len] == '/')
37185289Sdes			mntto += lep_len;
37285289Sdes
37385289Sdes		/* determine fs type */
37485289Sdes		fstype = mp->mnt_stat.f_fstypename;
37585289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
37685289Sdes			mntfrom = fstype = "proc";
37785289Sdes		else if (strcmp(fstype, "procfs") == 0)
37885289Sdes			continue;
379119068Sdes
38085289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
38185289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
38285289Sdes#define ADD_OPTION(opt, name) \
38385289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
38485289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
38585289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
38685289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
38785289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
38885289Sdes		ADD_OPTION(MNT_UNION,		"union");
38985289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
39085289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
39185289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
39285289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
39385289Sdes#undef ADD_OPTION
39485289Sdes		/* a real Linux mtab will also show NFS options */
39585289Sdes		sbuf_printf(sb, " 0 0\n");
39685289Sdes	}
39785289Sdes	mtx_unlock(&mountlist_mtx);
39885289Sdes	if (flep != NULL)
39985289Sdes		free(flep, M_TEMP);
40085289Sdes	return (error);
40185289Sdes}
40285289Sdes
40385289Sdes/*
40478113Sdes * Filler function for proc/stat
40578113Sdes */
40678025Sdesstatic int
40778025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
40865633Sdes{
409123246Sdes	int i;
410120339Sdes
411120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
412120339Sdes	    T2J(cp_time[CP_USER]),
413120339Sdes	    T2J(cp_time[CP_NICE]),
414120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
415120339Sdes	    T2J(cp_time[CP_IDLE]));
416123246Sdes	if (mp_ncpus > 1)
417123246Sdes		for (i = 0; i < mp_ncpus; ++i)
418120340Sdes			sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
419123246Sdes			    T2J(cp_time[CP_USER]) / mp_ncpus,
420123246Sdes			    T2J(cp_time[CP_NICE]) / mp_ncpus,
421123246Sdes			    T2J(cp_time[CP_SYS]) / mp_ncpus,
422123246Sdes			    T2J(cp_time[CP_IDLE]) / mp_ncpus);
42378025Sdes	sbuf_printf(sb,
42469799Sdes	    "disk 0 0 0 0\n"
42569799Sdes	    "page %u %u\n"
42669799Sdes	    "swap %u %u\n"
42769799Sdes	    "intr %u\n"
42869799Sdes	    "ctxt %u\n"
42985657Sdillon	    "btime %lld\n",
43069799Sdes	    cnt.v_vnodepgsin,
43169799Sdes	    cnt.v_vnodepgsout,
43269799Sdes	    cnt.v_swappgsin,
43369799Sdes	    cnt.v_swappgsout,
43469799Sdes	    cnt.v_intr,
43569799Sdes	    cnt.v_swtch,
436113574Sjhb	    (long long)boottime.tv_sec);
43778025Sdes	return (0);
43865633Sdes}
43965633Sdes
44078113Sdes/*
44178113Sdes * Filler function for proc/uptime
44278113Sdes */
44378025Sdesstatic int
44478025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
44565633Sdes{
44665633Sdes	struct timeval tv;
44765633Sdes
44865633Sdes	getmicrouptime(&tv);
44985657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
450113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
45169799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
45278025Sdes	return (0);
45365633Sdes}
45465633Sdes
45578113Sdes/*
45678113Sdes * Filler function for proc/version
45778113Sdes */
45878025Sdesstatic int
45978025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
46065633Sdes{
46187275Srwatson	char osname[LINUX_MAX_UTSNAME];
46287275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
46387275Srwatson
464112206Sjhb	linux_get_osname(td, osname);
465112206Sjhb	linux_get_osrelease(td, osrelease);
46687275Srwatson
46778025Sdes	sbuf_printf(sb,
46869995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
46987275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
47078025Sdes	return (0);
47165633Sdes}
47265633Sdes
47378113Sdes/*
47478113Sdes * Filler function for proc/loadavg
47578113Sdes */
47678025Sdesstatic int
47778025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
47876839Sjlemon{
47978025Sdes	sbuf_printf(sb,
48076839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
48176839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
48276839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
48376839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
48476839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
48576839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
48676839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
48776839Sjlemon	    1,				/* number of running tasks */
48876839Sjlemon	    nprocs,			/* number of tasks */
48978116Sdes	    lastpid			/* the last pid */
49076839Sjlemon	);
491119068Sdes
49278025Sdes	return (0);
49376839Sjlemon}
49476839Sjlemon
49578113Sdes/*
49678113Sdes * Filler function for proc/pid/stat
49778113Sdes */
49878025Sdesstatic int
49978025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
50067588Sdes{
50169995Sdes	struct kinfo_proc kp;
50267588Sdes
50394307Sjhb	PROC_LOCK(p);
50469995Sdes	fill_kinfo_proc(p, &kp);
50578025Sdes	sbuf_printf(sb, "%d", p->p_pid);
50678025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
50767588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
50867588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
50973923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
51067588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
51167588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
51291140Stanimura	PROC_UNLOCK(p);
51367588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
51467588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
51567588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
51667588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
51767588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
51867588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
51967588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
52067588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
52167588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
52267588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
52367588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
52467588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
52567588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
52667588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
52767588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
52867588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
529113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
530113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
53167588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
53269995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
53367588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
53467588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
53569799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
53669799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
53767588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
53867588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
53967588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
54067588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
54167588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
54269799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
54369799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
54469799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
54569799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
54667588Sdes#undef PS_ADD
54778025Sdes	sbuf_putc(sb, '\n');
548119068Sdes
54978025Sdes	return (0);
55067588Sdes}
55167588Sdes
55267588Sdes/*
553119911Sdes * Filler function for proc/pid/statm
554119911Sdes */
555119911Sdesstatic int
556119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
557119911Sdes{
558119911Sdes	struct kinfo_proc kp;
559119911Sdes	segsz_t lsize;
560120340Sdes
561119911Sdes	PROC_LOCK(p);
562119911Sdes	fill_kinfo_proc(p, &kp);
563119911Sdes	PROC_UNLOCK(p);
564119911Sdes
565119911Sdes	/*
566119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
567119911Sdes	 * computation of lsize.
568119911Sdes	 */
569119911Sdes	/* size resident share trs drs lrs dt */
570119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
571119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
572119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
573119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
574119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
575119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
576119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
577119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
578119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
579119911Sdes
580119911Sdes	return (0);
581119911Sdes}
582119911Sdes
583119911Sdes/*
58478113Sdes * Filler function for proc/pid/status
58578113Sdes */
58678025Sdesstatic int
58778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
58867588Sdes{
58969995Sdes	struct kinfo_proc kp;
59067588Sdes	char *state;
59169799Sdes	segsz_t lsize;
59299072Sjulian	struct thread *td2;
593114983Sjhb	struct sigacts *ps;
59474135Sjlemon	int i;
59567588Sdes
596113611Sjhb	PROC_LOCK(p);
59799072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
59899072Sjulian
59999072Sjulian	if (P_SHOULDSTOP(p)) {
60099072Sjulian		state = "T (stopped)";
60199072Sjulian	} else {
602113611Sjhb		mtx_lock_spin(&sched_lock);
60399072Sjulian		switch(p->p_state) {
60499072Sjulian		case PRS_NEW:
60599072Sjulian			state = "I (idle)";
60699072Sjulian			break;
60799072Sjulian		case PRS_NORMAL:
60899072Sjulian			if (p->p_flag & P_WEXIT) {
60999072Sjulian				state = "X (exiting)";
61099072Sjulian				break;
61199072Sjulian			}
61299072Sjulian			switch(td2->td_state) {
613103216Sjulian			case TDS_INHIBITED:
61499072Sjulian				state = "S (sleeping)";
61599072Sjulian				break;
61699072Sjulian			case TDS_RUNQ:
61799072Sjulian			case TDS_RUNNING:
61899072Sjulian				state = "R (running)";
61999072Sjulian				break;
62099072Sjulian			default:
62199072Sjulian				state = "? (unknown)";
62299072Sjulian				break;
62399072Sjulian			}
62499072Sjulian			break;
62599072Sjulian		case PRS_ZOMBIE:
62699072Sjulian			state = "Z (zombie)";
62799072Sjulian			break;
62899072Sjulian		default:
62999072Sjulian			state = "? (unknown)";
63099072Sjulian			break;
63199072Sjulian		}
632113611Sjhb		mtx_unlock_spin(&sched_lock);
63399072Sjulian	}
63467588Sdes
63569995Sdes	fill_kinfo_proc(p, &kp);
63678025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
63778031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
63867588Sdes
63967588Sdes	/*
64067588Sdes	 * Credentials
64167588Sdes	 */
64278025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
64378025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
64473923Sjhb						p->p_pptr->p_pid : 0);
64578031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
64678031Sdes						p->p_ucred->cr_uid,
64778031Sdes						p->p_ucred->cr_svuid,
64878031Sdes						/* FreeBSD doesn't have fsuid */
64978031Sdes						p->p_ucred->cr_uid);
65078031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
65178031Sdes						p->p_ucred->cr_gid,
65278031Sdes						p->p_ucred->cr_svgid,
65378031Sdes						/* FreeBSD doesn't have fsgid */
65478031Sdes						p->p_ucred->cr_gid);
65578025Sdes	sbuf_cat(sb, "Groups:\t");
65667588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
65778031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
65871471Sjhb	PROC_UNLOCK(p);
65978025Sdes	sbuf_putc(sb, '\n');
660119068Sdes
66167588Sdes	/*
66267588Sdes	 * Memory
66369799Sdes	 *
66469799Sdes	 * While our approximation of VmLib may not be accurate (I
66569799Sdes	 * don't know of a simple way to verify it, and I'm not sure
66669799Sdes	 * it has much meaning anyway), I believe it's good enough.
66769799Sdes	 *
66869799Sdes	 * The same code that could (I think) accurately compute VmLib
66969799Sdes	 * could also compute VmLck, but I don't really care enough to
67069799Sdes	 * implement it. Submissions are welcome.
67167588Sdes	 */
672113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
67378025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
674113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
675113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
676113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
677113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
67869995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
67969995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
680113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
68167588Sdes
68267588Sdes	/*
68367588Sdes	 * Signal masks
68467588Sdes	 *
68567588Sdes	 * We support up to 128 signals, while Linux supports 32,
68667588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
68767588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
68867588Sdes	 *
68967588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
69067588Sdes	 * supports 64 signals, but this code is a long way from
69167588Sdes	 * running on anything but i386, so ignore that for now.
69267588Sdes	 */
69371471Sjhb	PROC_LOCK(p);
694104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
69569799Sdes	/*
69669799Sdes	 * I can't seem to find out where the signal mask is in
69769799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
69869799Sdes	 */
69978025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
700114983Sjhb	ps = p->p_sigacts;
701114983Sjhb	mtx_lock(&ps->ps_mtx);
702114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
703114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
704114983Sjhb	mtx_unlock(&ps->ps_mtx);
70571471Sjhb	PROC_UNLOCK(p);
706119068Sdes
70767588Sdes	/*
70867588Sdes	 * Linux also prints the capability masks, but we don't have
70967588Sdes	 * capabilities yet, and when we do get them they're likely to
71067588Sdes	 * be meaningless to Linux programs, so we lie. XXX
71167588Sdes	 */
71278025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
71378025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
71478025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
715119068Sdes
71678025Sdes	return (0);
71767588Sdes}
71874135Sjlemon
719119911Sdes
72078113Sdes/*
721119911Sdes * Filler function for proc/pid/cwd
722119911Sdes */
723119911Sdesstatic int
724119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
725119911Sdes{
726119911Sdes	char *fullpath = "unknown";
727119911Sdes	char *freepath = NULL;
728119911Sdes
729119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
730119911Sdes	sbuf_printf(sb, "%s", fullpath);
731119911Sdes	if (freepath)
732119911Sdes		free(freepath, M_TEMP);
733119911Sdes	return (0);
734119911Sdes}
735119911Sdes
736119911Sdes/*
737119911Sdes * Filler function for proc/pid/root
738119911Sdes */
739119911Sdesstatic int
740119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
741119911Sdes{
742119911Sdes	struct vnode *rvp;
743119911Sdes	char *fullpath = "unknown";
744119911Sdes	char *freepath = NULL;
745119911Sdes
746119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
747119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
748119911Sdes	sbuf_printf(sb, "%s", fullpath);
749119911Sdes	if (freepath)
750119911Sdes		free(freepath, M_TEMP);
751119911Sdes	return (0);
752119911Sdes}
753119911Sdes
754119911Sdes/*
75578113Sdes * Filler function for proc/pid/cmdline
75678113Sdes */
75778025Sdesstatic int
75878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
75978113Sdes{
76078113Sdes	struct ps_strings pstr;
76178113Sdes	int error, i;
76278113Sdes
76378113Sdes	/*
76478113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
76578113Sdes	 * revert back to the old way which only implements full cmdline
76678113Sdes	 * for the currept process and just p->p_comm for all other
76778113Sdes	 * processes.
76878113Sdes	 * Note that if the argv is no longer available, we deliberately
76978113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
77078113Sdes	 * Linux behaviour is to return zero-length in this case.
77178113Sdes	 */
77278113Sdes
77394620Sjhb	PROC_LOCK(p);
774127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
77594620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
77694620Sjhb		PROC_UNLOCK(p);
77794620Sjhb	} else if (p != td->td_proc) {
77894620Sjhb		PROC_UNLOCK(p);
77994620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
78094620Sjhb	} else {
78194620Sjhb		PROC_UNLOCK(p);
782103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
783103767Sjake		    sizeof(pstr));
78494620Sjhb		if (error)
78594620Sjhb			return (error);
78694620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
78794620Sjhb			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
78894620Sjhb			sbuf_printf(sb, "%c", '\0');
78978113Sdes		}
79078113Sdes	}
79178113Sdes
79278113Sdes	return (0);
79378113Sdes}
79478113Sdes
79578113Sdes/*
796116173Sobrien * Filler function for proc/pid/environ
797116173Sobrien */
798116173Sobrienstatic int
799116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
800116173Sobrien{
801116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
802116173Sobrien
803116173Sobrien	return (0);
804116173Sobrien}
805116173Sobrien
806116173Sobrien/*
807116173Sobrien * Filler function for proc/pid/maps
808116173Sobrien */
809116173Sobrienstatic int
810116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
811116173Sobrien{
812121265Scognet	char mebuffer[512];
813121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
814121246Scognet	vm_map_entry_t entry;
815121265Scognet	vm_object_t obj, tobj, lobj;
816121265Scognet	vm_ooffset_t off = 0;
817121265Scognet	char *name = "", *freename = NULL;
818121265Scognet	size_t len;
819121265Scognet	ino_t ino;
820121265Scognet	int ref_count, shadow_count, flags;
821121265Scognet	int error;
822121246Scognet
823121246Scognet	PROC_LOCK(p);
824121246Scognet	error = p_candebug(td, p);
825121246Scognet	PROC_UNLOCK(p);
826121246Scognet	if (error)
827121246Scognet		return (error);
828121246Scognet
829121246Scognet	if (uio->uio_rw != UIO_READ)
830121246Scognet		return (EOPNOTSUPP);
831121246Scognet
832121246Scognet	if (uio->uio_offset != 0)
833121246Scognet		return (0);
834121246Scognet
835121246Scognet	error = 0;
836121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
837121246Scognet		vm_map_lock_read(map);
838121246Scognet        for (entry = map->header.next;
839121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
840121246Scognet	    entry = entry->next) {
841121265Scognet		name = "";
842121265Scognet		freename = NULL;
843121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
844121246Scognet			continue;
845121246Scognet		obj = entry->object.vm_object;
846121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
847121246Scognet			lobj = tobj;
848121246Scognet		ino = 0;
849121246Scognet		if (lobj) {
850121246Scognet			VM_OBJECT_LOCK(lobj);
851121246Scognet			off = IDX_TO_OFF(lobj->size);
852121246Scognet			if (lobj->type == OBJT_VNODE && lobj->handle) {
853121246Scognet				vn_fullpath(td, (struct vnode *)lobj->handle,
854121246Scognet				    &name, &freename);
855121246Scognet				ino = ((struct vnode *)
856121246Scognet				    lobj->handle)->v_cachedid;
857121246Scognet			}
858121246Scognet			flags = obj->flags;
859121246Scognet			ref_count = obj->ref_count;
860121246Scognet			shadow_count = obj->shadow_count;
861121246Scognet			VM_OBJECT_UNLOCK(lobj);
862121246Scognet		} else {
863121246Scognet			flags = 0;
864121246Scognet			ref_count = 0;
865121246Scognet			shadow_count = 0;
866121246Scognet		}
867121246Scognet
868121246Scognet		/*
869121246Scognet	     	 * format:
870121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
871121246Scognet		 */
872121246Scognet		snprintf(mebuffer, sizeof mebuffer,
873121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
874121246Scognet		    (u_long)entry->start, (u_long)entry->end,
875121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
876121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
877121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
878121246Scognet		    "p",
879121265Scognet		    (u_long)off,
880121246Scognet		    0,
881121246Scognet		    0,
882121265Scognet		    (u_long)ino,
883121246Scognet		    *name ? "     " : "",
884121246Scognet		    name
885121246Scognet		    );
886121246Scognet		if (freename)
887121246Scognet			free(freename, M_TEMP);
888121246Scognet		len = strlen(mebuffer);
889121246Scognet		if (len > uio->uio_resid)
890121246Scognet			len = uio->uio_resid; /*
891121246Scognet					       * XXX We should probably return
892121246Scognet					       * EFBIG here, as in procfs.
893121246Scognet					       */
894121246Scognet		error = uiomove(mebuffer, len, uio);
895121246Scognet		if (error)
896121246Scognet			break;
897121246Scognet	}
898121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
899121246Scognet		vm_map_unlock_read(map);
900121246Scognet
901121246Scognet	return (error);
902121246Scognet}
903121246Scognet
904116173Sobrien/*
90578113Sdes * Filler function for proc/net/dev
90678113Sdes */
90778025Sdesstatic int
90878025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
90974135Sjlemon{
91085129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
91174135Sjlemon	struct ifnet *ifp;
91274135Sjlemon
91385129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
91483926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
91585129Sdes	    "bytes    packets errs drop fifo frame compressed",
91683926Sdes	    "bytes    packets errs drop fifo frame compressed");
91774135Sjlemon
918108172Shsu	IFNET_RLOCK();
91974135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
92085129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
92185129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
92283926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
92383926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
92483926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
92583926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
92674135Sjlemon	}
927108172Shsu	IFNET_RUNLOCK();
928119068Sdes
92978025Sdes	return (0);
93074135Sjlemon}
93174135Sjlemon
93285538Sphk#if 0
93385538Sphkextern struct cdevsw *cdevsw[];
93485538Sphk
93578113Sdes/*
93678113Sdes * Filler function for proc/devices
93778113Sdes */
93878025Sdesstatic int
93978025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
94074135Sjlemon{
94174135Sjlemon	int i;
94274135Sjlemon
94378025Sdes	sbuf_printf(sb, "Character devices:\n");
94474135Sjlemon
94578025Sdes	for (i = 0; i < NUMCDEVSW; i++)
94674135Sjlemon		if (cdevsw[i] != NULL)
94778025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
94874135Sjlemon
94978025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
950119068Sdes
95178025Sdes	return (0);
95274135Sjlemon}
95385538Sphk#endif
95474135Sjlemon
95578113Sdes/*
95678113Sdes * Filler function for proc/cmdline
95778113Sdes */
95878025Sdesstatic int
95978025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
96074135Sjlemon{
96178025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
96278025Sdes	sbuf_printf(sb, " ro root=302\n");
96378025Sdes	return (0);
96478025Sdes}
96574135Sjlemon
96683926Sdes#if 0
96778025Sdes/*
96883926Sdes * Filler function for proc/modules
96983926Sdes */
97083926Sdesstatic int
97183926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
97283926Sdes{
97383926Sdes	struct linker_file *lf;
974119068Sdes
97583926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
97683926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
97783926Sdes		    (unsigned long)lf->size, lf->refs);
97883926Sdes	}
97983926Sdes	return (0);
98083926Sdes}
98183926Sdes#endif
98283926Sdes
98383926Sdes/*
98485129Sdes * Constructor
98578025Sdes */
98685129Sdesstatic int
98785129Sdeslinprocfs_init(PFS_INIT_ARGS)
98885129Sdes{
98985129Sdes	struct pfs_node *root;
99085129Sdes	struct pfs_node *dir;
99174135Sjlemon
99285129Sdes	root = pi->pi_root;
99378025Sdes
994119923Sdes	/* /proc/... */
995119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
996119911Sdes	    NULL, NULL, PFS_RD);
997119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
998119911Sdes	    NULL, NULL, PFS_RD);
99985538Sphk#if 0
1000119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1001119911Sdes	    NULL, NULL, PFS_RD);
100285538Sphk#endif
1003119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1004119911Sdes	    NULL, NULL, PFS_RD);
1005119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1006119911Sdes	    NULL, NULL, PFS_RD);
100783926Sdes#if 0
1008119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1009119911Sdes	    NULL, NULL, PFS_RD);
101083926Sdes#endif
1011119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1012119911Sdes	    NULL, NULL, PFS_RD);
101387543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
101485129Sdes	    NULL, NULL, 0);
1015119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1016119911Sdes	    NULL, NULL, PFS_RD);
1017119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1018119911Sdes	    NULL, NULL, PFS_RD);
1019119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1020119911Sdes	    NULL, NULL, PFS_RD);
102178025Sdes
1022119923Sdes	/* /proc/net/... */
102385129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
102485129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
102585129Sdes	    NULL, NULL, PFS_RD);
102678025Sdes
1027119923Sdes	/* /proc/<pid>/... */
102885129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
102985129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
103085129Sdes	    NULL, NULL, PFS_RD);
1031119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1032119911Sdes	    NULL, NULL, 0);
1033116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1034116173Sobrien	    NULL, NULL, PFS_RD);
103587543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
103687543Sdes	    NULL, &procfs_notsystem, 0);
1037116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1038116173Sobrien	    NULL, NULL, PFS_RD);
103985129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
104085129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1041119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1042119911Sdes	    NULL, NULL, 0);
104385129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
104485129Sdes	    NULL, NULL, PFS_RD);
1045119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1046119911Sdes	    NULL, NULL, PFS_RD);
104785129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
104885129Sdes	    NULL, NULL, PFS_RD);
104985129Sdes
105085129Sdes	return (0);
105185129Sdes}
105285129Sdes
105385129Sdes/*
105485129Sdes * Destructor
105585129Sdes */
105685129Sdesstatic int
105785129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
105885129Sdes{
105985129Sdes
106085129Sdes	/* nothing to do, pseudofs will GC */
106185129Sdes	return (0);
106285129Sdes}
106385129Sdes
106485129SdesPSEUDOFS(linprocfs, 1);
106578025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
106678025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1067