linprocfs.c revision 87543
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 87543 2001-12-09 00:38:59Z des $
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
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 ??? */
12176839Sjlemon	u_quad_t swaptotal;		/* total swap space in bytes */
12276839Sjlemon	u_quad_t swapused;		/* used swap space in bytes */
12376839Sjlemon	u_quad_t swapfree;		/* free swap space in bytes */
12460860Sdes	vm_object_t object;
12559412Smsmith
12659412Smsmith	memtotal = physmem * PAGE_SIZE;
12759412Smsmith	/*
12859412Smsmith	 * The correct thing here would be:
12959412Smsmith	 *
13059412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13159412Smsmith	memused = memtotal - memfree;
13259412Smsmith	 *
13359412Smsmith	 * but it might mislead linux binaries into thinking there
13459412Smsmith	 * is very little memory left, so we cheat and tell them that
13559412Smsmith	 * all memory that isn't wired down is free.
13659412Smsmith	 */
13759412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
13859412Smsmith	memfree = memtotal - memused;
13964560Sbde	if (swapblist == NULL) {
14064560Sbde		swaptotal = 0;
14164560Sbde		swapfree = 0;
14264560Sbde	} else {
14376839Sjlemon		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
14476839Sjlemon		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
14564560Sbde	}
14659412Smsmith	swapused = swaptotal - swapfree;
14760860Sdes	memshared = 0;
14871471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14960860Sdes		if (object->shadow_count > 1)
15060860Sdes			memshared += object->resident_page_count;
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__
18478113Sdes/*
18578113Sdes * Filler function for proc/cpuinfo (Alpha version)
18678113Sdes */
18778025Sdesstatic int
18878025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
18959412Smsmith{
19078113Sdes	u_int64_t type, major;
19178113Sdes	struct pcs *pcsp;
19278113Sdes	const char *model, *sysname;
19378113Sdes
19478113Sdes	static const char *cpuname[] = {
19578113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
19678113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
19778113Sdes	};
19878113Sdes
19978113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
20078113Sdes	type = pcsp->pcs_proc_type;
20178113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20278113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20378113Sdes		model = cpuname[major - 1];
20478113Sdes	} else {
20578113Sdes		model = "unknown";
20678113Sdes	}
20778113Sdes
20878113Sdes	sysname = alpha_dsr_sysname();
20978113Sdes
21078113Sdes	sbuf_printf(sb,
21178113Sdes	    "cpu\t\t\t: Alpha\n"
21278113Sdes	    "cpu model\t\t: %s\n"
21378113Sdes	    "cpu variation\t\t: %ld\n"
21478113Sdes	    "cpu revision\t\t: %ld\n"
21578113Sdes	    "cpu serial number\t: %s\n"
21678113Sdes	    "system type\t\t: %s\n"
21778113Sdes	    "system variation\t: %s\n"
21878113Sdes	    "system revision\t\t: %ld\n"
21978113Sdes	    "system serial number\t: %s\n"
22078113Sdes	    "cycle frequency [Hz]\t: %lu\n"
22178113Sdes	    "timer frequency [Hz]\t: %lu\n"
22278113Sdes	    "page size [bytes]\t: %ld\n"
22378113Sdes	    "phys. address bits\t: %ld\n"
22478113Sdes	    "max. addr. space #\t: %ld\n"
22578113Sdes	    "BogoMIPS\t\t: %lu.%02lu\n"
22678113Sdes	    "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
22778113Sdes	    "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
22878113Sdes	    "platform string\t\t: %s\n"
22978113Sdes	    "cpus detected\t\t: %d\n"
23078113Sdes	    ,
23178113Sdes	    model,
23278113Sdes	    pcsp->pcs_proc_var,
23378113Sdes	    *(int *)hwrpb->rpb_revision,
23478113Sdes	    " ",
23578113Sdes	    " ",
23678113Sdes	    "0",
23778113Sdes	    0,
23878113Sdes	    " ",
23978113Sdes	    hwrpb->rpb_cc_freq,
24078113Sdes	    hz,
24178113Sdes	    hwrpb->rpb_page_size,
24278113Sdes	    hwrpb->rpb_phys_addr_size,
24378113Sdes	    hwrpb->rpb_max_asn,
24478113Sdes	    0, 0,
24578113Sdes	    0, 0, 0,
24678113Sdes	    0, 0, 0,
24778113Sdes	    sysname,
24878113Sdes	    ncpus);
24978113Sdes	return (0);
25078113Sdes}
25178113Sdes#endif /* __alpha__ */
25278113Sdes
25378113Sdes#ifdef __i386__
25478113Sdes/*
25578113Sdes * Filler function for proc/cpuinfo (i386 version)
25678113Sdes */
25778113Sdesstatic int
25878113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
25978113Sdes{
26069799Sdes	int class, i, fqmhz, fqkhz;
26159412Smsmith
26269799Sdes	/*
26378031Sdes	 * We default the flags to include all non-conflicting flags,
26478031Sdes	 * and the Intel versions of conflicting flags.
26569799Sdes	 */
26678031Sdes	static char *flags[] = {
26778031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
26878031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
26978031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
27078031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
27178031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27278031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
27367589Sdes		"3dnowext", "3dnow"
27467589Sdes	};
27567589Sdes
27659412Smsmith	switch (cpu_class) {
27759412Smsmith	case CPUCLASS_286:
27867589Sdes		class = 2;
27959412Smsmith		break;
28059412Smsmith	case CPUCLASS_386:
28167589Sdes		class = 3;
28259412Smsmith		break;
28359412Smsmith	case CPUCLASS_486:
28467589Sdes		class = 4;
28559412Smsmith		break;
28659412Smsmith	case CPUCLASS_586:
28767589Sdes		class = 5;
28859412Smsmith		break;
28959412Smsmith	case CPUCLASS_686:
29067589Sdes		class = 6;
29159412Smsmith		break;
29259412Smsmith	default:
29378031Sdes		class = 0;
29459412Smsmith		break;
29559412Smsmith	}
29659412Smsmith
29778025Sdes	sbuf_printf(sb,
29878031Sdes	    "processor\t: %d\n"
29969799Sdes	    "vendor_id\t: %.20s\n"
30069799Sdes	    "cpu family\t: %d\n"
30169799Sdes	    "model\t\t: %d\n"
30269799Sdes	    "stepping\t: %d\n",
30369799Sdes	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
30459412Smsmith
30578031Sdes	sbuf_cat(sb,
30678031Sdes	    "flags\t\t:");
30767589Sdes
30878031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
30967589Sdes		flags[16] = "fcmov";
31078031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
31167589Sdes		flags[24] = "cxmmx";
31278031Sdes	}
31378031Sdes
31478031Sdes	for (i = 0; i < 32; i++)
31567589Sdes		if (cpu_feature & (1 << i))
31678025Sdes			sbuf_printf(sb, " %s", flags[i]);
31778025Sdes	sbuf_cat(sb, "\n");
31878031Sdes	if (class >= 5) {
31969799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
32069799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
32178025Sdes		sbuf_printf(sb,
32269799Sdes		    "cpu MHz\t\t: %d.%02d\n"
32369799Sdes		    "bogomips\t: %d.%02d\n",
32469799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
32578031Sdes	}
32669995Sdes
32778025Sdes	return (0);
32859412Smsmith}
32978113Sdes#endif /* __i386__ */
33065633Sdes
33178113Sdes/*
33285289Sdes * Filler function for proc/mtab
33385289Sdes *
33485289Sdes * This file doesn't exist in Linux' procfs, but is included here so
33585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
33685289Sdes */
33785289Sdesstatic int
33885289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
33985289Sdes{
34085289Sdes	struct nameidata nd;
34185289Sdes	struct mount *mp;
34285289Sdes	char *lep, *flep, *mntto, *mntfrom, *fstype;
34385289Sdes	size_t lep_len;
34485289Sdes	int error;
34585289Sdes
34685289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
34785289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
34885289Sdes	flep = NULL;
34985289Sdes	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1)
35085289Sdes		lep = linux_emul_path;
35185289Sdes	lep_len = strlen(lep);
35285289Sdes
35385289Sdes	mtx_lock(&mountlist_mtx);
35485289Sdes	error = 0;
35585289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
35685289Sdes		error = VFS_STATFS(mp, &mp->mnt_stat, td);
35785289Sdes		if (error)
35885289Sdes			break;
35985289Sdes
36085289Sdes		/* determine device name */
36185289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
36285289Sdes
36385289Sdes		/* determine mount point */
36485289Sdes		mntto = mp->mnt_stat.f_mntonname;
36585289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
36685289Sdes		    mntto[lep_len] == '/')
36785289Sdes			mntto += lep_len;
36885289Sdes
36985289Sdes		/* determine fs type */
37085289Sdes		fstype = mp->mnt_stat.f_fstypename;
37185289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
37285289Sdes			mntfrom = fstype = "proc";
37385289Sdes		else if (strcmp(fstype, "procfs") == 0)
37485289Sdes			continue;
37585289Sdes
37685289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
37785289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
37885289Sdes#define ADD_OPTION(opt, name) \
37985289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
38085289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
38185289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
38285289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
38385289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
38485289Sdes		ADD_OPTION(MNT_UNION,		"union");
38585289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
38685289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
38785289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
38885289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
38985289Sdes#undef ADD_OPTION
39085289Sdes		/* a real Linux mtab will also show NFS options */
39185289Sdes		sbuf_printf(sb, " 0 0\n");
39285289Sdes	}
39385289Sdes	mtx_unlock(&mountlist_mtx);
39485289Sdes	if (flep != NULL)
39585289Sdes		free(flep, M_TEMP);
39685289Sdes	return (error);
39785289Sdes}
39885289Sdes
39985289Sdes/*
40078113Sdes * Filler function for proc/stat
40178113Sdes */
40278025Sdesstatic int
40378025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
40465633Sdes{
40578025Sdes	sbuf_printf(sb,
40669799Sdes	    "cpu %ld %ld %ld %ld\n"
40769799Sdes	    "disk 0 0 0 0\n"
40869799Sdes	    "page %u %u\n"
40969799Sdes	    "swap %u %u\n"
41069799Sdes	    "intr %u\n"
41169799Sdes	    "ctxt %u\n"
41285657Sdillon	    "btime %lld\n",
41369799Sdes	    T2J(cp_time[CP_USER]),
41469799Sdes	    T2J(cp_time[CP_NICE]),
41569799Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
41669799Sdes	    T2J(cp_time[CP_IDLE]),
41769799Sdes	    cnt.v_vnodepgsin,
41869799Sdes	    cnt.v_vnodepgsout,
41969799Sdes	    cnt.v_swappgsin,
42069799Sdes	    cnt.v_swappgsout,
42169799Sdes	    cnt.v_intr,
42269799Sdes	    cnt.v_swtch,
42385657Sdillon	    (quad_t)boottime.tv_sec);
42478025Sdes	return (0);
42565633Sdes}
42665633Sdes
42778113Sdes/*
42878113Sdes * Filler function for proc/uptime
42978113Sdes */
43078025Sdesstatic int
43178025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
43265633Sdes{
43365633Sdes	struct timeval tv;
43465633Sdes
43565633Sdes	getmicrouptime(&tv);
43685657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
43785657Sdillon	    (quad_t)tv.tv_sec, tv.tv_usec / 10000,
43869799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
43978025Sdes	return (0);
44065633Sdes}
44165633Sdes
44278113Sdes/*
44378113Sdes * Filler function for proc/version
44478113Sdes */
44578025Sdesstatic int
44678025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
44765633Sdes{
44887275Srwatson	char osname[LINUX_MAX_UTSNAME];
44987275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
45087275Srwatson
45187275Srwatson	linux_get_osname(td->td_proc, osname);
45287275Srwatson	linux_get_osrelease(td->td_proc, osrelease);
45387275Srwatson
45478025Sdes	sbuf_printf(sb,
45569995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
45687275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
45778025Sdes	return (0);
45865633Sdes}
45965633Sdes
46078113Sdes/*
46178113Sdes * Filler function for proc/loadavg
46278113Sdes */
46378025Sdesstatic int
46478025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
46576839Sjlemon{
46678025Sdes	sbuf_printf(sb,
46776839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
46876839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
46976839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
47076839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
47176839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
47276839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
47376839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
47476839Sjlemon	    1,				/* number of running tasks */
47576839Sjlemon	    nprocs,			/* number of tasks */
47678116Sdes	    lastpid			/* the last pid */
47776839Sjlemon	);
47878025Sdes
47978025Sdes	return (0);
48076839Sjlemon}
48176839Sjlemon
48278113Sdes/*
48378113Sdes * Filler function for proc/pid/stat
48478113Sdes */
48578025Sdesstatic int
48678025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
48767588Sdes{
48869995Sdes	struct kinfo_proc kp;
48967588Sdes
49069995Sdes	fill_kinfo_proc(p, &kp);
49178025Sdes	sbuf_printf(sb, "%d", p->p_pid);
49278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
49367588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
49467588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
49573923Sjhb	PROC_LOCK(p);
49673923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
49773923Sjhb	PROC_UNLOCK(p);
49867588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
49967588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
50067588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
50167588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
50267588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
50367588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
50467588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50567588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
50667588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50767588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
50867588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
50967588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
51067588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
51167588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
51267588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
51367588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
51467588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
51567588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
51669995Sdes	PS_ADD("vsize",		"%u",	kp.ki_size);
51769995Sdes	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
51867588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
51969995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
52067588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
52167588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
52269799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
52369799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
52467588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
52567588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
52667588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
52767588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
52867588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
52969799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
53069799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
53169799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
53269799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
53367588Sdes#undef PS_ADD
53478025Sdes	sbuf_putc(sb, '\n');
53567588Sdes
53678025Sdes	return (0);
53767588Sdes}
53867588Sdes
53967588Sdes/*
54067588Sdes * Map process state to descriptive letter. Note that this does not
54167588Sdes * quite correspond to what Linux outputs, but it's close enough.
54267588Sdes */
54367588Sdesstatic char *state_str[] = {
54467588Sdes	"? (unknown)",
54567588Sdes	"I (idle)",
54667588Sdes	"R (running)",
54767588Sdes	"S (sleeping)",
54867588Sdes	"T (stopped)",
54967588Sdes	"Z (zombie)",
55067588Sdes	"W (waiting)",
55167588Sdes	"M (mutex)"
55267588Sdes};
55367588Sdes
55478113Sdes/*
55578113Sdes * Filler function for proc/pid/status
55678113Sdes */
55778025Sdesstatic int
55878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
55967588Sdes{
56069995Sdes	struct kinfo_proc kp;
56167588Sdes	char *state;
56269799Sdes	segsz_t lsize;
56374135Sjlemon	int i;
56467588Sdes
56572200Sbmilekic	mtx_lock_spin(&sched_lock);
56667588Sdes	if (p->p_stat > sizeof state_str / sizeof *state_str)
56767588Sdes		state = state_str[0];
56867588Sdes	else
56967588Sdes		state = state_str[(int)p->p_stat];
57072200Sbmilekic	mtx_unlock_spin(&sched_lock);
57167588Sdes
57269995Sdes	fill_kinfo_proc(p, &kp);
57378025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
57478031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
57567588Sdes
57667588Sdes	/*
57767588Sdes	 * Credentials
57867588Sdes	 */
57978025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
58071471Sjhb	PROC_LOCK(p);
58178025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
58273923Sjhb						p->p_pptr->p_pid : 0);
58378031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
58478031Sdes						p->p_ucred->cr_uid,
58578031Sdes						p->p_ucred->cr_svuid,
58678031Sdes						/* FreeBSD doesn't have fsuid */
58778031Sdes						p->p_ucred->cr_uid);
58878031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
58978031Sdes						p->p_ucred->cr_gid,
59078031Sdes						p->p_ucred->cr_svgid,
59178031Sdes						/* FreeBSD doesn't have fsgid */
59278031Sdes						p->p_ucred->cr_gid);
59378025Sdes	sbuf_cat(sb, "Groups:\t");
59467588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
59578031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
59671471Sjhb	PROC_UNLOCK(p);
59778025Sdes	sbuf_putc(sb, '\n');
59867588Sdes
59967588Sdes	/*
60067588Sdes	 * Memory
60169799Sdes	 *
60269799Sdes	 * While our approximation of VmLib may not be accurate (I
60369799Sdes	 * don't know of a simple way to verify it, and I'm not sure
60469799Sdes	 * it has much meaning anyway), I believe it's good enough.
60569799Sdes	 *
60669799Sdes	 * The same code that could (I think) accurately compute VmLib
60769799Sdes	 * could also compute VmLck, but I don't really care enough to
60869799Sdes	 * implement it. Submissions are welcome.
60967588Sdes	 */
61078025Sdes	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
61178025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
61278025Sdes	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
61378025Sdes	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
61478025Sdes	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
61578025Sdes	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
61669995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
61769995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
61878025Sdes	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
61967588Sdes
62067588Sdes	/*
62167588Sdes	 * Signal masks
62267588Sdes	 *
62367588Sdes	 * We support up to 128 signals, while Linux supports 32,
62467588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
62567588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
62667588Sdes	 *
62767588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
62867588Sdes	 * supports 64 signals, but this code is a long way from
62967588Sdes	 * running on anything but i386, so ignore that for now.
63067588Sdes	 */
63171471Sjhb	PROC_LOCK(p);
63278025Sdes	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
63369799Sdes	/*
63469799Sdes	 * I can't seem to find out where the signal mask is in
63569799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
63669799Sdes	 */
63778025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
63878025Sdes	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
63978025Sdes	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
64071471Sjhb	PROC_UNLOCK(p);
64167588Sdes
64267588Sdes	/*
64367588Sdes	 * Linux also prints the capability masks, but we don't have
64467588Sdes	 * capabilities yet, and when we do get them they're likely to
64567588Sdes	 * be meaningless to Linux programs, so we lie. XXX
64667588Sdes	 */
64778025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
64878025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
64978025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
65078025Sdes
65178025Sdes	return (0);
65267588Sdes}
65374135Sjlemon
65478113Sdes/*
65578113Sdes * Filler function for proc/pid/cmdline
65678113Sdes */
65778025Sdesstatic int
65878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
65978113Sdes{
66078113Sdes	struct ps_strings pstr;
66178113Sdes	int error, i;
66278113Sdes
66378113Sdes	/*
66478113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
66578113Sdes	 * revert back to the old way which only implements full cmdline
66678113Sdes	 * for the currept process and just p->p_comm for all other
66778113Sdes	 * processes.
66878113Sdes	 * Note that if the argv is no longer available, we deliberately
66978113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
67078113Sdes	 * Linux behaviour is to return zero-length in this case.
67178113Sdes	 */
67278113Sdes
67383366Sjulian	if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) {
67478113Sdes		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
67583366Sjulian	} else if (p != td->td_proc) {
67678113Sdes		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
67778113Sdes	} else {
67878113Sdes		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
67978113Sdes		if (error)
68078113Sdes			return (error);
68178113Sdes		for (i = 0; i < pstr.ps_nargvstr; i++) {
68278113Sdes			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
68378113Sdes			sbuf_printf(sb, "%c", '\0');
68478113Sdes		}
68578113Sdes	}
68678113Sdes
68778113Sdes	return (0);
68878113Sdes}
68978113Sdes
69078113Sdes/*
69178113Sdes * Filler function for proc/net/dev
69278113Sdes */
69378025Sdesstatic int
69478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
69574135Sjlemon{
69685129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
69774135Sjlemon	struct ifnet *ifp;
69874135Sjlemon
69985129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
70083926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
70185129Sdes	    "bytes    packets errs drop fifo frame compressed",
70283926Sdes	    "bytes    packets errs drop fifo frame compressed");
70374135Sjlemon
70474135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
70585129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
70685129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
70783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
70883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
70983926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
71083926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
71174135Sjlemon	}
71278025Sdes
71378025Sdes	return (0);
71474135Sjlemon}
71574135Sjlemon
71685538Sphk#if 0
71785538Sphkextern struct cdevsw *cdevsw[];
71885538Sphk
71978113Sdes/*
72078113Sdes * Filler function for proc/devices
72178113Sdes */
72278025Sdesstatic int
72378025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
72474135Sjlemon{
72574135Sjlemon	int i;
72674135Sjlemon
72778025Sdes	sbuf_printf(sb, "Character devices:\n");
72874135Sjlemon
72978025Sdes	for (i = 0; i < NUMCDEVSW; i++)
73074135Sjlemon		if (cdevsw[i] != NULL)
73178025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
73274135Sjlemon
73378025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
73478025Sdes
73578025Sdes	return (0);
73674135Sjlemon}
73785538Sphk#endif
73874135Sjlemon
73978113Sdes/*
74078113Sdes * Filler function for proc/cmdline
74178113Sdes */
74278025Sdesstatic int
74378025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
74474135Sjlemon{
74578025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
74678025Sdes	sbuf_printf(sb, " ro root=302\n");
74778025Sdes	return (0);
74878025Sdes}
74974135Sjlemon
75083926Sdes#if 0
75178025Sdes/*
75283926Sdes * Filler function for proc/modules
75383926Sdes */
75483926Sdesstatic int
75583926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
75683926Sdes{
75783926Sdes	struct linker_file *lf;
75883926Sdes
75983926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
76083926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
76183926Sdes		    (unsigned long)lf->size, lf->refs);
76283926Sdes	}
76383926Sdes	return (0);
76483926Sdes}
76583926Sdes#endif
76683926Sdes
76783926Sdes/*
76885129Sdes * Constructor
76978025Sdes */
77085129Sdesstatic int
77185129Sdeslinprocfs_init(PFS_INIT_ARGS)
77285129Sdes{
77385129Sdes	struct pfs_node *root;
77485129Sdes	struct pfs_node *dir;
77574135Sjlemon
77685129Sdes	root = pi->pi_root;
77778025Sdes
77885129Sdes#define PFS_CREATE_FILE(name) \
77985129Sdes	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
78085129Sdes	PFS_CREATE_FILE(cmdline);
78185129Sdes	PFS_CREATE_FILE(cpuinfo);
78285538Sphk#if 0
78385129Sdes	PFS_CREATE_FILE(devices);
78485538Sphk#endif
78585129Sdes	PFS_CREATE_FILE(loadavg);
78685129Sdes	PFS_CREATE_FILE(meminfo);
78783926Sdes#if 0
78885129Sdes	PFS_CREATE_FILE(modules);
78983926Sdes#endif
79085289Sdes	PFS_CREATE_FILE(mtab);
79185129Sdes	PFS_CREATE_FILE(stat);
79285129Sdes	PFS_CREATE_FILE(uptime);
79385129Sdes	PFS_CREATE_FILE(version);
79485129Sdes#undef PFS_CREATE_FILE
79587543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
79685129Sdes	    NULL, NULL, 0);
79778025Sdes
79885129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
79985129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
80085129Sdes	    NULL, NULL, PFS_RD);
80178025Sdes
80285129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
80385129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
80485129Sdes	    NULL, NULL, PFS_RD);
80587543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
80687543Sdes	    NULL, &procfs_notsystem, 0);
80785129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
80885129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
80985129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
81085129Sdes	    NULL, NULL, PFS_RD);
81185129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
81285129Sdes	    NULL, NULL, PFS_RD);
81385129Sdes
81485129Sdes	return (0);
81585129Sdes}
81685129Sdes
81785129Sdes/*
81885129Sdes * Destructor
81985129Sdes */
82085129Sdesstatic int
82185129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
82285129Sdes{
82385129Sdes
82485129Sdes	/* nothing to do, pseudofs will GC */
82585129Sdes	return (0);
82685129Sdes}
82785129Sdes
82885129SdesPSEUDOFS(linprocfs, 1);
82978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
83078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
831