linprocfs.c revision 85657
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 * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 85657 2001-10-29 02:17:41Z dillon $
4259412Smsmith */
4359412Smsmith
4459412Smsmith#include <sys/param.h>
4583926Sdes#include <sys/queue.h>
4676166Smarkm#include <sys/blist.h>
4774135Sjlemon#include <sys/conf.h>
4865633Sdes#include <sys/dkstat.h>
4983926Sdes#include <sys/exec.h>
5076166Smarkm#include <sys/jail.h>
5165633Sdes#include <sys/kernel.h>
5283926Sdes#include <sys/linker.h>
5376166Smarkm#include <sys/lock.h>
5474135Sjlemon#include <sys/malloc.h>
5578025Sdes#include <sys/mount.h>
5676827Salfred#include <sys/mutex.h>
5785289Sdes#include <sys/namei.h>
5865633Sdes#include <sys/proc.h>
5965633Sdes#include <sys/resourcevar.h>
6069995Sdes#include <sys/sbuf.h>
6183926Sdes#include <sys/socket.h>
6276839Sjlemon#include <sys/sysctl.h>
6383926Sdes#include <sys/systm.h>
6465633Sdes#include <sys/tty.h>
6583926Sdes#include <sys/user.h>
6683926Sdes#include <sys/vmmeter.h>
6759412Smsmith#include <sys/vnode.h>
6859412Smsmith
6983926Sdes#include <net/if.h>
7083926Sdes
7159412Smsmith#include <vm/vm.h>
7259412Smsmith#include <vm/pmap.h>
7367588Sdes#include <vm/vm_map.h>
7459412Smsmith#include <vm/vm_param.h>
7560860Sdes#include <vm/vm_object.h>
7669995Sdes#include <vm/vm_zone.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
9385129Sdes#include <compat/linux/linux_ioctl.h>
9469995Sdes#include <compat/linux/linux_mib.h>
9585289Sdes#include <compat/linux/linux_util.h>
9678025Sdes#include <fs/pseudofs/pseudofs.h>
9784248Sdes#include <fs/procfs/procfs.h>
9859412Smsmith
9967588Sdes/*
10067588Sdes * Various conversion macros
10167588Sdes */
10276405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10367588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10467588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10569799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10667588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10767588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
10874135Sjlemon
10978113Sdes/*
11078113Sdes * Filler function for proc/meminfo
11178113Sdes */
11278025Sdesstatic int
11378025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
11459412Smsmith{
11559412Smsmith	unsigned long memtotal;		/* total memory in bytes */
11659412Smsmith	unsigned long memused;		/* used memory in bytes */
11759412Smsmith	unsigned long memfree;		/* free memory in bytes */
11859412Smsmith	unsigned long memshared;	/* shared memory ??? */
11959412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
12076839Sjlemon	u_quad_t swaptotal;		/* total swap space in bytes */
12176839Sjlemon	u_quad_t swapused;		/* used swap space in bytes */
12276839Sjlemon	u_quad_t swapfree;		/* free swap space in bytes */
12360860Sdes	vm_object_t object;
12459412Smsmith
12559412Smsmith	memtotal = physmem * PAGE_SIZE;
12659412Smsmith	/*
12759412Smsmith	 * The correct thing here would be:
12859412Smsmith	 *
12959412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13059412Smsmith	memused = memtotal - memfree;
13159412Smsmith	 *
13259412Smsmith	 * but it might mislead linux binaries into thinking there
13359412Smsmith	 * is very little memory left, so we cheat and tell them that
13459412Smsmith	 * all memory that isn't wired down is free.
13559412Smsmith	 */
13659412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
13759412Smsmith	memfree = memtotal - memused;
13864560Sbde	if (swapblist == NULL) {
13964560Sbde		swaptotal = 0;
14064560Sbde		swapfree = 0;
14164560Sbde	} else {
14276839Sjlemon		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
14376839Sjlemon		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
14464560Sbde	}
14559412Smsmith	swapused = swaptotal - swapfree;
14660860Sdes	memshared = 0;
14771471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14860860Sdes		if (object->shadow_count > 1)
14960860Sdes			memshared += object->resident_page_count;
15060860Sdes	memshared *= PAGE_SIZE;
15159412Smsmith	/*
15259412Smsmith	 * We'd love to be able to write:
15359412Smsmith	 *
15459412Smsmith	buffers = bufspace;
15559412Smsmith	 *
15659412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
15759412Smsmith	 * like unstaticizing it just for linprocfs's sake.
15859412Smsmith	 */
15959412Smsmith	buffers = 0;
16059412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
16159412Smsmith
16278025Sdes	sbuf_printf(sb,
16378031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
16469799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
16576839Sjlemon	    "Swap: %llu %llu %llu\n"
16669799Sdes	    "MemTotal: %9lu kB\n"
16769799Sdes	    "MemFree:  %9lu kB\n"
16869799Sdes	    "MemShared:%9lu kB\n"
16969799Sdes	    "Buffers:  %9lu kB\n"
17069799Sdes	    "Cached:   %9lu kB\n"
17176839Sjlemon	    "SwapTotal:%9llu kB\n"
17276839Sjlemon	    "SwapFree: %9llu kB\n",
17369799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
17469799Sdes	    swaptotal, swapused, swapfree,
17569799Sdes	    B2K(memtotal), B2K(memfree),
17669799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
17769799Sdes	    B2K(swaptotal), B2K(swapfree));
17859412Smsmith
17978025Sdes	return (0);
18059412Smsmith}
18159412Smsmith
18278113Sdes#ifdef __alpha__
18378113Sdes/*
18478113Sdes * Filler function for proc/cpuinfo (Alpha version)
18578113Sdes */
18678025Sdesstatic int
18778025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
18859412Smsmith{
18978113Sdes	u_int64_t type, major;
19078113Sdes	struct pcs *pcsp;
19178113Sdes	const char *model, *sysname;
19278113Sdes
19378113Sdes	static const char *cpuname[] = {
19478113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
19578113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
19678113Sdes	};
19778113Sdes
19878113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
19978113Sdes	type = pcsp->pcs_proc_type;
20078113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20178113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20278113Sdes		model = cpuname[major - 1];
20378113Sdes	} else {
20478113Sdes		model = "unknown";
20578113Sdes	}
20678113Sdes
20778113Sdes	sysname = alpha_dsr_sysname();
20878113Sdes
20978113Sdes	sbuf_printf(sb,
21078113Sdes	    "cpu\t\t\t: Alpha\n"
21178113Sdes	    "cpu model\t\t: %s\n"
21278113Sdes	    "cpu variation\t\t: %ld\n"
21378113Sdes	    "cpu revision\t\t: %ld\n"
21478113Sdes	    "cpu serial number\t: %s\n"
21578113Sdes	    "system type\t\t: %s\n"
21678113Sdes	    "system variation\t: %s\n"
21778113Sdes	    "system revision\t\t: %ld\n"
21878113Sdes	    "system serial number\t: %s\n"
21978113Sdes	    "cycle frequency [Hz]\t: %lu\n"
22078113Sdes	    "timer frequency [Hz]\t: %lu\n"
22178113Sdes	    "page size [bytes]\t: %ld\n"
22278113Sdes	    "phys. address bits\t: %ld\n"
22378113Sdes	    "max. addr. space #\t: %ld\n"
22478113Sdes	    "BogoMIPS\t\t: %lu.%02lu\n"
22578113Sdes	    "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
22678113Sdes	    "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
22778113Sdes	    "platform string\t\t: %s\n"
22878113Sdes	    "cpus detected\t\t: %d\n"
22978113Sdes	    ,
23078113Sdes	    model,
23178113Sdes	    pcsp->pcs_proc_var,
23278113Sdes	    *(int *)hwrpb->rpb_revision,
23378113Sdes	    " ",
23478113Sdes	    " ",
23578113Sdes	    "0",
23678113Sdes	    0,
23778113Sdes	    " ",
23878113Sdes	    hwrpb->rpb_cc_freq,
23978113Sdes	    hz,
24078113Sdes	    hwrpb->rpb_page_size,
24178113Sdes	    hwrpb->rpb_phys_addr_size,
24278113Sdes	    hwrpb->rpb_max_asn,
24378113Sdes	    0, 0,
24478113Sdes	    0, 0, 0,
24578113Sdes	    0, 0, 0,
24678113Sdes	    sysname,
24778113Sdes	    ncpus);
24878113Sdes	return (0);
24978113Sdes}
25078113Sdes#endif /* __alpha__ */
25178113Sdes
25278113Sdes#ifdef __i386__
25378113Sdes/*
25478113Sdes * Filler function for proc/cpuinfo (i386 version)
25578113Sdes */
25678113Sdesstatic int
25778113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
25878113Sdes{
25969799Sdes	int class, i, fqmhz, fqkhz;
26059412Smsmith
26169799Sdes	/*
26278031Sdes	 * We default the flags to include all non-conflicting flags,
26378031Sdes	 * and the Intel versions of conflicting flags.
26469799Sdes	 */
26578031Sdes	static char *flags[] = {
26678031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
26778031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
26878031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
26978031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
27078031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27178031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
27267589Sdes		"3dnowext", "3dnow"
27367589Sdes	};
27467589Sdes
27559412Smsmith	switch (cpu_class) {
27659412Smsmith	case CPUCLASS_286:
27767589Sdes		class = 2;
27859412Smsmith		break;
27959412Smsmith	case CPUCLASS_386:
28067589Sdes		class = 3;
28159412Smsmith		break;
28259412Smsmith	case CPUCLASS_486:
28367589Sdes		class = 4;
28459412Smsmith		break;
28559412Smsmith	case CPUCLASS_586:
28667589Sdes		class = 5;
28759412Smsmith		break;
28859412Smsmith	case CPUCLASS_686:
28967589Sdes		class = 6;
29059412Smsmith		break;
29159412Smsmith	default:
29278031Sdes		class = 0;
29359412Smsmith		break;
29459412Smsmith	}
29559412Smsmith
29678025Sdes	sbuf_printf(sb,
29778031Sdes	    "processor\t: %d\n"
29869799Sdes	    "vendor_id\t: %.20s\n"
29969799Sdes	    "cpu family\t: %d\n"
30069799Sdes	    "model\t\t: %d\n"
30169799Sdes	    "stepping\t: %d\n",
30269799Sdes	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
30359412Smsmith
30478031Sdes	sbuf_cat(sb,
30578031Sdes	    "flags\t\t:");
30667589Sdes
30778031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
30867589Sdes		flags[16] = "fcmov";
30978031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
31067589Sdes		flags[24] = "cxmmx";
31178031Sdes	}
31278031Sdes
31378031Sdes	for (i = 0; i < 32; i++)
31467589Sdes		if (cpu_feature & (1 << i))
31578025Sdes			sbuf_printf(sb, " %s", flags[i]);
31678025Sdes	sbuf_cat(sb, "\n");
31778031Sdes	if (class >= 5) {
31869799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
31969799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
32078025Sdes		sbuf_printf(sb,
32169799Sdes		    "cpu MHz\t\t: %d.%02d\n"
32269799Sdes		    "bogomips\t: %d.%02d\n",
32369799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
32478031Sdes	}
32569995Sdes
32678025Sdes	return (0);
32759412Smsmith}
32878113Sdes#endif /* __i386__ */
32965633Sdes
33078113Sdes/*
33185289Sdes * Filler function for proc/mtab
33285289Sdes *
33385289Sdes * This file doesn't exist in Linux' procfs, but is included here so
33485289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
33585289Sdes */
33685289Sdesstatic int
33785289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
33885289Sdes{
33985289Sdes	struct nameidata nd;
34085289Sdes	struct mount *mp;
34185289Sdes	char *lep, *flep, *mntto, *mntfrom, *fstype;
34285289Sdes	size_t lep_len;
34385289Sdes	int error;
34485289Sdes
34585289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
34685289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
34785289Sdes	flep = NULL;
34885289Sdes	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1)
34985289Sdes		lep = linux_emul_path;
35085289Sdes	lep_len = strlen(lep);
35185289Sdes
35285289Sdes	mtx_lock(&mountlist_mtx);
35385289Sdes	error = 0;
35485289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
35585289Sdes		error = VFS_STATFS(mp, &mp->mnt_stat, td);
35685289Sdes		if (error)
35785289Sdes			break;
35885289Sdes
35985289Sdes		/* determine device name */
36085289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
36185289Sdes
36285289Sdes		/* determine mount point */
36385289Sdes		mntto = mp->mnt_stat.f_mntonname;
36485289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
36585289Sdes		    mntto[lep_len] == '/')
36685289Sdes			mntto += lep_len;
36785289Sdes
36885289Sdes		/* determine fs type */
36985289Sdes		fstype = mp->mnt_stat.f_fstypename;
37085289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
37185289Sdes			mntfrom = fstype = "proc";
37285289Sdes		else if (strcmp(fstype, "procfs") == 0)
37385289Sdes			continue;
37485289Sdes
37585289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
37685289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
37785289Sdes#define ADD_OPTION(opt, name) \
37885289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
37985289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
38085289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
38185289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
38285289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
38385289Sdes		ADD_OPTION(MNT_UNION,		"union");
38485289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
38585289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
38685289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
38785289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
38885289Sdes#undef ADD_OPTION
38985289Sdes		/* a real Linux mtab will also show NFS options */
39085289Sdes		sbuf_printf(sb, " 0 0\n");
39185289Sdes	}
39285289Sdes	mtx_unlock(&mountlist_mtx);
39385289Sdes	if (flep != NULL)
39485289Sdes		free(flep, M_TEMP);
39585289Sdes	return (error);
39685289Sdes}
39785289Sdes
39885289Sdes/*
39978113Sdes * Filler function for proc/stat
40078113Sdes */
40178025Sdesstatic int
40278025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
40365633Sdes{
40478025Sdes	sbuf_printf(sb,
40569799Sdes	    "cpu %ld %ld %ld %ld\n"
40669799Sdes	    "disk 0 0 0 0\n"
40769799Sdes	    "page %u %u\n"
40869799Sdes	    "swap %u %u\n"
40969799Sdes	    "intr %u\n"
41069799Sdes	    "ctxt %u\n"
41185657Sdillon	    "btime %lld\n",
41269799Sdes	    T2J(cp_time[CP_USER]),
41369799Sdes	    T2J(cp_time[CP_NICE]),
41469799Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
41569799Sdes	    T2J(cp_time[CP_IDLE]),
41669799Sdes	    cnt.v_vnodepgsin,
41769799Sdes	    cnt.v_vnodepgsout,
41869799Sdes	    cnt.v_swappgsin,
41969799Sdes	    cnt.v_swappgsout,
42069799Sdes	    cnt.v_intr,
42169799Sdes	    cnt.v_swtch,
42285657Sdillon	    (quad_t)boottime.tv_sec);
42378025Sdes	return (0);
42465633Sdes}
42565633Sdes
42678113Sdes/*
42778113Sdes * Filler function for proc/uptime
42878113Sdes */
42978025Sdesstatic int
43078025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
43165633Sdes{
43265633Sdes	struct timeval tv;
43365633Sdes
43465633Sdes	getmicrouptime(&tv);
43585657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
43685657Sdillon	    (quad_t)tv.tv_sec, tv.tv_usec / 10000,
43769799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
43878025Sdes	return (0);
43965633Sdes}
44065633Sdes
44178113Sdes/*
44278113Sdes * Filler function for proc/version
44378113Sdes */
44478025Sdesstatic int
44578025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
44665633Sdes{
44778025Sdes	sbuf_printf(sb,
44869995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
44969995Sdes	    " #4 Sun Dec 18 04:30:00 CET 1977\n",
45083366Sjulian	    linux_get_osname(td->td_proc),
45183366Sjulian	    linux_get_osrelease(td->td_proc));
45278025Sdes	return (0);
45365633Sdes}
45465633Sdes
45578113Sdes/*
45678113Sdes * Filler function for proc/loadavg
45778113Sdes */
45878025Sdesstatic int
45978025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
46076839Sjlemon{
46178025Sdes	sbuf_printf(sb,
46276839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
46376839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
46476839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
46576839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
46676839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
46776839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
46876839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
46976839Sjlemon	    1,				/* number of running tasks */
47076839Sjlemon	    nprocs,			/* number of tasks */
47178116Sdes	    lastpid			/* the last pid */
47276839Sjlemon	);
47378025Sdes
47478025Sdes	return (0);
47576839Sjlemon}
47676839Sjlemon
47778113Sdes/*
47878113Sdes * Filler function for proc/pid/stat
47978113Sdes */
48078025Sdesstatic int
48178025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
48267588Sdes{
48369995Sdes	struct kinfo_proc kp;
48467588Sdes
48569995Sdes	fill_kinfo_proc(p, &kp);
48678025Sdes	sbuf_printf(sb, "%d", p->p_pid);
48778025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
48867588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
48967588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
49073923Sjhb	PROC_LOCK(p);
49173923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
49273923Sjhb	PROC_UNLOCK(p);
49367588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
49467588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
49567588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
49667588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
49767588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
49867588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
49967588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50067588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
50167588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50267588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
50367588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
50467588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
50567588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
50667588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
50767588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
50867588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
50967588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
51067588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
51169995Sdes	PS_ADD("vsize",		"%u",	kp.ki_size);
51269995Sdes	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
51367588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
51469995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
51567588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
51667588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
51769799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
51869799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
51967588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
52067588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
52167588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
52267588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
52367588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
52469799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
52569799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
52669799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
52769799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
52867588Sdes#undef PS_ADD
52978025Sdes	sbuf_putc(sb, '\n');
53067588Sdes
53178025Sdes	return (0);
53267588Sdes}
53367588Sdes
53467588Sdes/*
53567588Sdes * Map process state to descriptive letter. Note that this does not
53667588Sdes * quite correspond to what Linux outputs, but it's close enough.
53767588Sdes */
53867588Sdesstatic char *state_str[] = {
53967588Sdes	"? (unknown)",
54067588Sdes	"I (idle)",
54167588Sdes	"R (running)",
54267588Sdes	"S (sleeping)",
54367588Sdes	"T (stopped)",
54467588Sdes	"Z (zombie)",
54567588Sdes	"W (waiting)",
54667588Sdes	"M (mutex)"
54767588Sdes};
54867588Sdes
54978113Sdes/*
55078113Sdes * Filler function for proc/pid/status
55178113Sdes */
55278025Sdesstatic int
55378025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
55467588Sdes{
55569995Sdes	struct kinfo_proc kp;
55667588Sdes	char *state;
55769799Sdes	segsz_t lsize;
55874135Sjlemon	int i;
55967588Sdes
56072200Sbmilekic	mtx_lock_spin(&sched_lock);
56167588Sdes	if (p->p_stat > sizeof state_str / sizeof *state_str)
56267588Sdes		state = state_str[0];
56367588Sdes	else
56467588Sdes		state = state_str[(int)p->p_stat];
56572200Sbmilekic	mtx_unlock_spin(&sched_lock);
56667588Sdes
56769995Sdes	fill_kinfo_proc(p, &kp);
56878025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
56978031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
57067588Sdes
57167588Sdes	/*
57267588Sdes	 * Credentials
57367588Sdes	 */
57478025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
57571471Sjhb	PROC_LOCK(p);
57678025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
57773923Sjhb						p->p_pptr->p_pid : 0);
57878031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
57978031Sdes						p->p_ucred->cr_uid,
58078031Sdes						p->p_ucred->cr_svuid,
58178031Sdes						/* FreeBSD doesn't have fsuid */
58278031Sdes						p->p_ucred->cr_uid);
58378031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
58478031Sdes						p->p_ucred->cr_gid,
58578031Sdes						p->p_ucred->cr_svgid,
58678031Sdes						/* FreeBSD doesn't have fsgid */
58778031Sdes						p->p_ucred->cr_gid);
58878025Sdes	sbuf_cat(sb, "Groups:\t");
58967588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
59078031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
59171471Sjhb	PROC_UNLOCK(p);
59278025Sdes	sbuf_putc(sb, '\n');
59367588Sdes
59467588Sdes	/*
59567588Sdes	 * Memory
59669799Sdes	 *
59769799Sdes	 * While our approximation of VmLib may not be accurate (I
59869799Sdes	 * don't know of a simple way to verify it, and I'm not sure
59969799Sdes	 * it has much meaning anyway), I believe it's good enough.
60069799Sdes	 *
60169799Sdes	 * The same code that could (I think) accurately compute VmLib
60269799Sdes	 * could also compute VmLck, but I don't really care enough to
60369799Sdes	 * implement it. Submissions are welcome.
60467588Sdes	 */
60578025Sdes	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
60678025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
60778025Sdes	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
60878025Sdes	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
60978025Sdes	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
61078025Sdes	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
61169995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
61269995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
61378025Sdes	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
61467588Sdes
61567588Sdes	/*
61667588Sdes	 * Signal masks
61767588Sdes	 *
61867588Sdes	 * We support up to 128 signals, while Linux supports 32,
61967588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
62067588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
62167588Sdes	 *
62267588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
62367588Sdes	 * supports 64 signals, but this code is a long way from
62467588Sdes	 * running on anything but i386, so ignore that for now.
62567588Sdes	 */
62671471Sjhb	PROC_LOCK(p);
62778025Sdes	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
62869799Sdes	/*
62969799Sdes	 * I can't seem to find out where the signal mask is in
63069799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
63169799Sdes	 */
63278025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
63378025Sdes	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
63478025Sdes	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
63571471Sjhb	PROC_UNLOCK(p);
63667588Sdes
63767588Sdes	/*
63867588Sdes	 * Linux also prints the capability masks, but we don't have
63967588Sdes	 * capabilities yet, and when we do get them they're likely to
64067588Sdes	 * be meaningless to Linux programs, so we lie. XXX
64167588Sdes	 */
64278025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
64378025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
64478025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
64578025Sdes
64678025Sdes	return (0);
64767588Sdes}
64874135Sjlemon
64978113Sdes/*
65078113Sdes * Filler function for proc/self
65178113Sdes */
65278025Sdesstatic int
65378025Sdeslinprocfs_doselflink(PFS_FILL_ARGS)
65474135Sjlemon{
65583366Sjulian	sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid);
65678025Sdes	return (0);
65774135Sjlemon}
65874135Sjlemon
65978113Sdes/*
66078113Sdes * Filler function for proc/pid/cmdline
66178113Sdes */
66278025Sdesstatic int
66378113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
66478113Sdes{
66578113Sdes	struct ps_strings pstr;
66678113Sdes	int error, i;
66778113Sdes
66878113Sdes	/*
66978113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
67078113Sdes	 * revert back to the old way which only implements full cmdline
67178113Sdes	 * for the currept process and just p->p_comm for all other
67278113Sdes	 * processes.
67378113Sdes	 * Note that if the argv is no longer available, we deliberately
67478113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
67578113Sdes	 * Linux behaviour is to return zero-length in this case.
67678113Sdes	 */
67778113Sdes
67883366Sjulian	if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) {
67978113Sdes		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
68083366Sjulian	} else if (p != td->td_proc) {
68178113Sdes		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
68278113Sdes	} else {
68378113Sdes		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
68478113Sdes		if (error)
68578113Sdes			return (error);
68678113Sdes		for (i = 0; i < pstr.ps_nargvstr; i++) {
68778113Sdes			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
68878113Sdes			sbuf_printf(sb, "%c", '\0');
68978113Sdes		}
69078113Sdes	}
69178113Sdes
69278113Sdes	return (0);
69378113Sdes}
69478113Sdes
69578113Sdes/*
69678113Sdes * Filler function for proc/pid/exe
69778113Sdes */
69878113Sdesstatic int
69985129Sdeslinprocfs_doprocexe(PFS_FILL_ARGS)
70074135Sjlemon{
70174135Sjlemon	char *fullpath = "unknown";
70274135Sjlemon	char *freepath = NULL;
70374135Sjlemon
70485289Sdes	vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath);
70578025Sdes	sbuf_printf(sb, "%s", fullpath);
70674135Sjlemon	if (freepath)
70774135Sjlemon		free(freepath, M_TEMP);
70878025Sdes	return (0);
70974135Sjlemon}
71074135Sjlemon
71178113Sdes/*
71278113Sdes * Filler function for proc/net/dev
71378113Sdes */
71478025Sdesstatic int
71578025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
71674135Sjlemon{
71785129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
71874135Sjlemon	struct ifnet *ifp;
71974135Sjlemon
72085129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
72183926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
72285129Sdes	    "bytes    packets errs drop fifo frame compressed",
72383926Sdes	    "bytes    packets errs drop fifo frame compressed");
72474135Sjlemon
72574135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
72685129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
72785129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
72883926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
72983926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
73083926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
73183926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
73274135Sjlemon	}
73378025Sdes
73478025Sdes	return (0);
73574135Sjlemon}
73674135Sjlemon
73785538Sphk#if 0
73885538Sphkextern struct cdevsw *cdevsw[];
73985538Sphk
74078113Sdes/*
74178113Sdes * Filler function for proc/devices
74278113Sdes */
74378025Sdesstatic int
74478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
74574135Sjlemon{
74674135Sjlemon	int i;
74774135Sjlemon
74878025Sdes	sbuf_printf(sb, "Character devices:\n");
74974135Sjlemon
75078025Sdes	for (i = 0; i < NUMCDEVSW; i++)
75174135Sjlemon		if (cdevsw[i] != NULL)
75278025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
75374135Sjlemon
75478025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
75578025Sdes
75678025Sdes	return (0);
75774135Sjlemon}
75885538Sphk#endif
75974135Sjlemon
76078113Sdes/*
76178113Sdes * Filler function for proc/cmdline
76278113Sdes */
76378025Sdesstatic int
76478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
76574135Sjlemon{
76678025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
76778025Sdes	sbuf_printf(sb, " ro root=302\n");
76878025Sdes	return (0);
76978025Sdes}
77074135Sjlemon
77183926Sdes#if 0
77278025Sdes/*
77383926Sdes * Filler function for proc/modules
77483926Sdes */
77583926Sdesstatic int
77683926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
77783926Sdes{
77883926Sdes	struct linker_file *lf;
77983926Sdes
78083926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
78183926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
78283926Sdes		    (unsigned long)lf->size, lf->refs);
78383926Sdes	}
78483926Sdes	return (0);
78583926Sdes}
78683926Sdes#endif
78783926Sdes
78883926Sdes/*
78985129Sdes * Constructor
79078025Sdes */
79185129Sdesstatic int
79285129Sdeslinprocfs_init(PFS_INIT_ARGS)
79385129Sdes{
79485129Sdes	struct pfs_node *root;
79585129Sdes	struct pfs_node *dir;
79674135Sjlemon
79785129Sdes	root = pi->pi_root;
79878025Sdes
79985129Sdes#define PFS_CREATE_FILE(name) \
80085129Sdes	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
80185129Sdes	PFS_CREATE_FILE(cmdline);
80285129Sdes	PFS_CREATE_FILE(cpuinfo);
80385538Sphk#if 0
80485129Sdes	PFS_CREATE_FILE(devices);
80585538Sphk#endif
80685129Sdes	PFS_CREATE_FILE(loadavg);
80785129Sdes	PFS_CREATE_FILE(meminfo);
80883926Sdes#if 0
80985129Sdes	PFS_CREATE_FILE(modules);
81083926Sdes#endif
81185289Sdes	PFS_CREATE_FILE(mtab);
81285129Sdes	PFS_CREATE_FILE(stat);
81385129Sdes	PFS_CREATE_FILE(uptime);
81485129Sdes	PFS_CREATE_FILE(version);
81585129Sdes#undef PFS_CREATE_FILE
81685129Sdes	pfs_create_link(root, "self", &linprocfs_doselflink,
81785129Sdes	    NULL, NULL, 0);
81878025Sdes
81985129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
82085129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
82185129Sdes	    NULL, NULL, PFS_RD);
82278025Sdes
82385129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
82485129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
82585129Sdes	    NULL, NULL, PFS_RD);
82685129Sdes	pfs_create_link(dir, "exe", &linprocfs_doprocexe,
82785129Sdes	    NULL, NULL, 0);
82885130Sdes#if 0
82985129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
83085129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
83185130Sdes#endif
83285129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
83385129Sdes	    NULL, NULL, PFS_RD);
83485129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
83585129Sdes	    NULL, NULL, PFS_RD);
83685129Sdes
83785129Sdes	return (0);
83885129Sdes}
83985129Sdes
84085129Sdes/*
84185129Sdes * Destructor
84285129Sdes */
84385129Sdesstatic int
84485129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
84585129Sdes{
84685129Sdes
84785129Sdes	/* nothing to do, pseudofs will GC */
84885129Sdes	return (0);
84985129Sdes}
85085129Sdes
85185129SdesPSEUDOFS(linprocfs, 1);
85278025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
85378025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
854