linprocfs.c revision 116173
159412Smsmith/*
265577Sdes * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
365577Sdes * Copyright (c) 1999 Pierre Beyssac
459412Smsmith * Copyright (c) 1993 Jan-Simon Pendry
559412Smsmith * Copyright (c) 1993
659412Smsmith *	The Regents of the University of California.  All rights reserved.
759412Smsmith *
859412Smsmith * This code is derived from software contributed to Berkeley by
959412Smsmith * Jan-Simon Pendry.
1059412Smsmith *
1159412Smsmith * Redistribution and use in source and binary forms, with or without
1259412Smsmith * modification, are permitted provided that the following conditions
1359412Smsmith * are met:
1459412Smsmith * 1. Redistributions of source code must retain the above copyright
1559412Smsmith *    notice, this list of conditions and the following disclaimer.
1659412Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1759412Smsmith *    notice, this list of conditions and the following disclaimer in the
1859412Smsmith *    documentation and/or other materials provided with the distribution.
1959412Smsmith * 3. All advertising materials mentioning features or use of this software
2059412Smsmith *    must display the following acknowledgement:
2159412Smsmith *	This product includes software developed by the University of
2259412Smsmith *	California, Berkeley and its contributors.
2359412Smsmith * 4. Neither the name of the University nor the names of its contributors
2459412Smsmith *    may be used to endorse or promote products derived from this software
2559412Smsmith *    without specific prior written permission.
2659412Smsmith *
2759412Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2859412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2959412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3059412Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3159412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3259412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3359412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3459412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3559412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3659412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3759412Smsmith * SUCH DAMAGE.
3859412Smsmith *
3959412Smsmith *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
4059412Smsmith */
4159412Smsmith
42116173Sobrien#include <sys/cdefs.h>
43116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 116173 2003-06-10 21:29:12Z obrien $");
44116173Sobrien
4559412Smsmith#include <sys/param.h>
4683926Sdes#include <sys/queue.h>
4776166Smarkm#include <sys/blist.h>
4874135Sjlemon#include <sys/conf.h>
4983926Sdes#include <sys/exec.h>
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>
7659412Smsmith#include <vm/swap_pager.h>
7769799Sdes
7867589Sdes#include <machine/clock.h>
7978113Sdes
8078113Sdes#ifdef __alpha__
8178113Sdes#include <machine/alpha_cpu.h>
8278113Sdes#include <machine/cpuconf.h>
8378113Sdes#include <machine/rpb.h>
8478113Sdesextern int ncpus;
8578113Sdes#endif /* __alpha__ */
8678113Sdes
8778113Sdes#ifdef __i386__
8867589Sdes#include <machine/cputypes.h>
8959412Smsmith#include <machine/md_var.h>
9078113Sdes#endif /* __i386__ */
9159412Smsmith
9287275Srwatson#include <machine/../linux/linux.h>
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 ??? */
120113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
121113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
122113574Sjhb	unsigned long long 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"
213113574Sjhb	    "cpu revision\t\t: %d\n"
21478113Sdes	    "cpu serial number\t: %s\n"
21578113Sdes	    "system type\t\t: %s\n"
21678113Sdes	    "system variation\t: %s\n"
217113574Sjhb	    "system revision\t\t: %d\n"
21878113Sdes	    "system serial number\t: %s\n"
21978113Sdes	    "cycle frequency [Hz]\t: %lu\n"
220113574Sjhb	    "timer frequency [Hz]\t: %u\n"
22178113Sdes	    "page size [bytes]\t: %ld\n"
22278113Sdes	    "phys. address bits\t: %ld\n"
22378113Sdes	    "max. addr. space #\t: %ld\n"
224113574Sjhb	    "BogoMIPS\t\t: %u.%02u\n"
225113574Sjhb	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
226113574Sjhb	    "user unaligned acc\t: %d (pc=%x,va=%x)\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;
34191334Sjulian	const char *lep;
34291334Sjulian	char *dlep, *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;
34991334Sjulian	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
35085289Sdes		lep = linux_emul_path;
35191334Sjulian	else
35291334Sjulian		lep = dlep;
35385289Sdes	lep_len = strlen(lep);
35485289Sdes
35585289Sdes	mtx_lock(&mountlist_mtx);
35685289Sdes	error = 0;
35785289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
35885289Sdes		error = VFS_STATFS(mp, &mp->mnt_stat, td);
35985289Sdes		if (error)
36085289Sdes			break;
36185289Sdes
36285289Sdes		/* determine device name */
36385289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
36485289Sdes
36585289Sdes		/* determine mount point */
36685289Sdes		mntto = mp->mnt_stat.f_mntonname;
36785289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
36885289Sdes		    mntto[lep_len] == '/')
36985289Sdes			mntto += lep_len;
37085289Sdes
37185289Sdes		/* determine fs type */
37285289Sdes		fstype = mp->mnt_stat.f_fstypename;
37385289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
37485289Sdes			mntfrom = fstype = "proc";
37585289Sdes		else if (strcmp(fstype, "procfs") == 0)
37685289Sdes			continue;
37785289Sdes
37885289Sdes		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
37985289Sdes		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
38085289Sdes#define ADD_OPTION(opt, name) \
38185289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
38285289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
38385289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
38485289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
38585289Sdes		ADD_OPTION(MNT_NODEV,		"nodev");
38685289Sdes		ADD_OPTION(MNT_UNION,		"union");
38785289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
38885289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
38985289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
39085289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
39185289Sdes#undef ADD_OPTION
39285289Sdes		/* a real Linux mtab will also show NFS options */
39385289Sdes		sbuf_printf(sb, " 0 0\n");
39485289Sdes	}
39585289Sdes	mtx_unlock(&mountlist_mtx);
39685289Sdes	if (flep != NULL)
39785289Sdes		free(flep, M_TEMP);
39885289Sdes	return (error);
39985289Sdes}
40085289Sdes
40185289Sdes/*
40278113Sdes * Filler function for proc/stat
40378113Sdes */
40478025Sdesstatic int
40578025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
40665633Sdes{
40778025Sdes	sbuf_printf(sb,
40869799Sdes	    "cpu %ld %ld %ld %ld\n"
40969799Sdes	    "disk 0 0 0 0\n"
41069799Sdes	    "page %u %u\n"
41169799Sdes	    "swap %u %u\n"
41269799Sdes	    "intr %u\n"
41369799Sdes	    "ctxt %u\n"
41485657Sdillon	    "btime %lld\n",
41569799Sdes	    T2J(cp_time[CP_USER]),
41669799Sdes	    T2J(cp_time[CP_NICE]),
41769799Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
41869799Sdes	    T2J(cp_time[CP_IDLE]),
41969799Sdes	    cnt.v_vnodepgsin,
42069799Sdes	    cnt.v_vnodepgsout,
42169799Sdes	    cnt.v_swappgsin,
42269799Sdes	    cnt.v_swappgsout,
42369799Sdes	    cnt.v_intr,
42469799Sdes	    cnt.v_swtch,
425113574Sjhb	    (long long)boottime.tv_sec);
42678025Sdes	return (0);
42765633Sdes}
42865633Sdes
42978113Sdes/*
43078113Sdes * Filler function for proc/uptime
43178113Sdes */
43278025Sdesstatic int
43378025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
43465633Sdes{
43565633Sdes	struct timeval tv;
43665633Sdes
43765633Sdes	getmicrouptime(&tv);
43885657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
439113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
44069799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
44178025Sdes	return (0);
44265633Sdes}
44365633Sdes
44478113Sdes/*
44578113Sdes * Filler function for proc/version
44678113Sdes */
44778025Sdesstatic int
44878025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
44965633Sdes{
45087275Srwatson	char osname[LINUX_MAX_UTSNAME];
45187275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
45287275Srwatson
453112206Sjhb	linux_get_osname(td, osname);
454112206Sjhb	linux_get_osrelease(td, osrelease);
45587275Srwatson
45678025Sdes	sbuf_printf(sb,
45769995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
45887275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
45978025Sdes	return (0);
46065633Sdes}
46165633Sdes
46278113Sdes/*
46378113Sdes * Filler function for proc/loadavg
46478113Sdes */
46578025Sdesstatic int
46678025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
46776839Sjlemon{
46878025Sdes	sbuf_printf(sb,
46976839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
47076839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
47176839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
47276839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
47376839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
47476839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
47576839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
47676839Sjlemon	    1,				/* number of running tasks */
47776839Sjlemon	    nprocs,			/* number of tasks */
47878116Sdes	    lastpid			/* the last pid */
47976839Sjlemon	);
48078025Sdes
48178025Sdes	return (0);
48276839Sjlemon}
48376839Sjlemon
48478113Sdes/*
48578113Sdes * Filler function for proc/pid/stat
48678113Sdes */
48778025Sdesstatic int
48878025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
48967588Sdes{
49069995Sdes	struct kinfo_proc kp;
49167588Sdes
49294307Sjhb	PROC_LOCK(p);
49369995Sdes	fill_kinfo_proc(p, &kp);
49478025Sdes	sbuf_printf(sb, "%d", p->p_pid);
49578025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
49667588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
49767588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
49873923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
49967588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
50067588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
50191140Stanimura	PROC_UNLOCK(p);
50267588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
50367588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
50467588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
50567588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
50667588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50767588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
50867588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
50967588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
51067588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
51167588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
51267588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
51367588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
51467588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
51567588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
51667588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
51767588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
518113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
519113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
52067588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
52169995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
52267588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
52367588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
52469799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
52569799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
52667588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
52767588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
52867588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
52967588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
53067588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
53169799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
53269799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
53369799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
53469799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
53567588Sdes#undef PS_ADD
53678025Sdes	sbuf_putc(sb, '\n');
53767588Sdes
53878025Sdes	return (0);
53967588Sdes}
54067588Sdes
54167588Sdes/*
54278113Sdes * Filler function for proc/pid/status
54378113Sdes */
54478025Sdesstatic int
54578025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
54667588Sdes{
54769995Sdes	struct kinfo_proc kp;
54867588Sdes	char *state;
54969799Sdes	segsz_t lsize;
55099072Sjulian	struct thread *td2;
551114983Sjhb	struct sigacts *ps;
55274135Sjlemon	int i;
55367588Sdes
554113611Sjhb	PROC_LOCK(p);
55599072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
55699072Sjulian
55799072Sjulian	if (P_SHOULDSTOP(p)) {
55899072Sjulian		state = "T (stopped)";
55999072Sjulian	} else {
560113611Sjhb		mtx_lock_spin(&sched_lock);
56199072Sjulian		switch(p->p_state) {
56299072Sjulian		case PRS_NEW:
56399072Sjulian			state = "I (idle)";
56499072Sjulian			break;
56599072Sjulian		case PRS_NORMAL:
56699072Sjulian			if (p->p_flag & P_WEXIT) {
56799072Sjulian				state = "X (exiting)";
56899072Sjulian				break;
56999072Sjulian			}
57099072Sjulian			switch(td2->td_state) {
571103216Sjulian			case TDS_INHIBITED:
57299072Sjulian				state = "S (sleeping)";
57399072Sjulian				break;
57499072Sjulian			case TDS_RUNQ:
57599072Sjulian			case TDS_RUNNING:
57699072Sjulian				state = "R (running)";
57799072Sjulian				break;
57899072Sjulian			default:
57999072Sjulian				state = "? (unknown)";
58099072Sjulian				break;
58199072Sjulian			}
58299072Sjulian			break;
58399072Sjulian		case PRS_ZOMBIE:
58499072Sjulian			state = "Z (zombie)";
58599072Sjulian			break;
58699072Sjulian		default:
58799072Sjulian			state = "? (unknown)";
58899072Sjulian			break;
58999072Sjulian		}
590113611Sjhb		mtx_unlock_spin(&sched_lock);
59199072Sjulian	}
59267588Sdes
59369995Sdes	fill_kinfo_proc(p, &kp);
59478025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
59578031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
59667588Sdes
59767588Sdes	/*
59867588Sdes	 * Credentials
59967588Sdes	 */
60078025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
60178025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
60273923Sjhb						p->p_pptr->p_pid : 0);
60378031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
60478031Sdes						p->p_ucred->cr_uid,
60578031Sdes						p->p_ucred->cr_svuid,
60678031Sdes						/* FreeBSD doesn't have fsuid */
60778031Sdes						p->p_ucred->cr_uid);
60878031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
60978031Sdes						p->p_ucred->cr_gid,
61078031Sdes						p->p_ucred->cr_svgid,
61178031Sdes						/* FreeBSD doesn't have fsgid */
61278031Sdes						p->p_ucred->cr_gid);
61378025Sdes	sbuf_cat(sb, "Groups:\t");
61467588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
61578031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
61671471Sjhb	PROC_UNLOCK(p);
61778025Sdes	sbuf_putc(sb, '\n');
61867588Sdes
61967588Sdes	/*
62067588Sdes	 * Memory
62169799Sdes	 *
62269799Sdes	 * While our approximation of VmLib may not be accurate (I
62369799Sdes	 * don't know of a simple way to verify it, and I'm not sure
62469799Sdes	 * it has much meaning anyway), I believe it's good enough.
62569799Sdes	 *
62669799Sdes	 * The same code that could (I think) accurately compute VmLib
62769799Sdes	 * could also compute VmLck, but I don't really care enough to
62869799Sdes	 * implement it. Submissions are welcome.
62967588Sdes	 */
630113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
63178025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
632113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
633113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
634113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
635113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
63669995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
63769995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
638113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
63967588Sdes
64067588Sdes	/*
64167588Sdes	 * Signal masks
64267588Sdes	 *
64367588Sdes	 * We support up to 128 signals, while Linux supports 32,
64467588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
64567588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
64667588Sdes	 *
64767588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
64867588Sdes	 * supports 64 signals, but this code is a long way from
64967588Sdes	 * running on anything but i386, so ignore that for now.
65067588Sdes	 */
65171471Sjhb	PROC_LOCK(p);
652104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
65369799Sdes	/*
65469799Sdes	 * I can't seem to find out where the signal mask is in
65569799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
65669799Sdes	 */
65778025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
658114983Sjhb	ps = p->p_sigacts;
659114983Sjhb	mtx_lock(&ps->ps_mtx);
660114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
661114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
662114983Sjhb	mtx_unlock(&ps->ps_mtx);
66371471Sjhb	PROC_UNLOCK(p);
66467588Sdes
66567588Sdes	/*
66667588Sdes	 * Linux also prints the capability masks, but we don't have
66767588Sdes	 * capabilities yet, and when we do get them they're likely to
66867588Sdes	 * be meaningless to Linux programs, so we lie. XXX
66967588Sdes	 */
67078025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
67178025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
67278025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
67378025Sdes
67478025Sdes	return (0);
67567588Sdes}
67674135Sjlemon
67778113Sdes/*
67878113Sdes * Filler function for proc/pid/cmdline
67978113Sdes */
68078025Sdesstatic int
68178113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
68278113Sdes{
68378113Sdes	struct ps_strings pstr;
68478113Sdes	int error, i;
68578113Sdes
68678113Sdes	/*
68778113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
68878113Sdes	 * revert back to the old way which only implements full cmdline
68978113Sdes	 * for the currept process and just p->p_comm for all other
69078113Sdes	 * processes.
69178113Sdes	 * Note that if the argv is no longer available, we deliberately
69278113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
69378113Sdes	 * Linux behaviour is to return zero-length in this case.
69478113Sdes	 */
69578113Sdes
69694620Sjhb	PROC_LOCK(p);
69796886Sjhb	if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
69894620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
69994620Sjhb		PROC_UNLOCK(p);
70094620Sjhb	} else if (p != td->td_proc) {
70194620Sjhb		PROC_UNLOCK(p);
70294620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
70394620Sjhb	} else {
70494620Sjhb		PROC_UNLOCK(p);
705103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
706103767Sjake		    sizeof(pstr));
70794620Sjhb		if (error)
70894620Sjhb			return (error);
70994620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
71094620Sjhb			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
71194620Sjhb			sbuf_printf(sb, "%c", '\0');
71278113Sdes		}
71378113Sdes	}
71478113Sdes
71578113Sdes	return (0);
71678113Sdes}
71778113Sdes
71878113Sdes/*
719116173Sobrien * Filler function for proc/pid/environ
720116173Sobrien */
721116173Sobrienstatic int
722116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
723116173Sobrien{
724116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
725116173Sobrien
726116173Sobrien	return (0);
727116173Sobrien}
728116173Sobrien
729116173Sobrien/*
730116173Sobrien * Filler function for proc/pid/maps
731116173Sobrien */
732116173Sobrienstatic int
733116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
734116173Sobrien{
735116173Sobrien	sbuf_printf(sb, "doprocmaps\n%c", '\0');
736116173Sobrien
737116173Sobrien	return (0);
738116173Sobrien}
739116173Sobrien
740116173Sobrien/*
74178113Sdes * Filler function for proc/net/dev
74278113Sdes */
74378025Sdesstatic int
74478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
74574135Sjlemon{
74685129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
74774135Sjlemon	struct ifnet *ifp;
74874135Sjlemon
74985129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
75083926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
75185129Sdes	    "bytes    packets errs drop fifo frame compressed",
75283926Sdes	    "bytes    packets errs drop fifo frame compressed");
75374135Sjlemon
754108172Shsu	IFNET_RLOCK();
75574135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
75685129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
75785129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
75883926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
75983926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
76083926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
76183926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
76274135Sjlemon	}
763108172Shsu	IFNET_RUNLOCK();
76478025Sdes
76578025Sdes	return (0);
76674135Sjlemon}
76774135Sjlemon
76885538Sphk#if 0
76985538Sphkextern struct cdevsw *cdevsw[];
77085538Sphk
77178113Sdes/*
77278113Sdes * Filler function for proc/devices
77378113Sdes */
77478025Sdesstatic int
77578025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
77674135Sjlemon{
77774135Sjlemon	int i;
77874135Sjlemon
77978025Sdes	sbuf_printf(sb, "Character devices:\n");
78074135Sjlemon
78178025Sdes	for (i = 0; i < NUMCDEVSW; i++)
78274135Sjlemon		if (cdevsw[i] != NULL)
78378025Sdes			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
78474135Sjlemon
78578025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
78678025Sdes
78778025Sdes	return (0);
78874135Sjlemon}
78985538Sphk#endif
79074135Sjlemon
79178113Sdes/*
79278113Sdes * Filler function for proc/cmdline
79378113Sdes */
79478025Sdesstatic int
79578025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
79674135Sjlemon{
79778025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
79878025Sdes	sbuf_printf(sb, " ro root=302\n");
79978025Sdes	return (0);
80078025Sdes}
80174135Sjlemon
80283926Sdes#if 0
80378025Sdes/*
80483926Sdes * Filler function for proc/modules
80583926Sdes */
80683926Sdesstatic int
80783926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
80883926Sdes{
80983926Sdes	struct linker_file *lf;
81083926Sdes
81183926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
81283926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
81383926Sdes		    (unsigned long)lf->size, lf->refs);
81483926Sdes	}
81583926Sdes	return (0);
81683926Sdes}
81783926Sdes#endif
81883926Sdes
81983926Sdes/*
82085129Sdes * Constructor
82178025Sdes */
82285129Sdesstatic int
82385129Sdeslinprocfs_init(PFS_INIT_ARGS)
82485129Sdes{
82585129Sdes	struct pfs_node *root;
82685129Sdes	struct pfs_node *dir;
82774135Sjlemon
82885129Sdes	root = pi->pi_root;
82978025Sdes
83085129Sdes#define PFS_CREATE_FILE(name) \
83185129Sdes	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
83285129Sdes	PFS_CREATE_FILE(cmdline);
83385129Sdes	PFS_CREATE_FILE(cpuinfo);
83485538Sphk#if 0
83585129Sdes	PFS_CREATE_FILE(devices);
83685538Sphk#endif
83785129Sdes	PFS_CREATE_FILE(loadavg);
83885129Sdes	PFS_CREATE_FILE(meminfo);
83983926Sdes#if 0
84085129Sdes	PFS_CREATE_FILE(modules);
84183926Sdes#endif
84285289Sdes	PFS_CREATE_FILE(mtab);
84385129Sdes	PFS_CREATE_FILE(stat);
84485129Sdes	PFS_CREATE_FILE(uptime);
84585129Sdes	PFS_CREATE_FILE(version);
84685129Sdes#undef PFS_CREATE_FILE
84787543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
84885129Sdes	    NULL, NULL, 0);
84978025Sdes
85085129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
85185129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
85285129Sdes	    NULL, NULL, PFS_RD);
85378025Sdes
85485129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
85585129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
85685129Sdes	    NULL, NULL, PFS_RD);
857116173Sobrien
858116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
859116173Sobrien	    NULL, NULL, PFS_RD);
860116173Sobrien
86187543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
86287543Sdes	    NULL, &procfs_notsystem, 0);
863116173Sobrien
864116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
865116173Sobrien	    NULL, NULL, PFS_RD);
866116173Sobrien
86785129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
86885129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
86985129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
87085129Sdes	    NULL, NULL, PFS_RD);
87185129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
87285129Sdes	    NULL, NULL, PFS_RD);
87385129Sdes
87485129Sdes	return (0);
87585129Sdes}
87685129Sdes
87785129Sdes/*
87885129Sdes * Destructor
87985129Sdes */
88085129Sdesstatic int
88185129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
88285129Sdes{
88385129Sdes
88485129Sdes	/* nothing to do, pseudofs will GC */
88585129Sdes	return (0);
88685129Sdes}
88785129Sdes
88885129SdesPSEUDOFS(linprocfs, 1);
88978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
89078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
891