linprocfs.c revision 114983
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 114983 2003-05-13 20:36:02Z jhb $
4259412Smsmith */
4359412Smsmith
4459412Smsmith#include <sys/param.h>
4583926Sdes#include <sys/queue.h>
4676166Smarkm#include <sys/blist.h>
4774135Sjlemon#include <sys/conf.h>
4883926Sdes#include <sys/exec.h>
4976166Smarkm#include <sys/jail.h>
5065633Sdes#include <sys/kernel.h>
5183926Sdes#include <sys/linker.h>
5276166Smarkm#include <sys/lock.h>
5374135Sjlemon#include <sys/malloc.h>
5478025Sdes#include <sys/mount.h>
5576827Salfred#include <sys/mutex.h>
5685289Sdes#include <sys/namei.h>
5765633Sdes#include <sys/proc.h>
5865633Sdes#include <sys/resourcevar.h>
5969995Sdes#include <sys/sbuf.h>
6083926Sdes#include <sys/socket.h>
6176839Sjlemon#include <sys/sysctl.h>
6283926Sdes#include <sys/systm.h>
6365633Sdes#include <sys/tty.h>
6483926Sdes#include <sys/user.h>
6583926Sdes#include <sys/vmmeter.h>
6659412Smsmith#include <sys/vnode.h>
6759412Smsmith
6883926Sdes#include <net/if.h>
6983926Sdes
7059412Smsmith#include <vm/vm.h>
7159412Smsmith#include <vm/pmap.h>
7267588Sdes#include <vm/vm_map.h>
7359412Smsmith#include <vm/vm_param.h>
7460860Sdes#include <vm/vm_object.h>
7559412Smsmith#include <vm/swap_pager.h>
7669799Sdes
7767589Sdes#include <machine/clock.h>
7878113Sdes
7978113Sdes#ifdef __alpha__
8078113Sdes#include <machine/alpha_cpu.h>
8178113Sdes#include <machine/cpuconf.h>
8278113Sdes#include <machine/rpb.h>
8378113Sdesextern int ncpus;
8478113Sdes#endif /* __alpha__ */
8578113Sdes
8678113Sdes#ifdef __i386__
8767589Sdes#include <machine/cputypes.h>
8859412Smsmith#include <machine/md_var.h>
8978113Sdes#endif /* __i386__ */
9059412Smsmith
9187275Srwatson#include <machine/../linux/linux.h>
9285129Sdes#include <compat/linux/linux_ioctl.h>
9369995Sdes#include <compat/linux/linux_mib.h>
9485289Sdes#include <compat/linux/linux_util.h>
9578025Sdes#include <fs/pseudofs/pseudofs.h>
9684248Sdes#include <fs/procfs/procfs.h>
9759412Smsmith
9867588Sdes/*
9967588Sdes * Various conversion macros
10067588Sdes */
10176405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10267588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10367588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10469799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10567588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10667588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
10774135Sjlemon
10878113Sdes/*
10978113Sdes * Filler function for proc/meminfo
11078113Sdes */
11178025Sdesstatic int
11278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
11359412Smsmith{
11459412Smsmith	unsigned long memtotal;		/* total memory in bytes */
11559412Smsmith	unsigned long memused;		/* used memory in bytes */
11659412Smsmith	unsigned long memfree;		/* free memory in bytes */
11759412Smsmith	unsigned long memshared;	/* shared memory ??? */
11859412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
119113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
120113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
121113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
12260860Sdes	vm_object_t object;
12359412Smsmith
12459412Smsmith	memtotal = physmem * PAGE_SIZE;
12559412Smsmith	/*
12659412Smsmith	 * The correct thing here would be:
12759412Smsmith	 *
12859412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
12959412Smsmith	memused = memtotal - memfree;
13059412Smsmith	 *
13159412Smsmith	 * but it might mislead linux binaries into thinking there
13259412Smsmith	 * is very little memory left, so we cheat and tell them that
13359412Smsmith	 * all memory that isn't wired down is free.
13459412Smsmith	 */
13559412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
13659412Smsmith	memfree = memtotal - memused;
13764560Sbde	if (swapblist == NULL) {
13864560Sbde		swaptotal = 0;
13964560Sbde		swapfree = 0;
14064560Sbde	} else {
14176839Sjlemon		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
14276839Sjlemon		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
14364560Sbde	}
14459412Smsmith	swapused = swaptotal - swapfree;
14560860Sdes	memshared = 0;
14671471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14760860Sdes		if (object->shadow_count > 1)
14860860Sdes			memshared += object->resident_page_count;
14960860Sdes	memshared *= PAGE_SIZE;
15059412Smsmith	/*
15159412Smsmith	 * We'd love to be able to write:
15259412Smsmith	 *
15359412Smsmith	buffers = bufspace;
15459412Smsmith	 *
15559412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
15659412Smsmith	 * like unstaticizing it just for linprocfs's sake.
15759412Smsmith	 */
15859412Smsmith	buffers = 0;
15959412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
16059412Smsmith
16178025Sdes	sbuf_printf(sb,
16278031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
16369799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
16476839Sjlemon	    "Swap: %llu %llu %llu\n"
16569799Sdes	    "MemTotal: %9lu kB\n"
16669799Sdes	    "MemFree:  %9lu kB\n"
16769799Sdes	    "MemShared:%9lu kB\n"
16869799Sdes	    "Buffers:  %9lu kB\n"
16969799Sdes	    "Cached:   %9lu kB\n"
17076839Sjlemon	    "SwapTotal:%9llu kB\n"
17176839Sjlemon	    "SwapFree: %9llu kB\n",
17269799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
17369799Sdes	    swaptotal, swapused, swapfree,
17469799Sdes	    B2K(memtotal), B2K(memfree),
17569799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
17669799Sdes	    B2K(swaptotal), B2K(swapfree));
17759412Smsmith
17878025Sdes	return (0);
17959412Smsmith}
18059412Smsmith
18178113Sdes#ifdef __alpha__
18278113Sdes/*
18378113Sdes * Filler function for proc/cpuinfo (Alpha version)
18478113Sdes */
18578025Sdesstatic int
18678025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
18759412Smsmith{
18878113Sdes	u_int64_t type, major;
18978113Sdes	struct pcs *pcsp;
19078113Sdes	const char *model, *sysname;
19178113Sdes
19278113Sdes	static const char *cpuname[] = {
19378113Sdes		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
19478113Sdes		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
19578113Sdes	};
19678113Sdes
19778113Sdes	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
19878113Sdes	type = pcsp->pcs_proc_type;
19978113Sdes	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
20078113Sdes	if (major < sizeof(cpuname)/sizeof(char *)) {
20178113Sdes		model = cpuname[major - 1];
20278113Sdes	} else {
20378113Sdes		model = "unknown";
20478113Sdes	}
20578113Sdes
20678113Sdes	sysname = alpha_dsr_sysname();
20778113Sdes
20878113Sdes	sbuf_printf(sb,
20978113Sdes	    "cpu\t\t\t: Alpha\n"
21078113Sdes	    "cpu model\t\t: %s\n"
21178113Sdes	    "cpu variation\t\t: %ld\n"
212113574Sjhb	    "cpu revision\t\t: %d\n"
21378113Sdes	    "cpu serial number\t: %s\n"
21478113Sdes	    "system type\t\t: %s\n"
21578113Sdes	    "system variation\t: %s\n"
216113574Sjhb	    "system revision\t\t: %d\n"
21778113Sdes	    "system serial number\t: %s\n"
21878113Sdes	    "cycle frequency [Hz]\t: %lu\n"
219113574Sjhb	    "timer frequency [Hz]\t: %u\n"
22078113Sdes	    "page size [bytes]\t: %ld\n"
22178113Sdes	    "phys. address bits\t: %ld\n"
22278113Sdes	    "max. addr. space #\t: %ld\n"
223113574Sjhb	    "BogoMIPS\t\t: %u.%02u\n"
224113574Sjhb	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
225113574Sjhb	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
22678113Sdes	    "platform string\t\t: %s\n"
22778113Sdes	    "cpus detected\t\t: %d\n"
22878113Sdes	    ,
22978113Sdes	    model,
23078113Sdes	    pcsp->pcs_proc_var,
23178113Sdes	    *(int *)hwrpb->rpb_revision,
23278113Sdes	    " ",
23378113Sdes	    " ",
23478113Sdes	    "0",
23578113Sdes	    0,
23678113Sdes	    " ",
23778113Sdes	    hwrpb->rpb_cc_freq,
23878113Sdes	    hz,
23978113Sdes	    hwrpb->rpb_page_size,
24078113Sdes	    hwrpb->rpb_phys_addr_size,
24178113Sdes	    hwrpb->rpb_max_asn,
24278113Sdes	    0, 0,
24378113Sdes	    0, 0, 0,
24478113Sdes	    0, 0, 0,
24578113Sdes	    sysname,
24678113Sdes	    ncpus);
24778113Sdes	return (0);
24878113Sdes}
24978113Sdes#endif /* __alpha__ */
25078113Sdes
25178113Sdes#ifdef __i386__
25278113Sdes/*
25378113Sdes * Filler function for proc/cpuinfo (i386 version)
25478113Sdes */
25578113Sdesstatic int
25678113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
25778113Sdes{
25869799Sdes	int class, i, fqmhz, fqkhz;
25959412Smsmith
26069799Sdes	/*
26178031Sdes	 * We default the flags to include all non-conflicting flags,
26278031Sdes	 * and the Intel versions of conflicting flags.
26369799Sdes	 */
26478031Sdes	static char *flags[] = {
26578031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
26678031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
26778031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
26878031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
26978031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
27078031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
27167589Sdes		"3dnowext", "3dnow"
27267589Sdes	};
27367589Sdes
27459412Smsmith	switch (cpu_class) {
27559412Smsmith	case CPUCLASS_286:
27667589Sdes		class = 2;
27759412Smsmith		break;
27859412Smsmith	case CPUCLASS_386:
27967589Sdes		class = 3;
28059412Smsmith		break;
28159412Smsmith	case CPUCLASS_486:
28267589Sdes		class = 4;
28359412Smsmith		break;
28459412Smsmith	case CPUCLASS_586:
28567589Sdes		class = 5;
28659412Smsmith		break;
28759412Smsmith	case CPUCLASS_686:
28867589Sdes		class = 6;
28959412Smsmith		break;
29059412Smsmith	default:
29178031Sdes		class = 0;
29259412Smsmith		break;
29359412Smsmith	}
29459412Smsmith
29578025Sdes	sbuf_printf(sb,
29678031Sdes	    "processor\t: %d\n"
29769799Sdes	    "vendor_id\t: %.20s\n"
29869799Sdes	    "cpu family\t: %d\n"
29969799Sdes	    "model\t\t: %d\n"
30069799Sdes	    "stepping\t: %d\n",
30169799Sdes	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
30259412Smsmith
30378031Sdes	sbuf_cat(sb,
30478031Sdes	    "flags\t\t:");
30567589Sdes
30678031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
30767589Sdes		flags[16] = "fcmov";
30878031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
30967589Sdes		flags[24] = "cxmmx";
31078031Sdes	}
31178031Sdes
31278031Sdes	for (i = 0; i < 32; i++)
31367589Sdes		if (cpu_feature & (1 << i))
31478025Sdes			sbuf_printf(sb, " %s", flags[i]);
31578025Sdes	sbuf_cat(sb, "\n");
31678031Sdes	if (class >= 5) {
31769799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
31869799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
31978025Sdes		sbuf_printf(sb,
32069799Sdes		    "cpu MHz\t\t: %d.%02d\n"
32169799Sdes		    "bogomips\t: %d.%02d\n",
32269799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
32378031Sdes	}
32469995Sdes
32578025Sdes	return (0);
32659412Smsmith}
32778113Sdes#endif /* __i386__ */
32865633Sdes
32978113Sdes/*
33085289Sdes * Filler function for proc/mtab
33185289Sdes *
33285289Sdes * This file doesn't exist in Linux' procfs, but is included here so
33385289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
33485289Sdes */
33585289Sdesstatic int
33685289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
33785289Sdes{
33885289Sdes	struct nameidata nd;
33985289Sdes	struct mount *mp;
34091334Sjulian	const char *lep;
34191334Sjulian	char *dlep, *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;
34891334Sjulian	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
34985289Sdes		lep = linux_emul_path;
35091334Sjulian	else
35191334Sjulian		lep = dlep;
35285289Sdes	lep_len = strlen(lep);
35385289Sdes
35485289Sdes	mtx_lock(&mountlist_mtx);
35585289Sdes	error = 0;
35685289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
35785289Sdes		error = VFS_STATFS(mp, &mp->mnt_stat, td);
35885289Sdes		if (error)
35985289Sdes			break;
36085289Sdes
36185289Sdes		/* determine device name */
36285289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
36385289Sdes
36485289Sdes		/* determine mount point */
36585289Sdes		mntto = mp->mnt_stat.f_mntonname;
36685289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
36785289Sdes		    mntto[lep_len] == '/')
36885289Sdes			mntto += lep_len;
36985289Sdes
37085289Sdes		/* determine fs type */
37185289Sdes		fstype = mp->mnt_stat.f_fstypename;
37285289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
37385289Sdes			mntfrom = fstype = "proc";
37485289Sdes		else if (strcmp(fstype, "procfs") == 0)
37585289Sdes			continue;
37685289Sdes
37785289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
37885289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
37985289Sdes#define ADD_OPTION(opt, name) \
38085289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
38185289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
38285289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
38385289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
38485289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
38585289Sdes		ADD_OPTION(MNT_UNION,		"union");
38685289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
38785289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
38885289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
38985289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
39085289Sdes#undef ADD_OPTION
39185289Sdes		/* a real Linux mtab will also show NFS options */
39285289Sdes		sbuf_printf(sb, " 0 0\n");
39385289Sdes	}
39485289Sdes	mtx_unlock(&mountlist_mtx);
39585289Sdes	if (flep != NULL)
39685289Sdes		free(flep, M_TEMP);
39785289Sdes	return (error);
39885289Sdes}
39985289Sdes
40085289Sdes/*
40178113Sdes * Filler function for proc/stat
40278113Sdes */
40378025Sdesstatic int
40478025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
40565633Sdes{
40678025Sdes	sbuf_printf(sb,
40769799Sdes	    "cpu %ld %ld %ld %ld\n"
40869799Sdes	    "disk 0 0 0 0\n"
40969799Sdes	    "page %u %u\n"
41069799Sdes	    "swap %u %u\n"
41169799Sdes	    "intr %u\n"
41269799Sdes	    "ctxt %u\n"
41385657Sdillon	    "btime %lld\n",
41469799Sdes	    T2J(cp_time[CP_USER]),
41569799Sdes	    T2J(cp_time[CP_NICE]),
41669799Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
41769799Sdes	    T2J(cp_time[CP_IDLE]),
41869799Sdes	    cnt.v_vnodepgsin,
41969799Sdes	    cnt.v_vnodepgsout,
42069799Sdes	    cnt.v_swappgsin,
42169799Sdes	    cnt.v_swappgsout,
42269799Sdes	    cnt.v_intr,
42369799Sdes	    cnt.v_swtch,
424113574Sjhb	    (long long)boottime.tv_sec);
42578025Sdes	return (0);
42665633Sdes}
42765633Sdes
42878113Sdes/*
42978113Sdes * Filler function for proc/uptime
43078113Sdes */
43178025Sdesstatic int
43278025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
43365633Sdes{
43465633Sdes	struct timeval tv;
43565633Sdes
43665633Sdes	getmicrouptime(&tv);
43785657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
438113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
43969799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
44078025Sdes	return (0);
44165633Sdes}
44265633Sdes
44378113Sdes/*
44478113Sdes * Filler function for proc/version
44578113Sdes */
44678025Sdesstatic int
44778025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
44865633Sdes{
44987275Srwatson	char osname[LINUX_MAX_UTSNAME];
45087275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
45187275Srwatson
452112206Sjhb	linux_get_osname(td, osname);
453112206Sjhb	linux_get_osrelease(td, osrelease);
45487275Srwatson
45578025Sdes	sbuf_printf(sb,
45669995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
45787275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
45878025Sdes	return (0);
45965633Sdes}
46065633Sdes
46178113Sdes/*
46278113Sdes * Filler function for proc/loadavg
46378113Sdes */
46478025Sdesstatic int
46578025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
46676839Sjlemon{
46778025Sdes	sbuf_printf(sb,
46876839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
46976839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
47076839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
47176839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
47276839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
47376839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
47476839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
47576839Sjlemon	    1,				/* number of running tasks */
47676839Sjlemon	    nprocs,			/* number of tasks */
47778116Sdes	    lastpid			/* the last pid */
47876839Sjlemon	);
47978025Sdes
48078025Sdes	return (0);
48176839Sjlemon}
48276839Sjlemon
48378113Sdes/*
48478113Sdes * Filler function for proc/pid/stat
48578113Sdes */
48678025Sdesstatic int
48778025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
48867588Sdes{
48969995Sdes	struct kinfo_proc kp;
49067588Sdes
49194307Sjhb	PROC_LOCK(p);
49269995Sdes	fill_kinfo_proc(p, &kp);
49378025Sdes	sbuf_printf(sb, "%d", p->p_pid);
49478025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
49567588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
49667588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
49773923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
49867588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
49967588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
50091140Stanimura	PROC_UNLOCK(p);
50167588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
50267588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
50367588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
50467588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
50567588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50667588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
50767588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50867588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
50967588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
51067588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
51167588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
51267588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
51367588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
51467588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
51567588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
51667588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
517113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
518113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
51967588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
52069995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
52167588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
52267588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
52369799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
52469799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
52567588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
52667588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
52767588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
52867588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
52967588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
53069799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
53169799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
53269799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
53369799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
53467588Sdes#undef PS_ADD
53578025Sdes	sbuf_putc(sb, '\n');
53667588Sdes
53778025Sdes	return (0);
53867588Sdes}
53967588Sdes
54067588Sdes/*
54178113Sdes * Filler function for proc/pid/status
54278113Sdes */
54378025Sdesstatic int
54478025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
54567588Sdes{
54669995Sdes	struct kinfo_proc kp;
54767588Sdes	char *state;
54869799Sdes	segsz_t lsize;
54999072Sjulian	struct thread *td2;
550114983Sjhb	struct sigacts *ps;
55174135Sjlemon	int i;
55267588Sdes
553113611Sjhb	PROC_LOCK(p);
55499072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
55599072Sjulian
55699072Sjulian	if (P_SHOULDSTOP(p)) {
55799072Sjulian		state = "T (stopped)";
55899072Sjulian	} else {
559113611Sjhb		mtx_lock_spin(&sched_lock);
56099072Sjulian		switch(p->p_state) {
56199072Sjulian		case PRS_NEW:
56299072Sjulian			state = "I (idle)";
56399072Sjulian			break;
56499072Sjulian		case PRS_NORMAL:
56599072Sjulian			if (p->p_flag & P_WEXIT) {
56699072Sjulian				state = "X (exiting)";
56799072Sjulian				break;
56899072Sjulian			}
56999072Sjulian			switch(td2->td_state) {
570103216Sjulian			case TDS_INHIBITED:
57199072Sjulian				state = "S (sleeping)";
57299072Sjulian				break;
57399072Sjulian			case TDS_RUNQ:
57499072Sjulian			case TDS_RUNNING:
57599072Sjulian				state = "R (running)";
57699072Sjulian				break;
57799072Sjulian			default:
57899072Sjulian				state = "? (unknown)";
57999072Sjulian				break;
58099072Sjulian			}
58199072Sjulian			break;
58299072Sjulian		case PRS_ZOMBIE:
58399072Sjulian			state = "Z (zombie)";
58499072Sjulian			break;
58599072Sjulian		default:
58699072Sjulian			state = "? (unknown)";
58799072Sjulian			break;
58899072Sjulian		}
589113611Sjhb		mtx_unlock_spin(&sched_lock);
59099072Sjulian	}
59167588Sdes
59269995Sdes	fill_kinfo_proc(p, &kp);
59378025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
59478031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
59567588Sdes
59667588Sdes	/*
59767588Sdes	 * Credentials
59867588Sdes	 */
59978025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
60078025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
60173923Sjhb						p->p_pptr->p_pid : 0);
60278031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
60378031Sdes						p->p_ucred->cr_uid,
60478031Sdes						p->p_ucred->cr_svuid,
60578031Sdes						/* FreeBSD doesn't have fsuid */
60678031Sdes						p->p_ucred->cr_uid);
60778031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
60878031Sdes						p->p_ucred->cr_gid,
60978031Sdes						p->p_ucred->cr_svgid,
61078031Sdes						/* FreeBSD doesn't have fsgid */
61178031Sdes						p->p_ucred->cr_gid);
61278025Sdes	sbuf_cat(sb, "Groups:\t");
61367588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
61478031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
61571471Sjhb	PROC_UNLOCK(p);
61678025Sdes	sbuf_putc(sb, '\n');
61767588Sdes
61867588Sdes	/*
61967588Sdes	 * Memory
62069799Sdes	 *
62169799Sdes	 * While our approximation of VmLib may not be accurate (I
62269799Sdes	 * don't know of a simple way to verify it, and I'm not sure
62369799Sdes	 * it has much meaning anyway), I believe it's good enough.
62469799Sdes	 *
62569799Sdes	 * The same code that could (I think) accurately compute VmLib
62669799Sdes	 * could also compute VmLck, but I don't really care enough to
62769799Sdes	 * implement it. Submissions are welcome.
62867588Sdes	 */
629113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
63078025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
631113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
632113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
633113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
634113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
63569995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
63669995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
637113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
63867588Sdes
63967588Sdes	/*
64067588Sdes	 * Signal masks
64167588Sdes	 *
64267588Sdes	 * We support up to 128 signals, while Linux supports 32,
64367588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
64467588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
64567588Sdes	 *
64667588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
64767588Sdes	 * supports 64 signals, but this code is a long way from
64867588Sdes	 * running on anything but i386, so ignore that for now.
64967588Sdes	 */
65071471Sjhb	PROC_LOCK(p);
651104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
65269799Sdes	/*
65369799Sdes	 * I can't seem to find out where the signal mask is in
65469799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
65569799Sdes	 */
65678025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
657114983Sjhb	ps = p->p_sigacts;
658114983Sjhb	mtx_lock(&ps->ps_mtx);
659114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
660114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
661114983Sjhb	mtx_unlock(&ps->ps_mtx);
66271471Sjhb	PROC_UNLOCK(p);
66367588Sdes
66467588Sdes	/*
66567588Sdes	 * Linux also prints the capability masks, but we don't have
66667588Sdes	 * capabilities yet, and when we do get them they're likely to
66767588Sdes	 * be meaningless to Linux programs, so we lie. XXX
66867588Sdes	 */
66978025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
67078025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
67178025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
67278025Sdes
67378025Sdes	return (0);
67467588Sdes}
67574135Sjlemon
67678113Sdes/*
67778113Sdes * Filler function for proc/pid/cmdline
67878113Sdes */
67978025Sdesstatic int
68078113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
68178113Sdes{
68278113Sdes	struct ps_strings pstr;
68378113Sdes	int error, i;
68478113Sdes
68578113Sdes	/*
68678113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
68778113Sdes	 * revert back to the old way which only implements full cmdline
68878113Sdes	 * for the currept process and just p->p_comm for all other
68978113Sdes	 * processes.
69078113Sdes	 * Note that if the argv is no longer available, we deliberately
69178113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
69278113Sdes	 * Linux behaviour is to return zero-length in this case.
69378113Sdes	 */
69478113Sdes
69594620Sjhb	PROC_LOCK(p);
69696886Sjhb	if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
69794620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
69894620Sjhb		PROC_UNLOCK(p);
69994620Sjhb	} else if (p != td->td_proc) {
70094620Sjhb		PROC_UNLOCK(p);
70194620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
70294620Sjhb	} else {
70394620Sjhb		PROC_UNLOCK(p);
704103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
705103767Sjake		    sizeof(pstr));
70694620Sjhb		if (error)
70794620Sjhb			return (error);
70894620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
70994620Sjhb			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
71094620Sjhb			sbuf_printf(sb, "%c", '\0');
71178113Sdes		}
71278113Sdes	}
71378113Sdes
71478113Sdes	return (0);
71578113Sdes}
71678113Sdes
71778113Sdes/*
71878113Sdes * Filler function for proc/net/dev
71978113Sdes */
72078025Sdesstatic int
72178025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
72274135Sjlemon{
72385129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
72474135Sjlemon	struct ifnet *ifp;
72574135Sjlemon
72685129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
72783926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
72885129Sdes	    "bytes    packets errs drop fifo frame compressed",
72983926Sdes	    "bytes    packets errs drop fifo frame compressed");
73074135Sjlemon
731108172Shsu	IFNET_RLOCK();
73274135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
73385129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
73485129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
73583926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
73683926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
73783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
73883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
73974135Sjlemon	}
740108172Shsu	IFNET_RUNLOCK();
74178025Sdes
74278025Sdes	return (0);
74374135Sjlemon}
74474135Sjlemon
74585538Sphk#if 0
74685538Sphkextern struct cdevsw *cdevsw[];
74785538Sphk
74878113Sdes/*
74978113Sdes * Filler function for proc/devices
75078113Sdes */
75178025Sdesstatic int
75278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
75374135Sjlemon{
75474135Sjlemon	int i;
75574135Sjlemon
75678025Sdes	sbuf_printf(sb, "Character devices:\n");
75774135Sjlemon
75878025Sdes	for (i = 0; i < NUMCDEVSW; i++)
75974135Sjlemon		if (cdevsw[i] != NULL)
76078025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
76174135Sjlemon
76278025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
76378025Sdes
76478025Sdes	return (0);
76574135Sjlemon}
76685538Sphk#endif
76774135Sjlemon
76878113Sdes/*
76978113Sdes * Filler function for proc/cmdline
77078113Sdes */
77178025Sdesstatic int
77278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
77374135Sjlemon{
77478025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
77578025Sdes	sbuf_printf(sb, " ro root=302\n");
77678025Sdes	return (0);
77778025Sdes}
77874135Sjlemon
77983926Sdes#if 0
78078025Sdes/*
78183926Sdes * Filler function for proc/modules
78283926Sdes */
78383926Sdesstatic int
78483926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
78583926Sdes{
78683926Sdes	struct linker_file *lf;
78783926Sdes
78883926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
78983926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
79083926Sdes		    (unsigned long)lf->size, lf->refs);
79183926Sdes	}
79283926Sdes	return (0);
79383926Sdes}
79483926Sdes#endif
79583926Sdes
79683926Sdes/*
79785129Sdes * Constructor
79878025Sdes */
79985129Sdesstatic int
80085129Sdeslinprocfs_init(PFS_INIT_ARGS)
80185129Sdes{
80285129Sdes	struct pfs_node *root;
80385129Sdes	struct pfs_node *dir;
80474135Sjlemon
80585129Sdes	root = pi->pi_root;
80678025Sdes
80785129Sdes#define PFS_CREATE_FILE(name) \
80885129Sdes	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
80985129Sdes	PFS_CREATE_FILE(cmdline);
81085129Sdes	PFS_CREATE_FILE(cpuinfo);
81185538Sphk#if 0
81285129Sdes	PFS_CREATE_FILE(devices);
81385538Sphk#endif
81485129Sdes	PFS_CREATE_FILE(loadavg);
81585129Sdes	PFS_CREATE_FILE(meminfo);
81683926Sdes#if 0
81785129Sdes	PFS_CREATE_FILE(modules);
81883926Sdes#endif
81985289Sdes	PFS_CREATE_FILE(mtab);
82085129Sdes	PFS_CREATE_FILE(stat);
82185129Sdes	PFS_CREATE_FILE(uptime);
82285129Sdes	PFS_CREATE_FILE(version);
82385129Sdes#undef PFS_CREATE_FILE
82487543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
82585129Sdes	    NULL, NULL, 0);
82678025Sdes
82785129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
82885129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
82985129Sdes	    NULL, NULL, PFS_RD);
83078025Sdes
83185129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
83285129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
83385129Sdes	    NULL, NULL, PFS_RD);
83487543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
83587543Sdes	    NULL, &procfs_notsystem, 0);
83685129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
83785129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
83885129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
83985129Sdes	    NULL, NULL, PFS_RD);
84085129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
84185129Sdes	    NULL, NULL, PFS_RD);
84285129Sdes
84385129Sdes	return (0);
84485129Sdes}
84585129Sdes
84685129Sdes/*
84785129Sdes * Destructor
84885129Sdes */
84985129Sdesstatic int
85085129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
85185129Sdes{
85285129Sdes
85385129Sdes	/* nothing to do, pseudofs will GC */
85485129Sdes	return (0);
85585129Sdes}
85685129Sdes
85785129SdesPSEUDOFS(linprocfs, 1);
85878025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
85978025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
860