linprocfs.c revision 161094
1139743Simp/*-
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 161094 2006-08-08 12:29:26Z kib $");
44116173Sobrien
4559412Smsmith#include <sys/param.h>
4683926Sdes#include <sys/queue.h>
4776166Smarkm#include <sys/blist.h>
4874135Sjlemon#include <sys/conf.h>
4983926Sdes#include <sys/exec.h>
50119911Sdes#include <sys/filedesc.h>
5176166Smarkm#include <sys/jail.h>
5265633Sdes#include <sys/kernel.h>
5383926Sdes#include <sys/linker.h>
5476166Smarkm#include <sys/lock.h>
5574135Sjlemon#include <sys/malloc.h>
5678025Sdes#include <sys/mount.h>
5776827Salfred#include <sys/mutex.h>
5885289Sdes#include <sys/namei.h>
5965633Sdes#include <sys/proc.h>
6065633Sdes#include <sys/resourcevar.h>
6169995Sdes#include <sys/sbuf.h>
62123246Sdes#include <sys/smp.h>
6383926Sdes#include <sys/socket.h>
6476839Sjlemon#include <sys/sysctl.h>
6583926Sdes#include <sys/systm.h>
66159995Snetchild#include <sys/time.h>
6765633Sdes#include <sys/tty.h>
6883926Sdes#include <sys/user.h>
6983926Sdes#include <sys/vmmeter.h>
7059412Smsmith#include <sys/vnode.h>
7159412Smsmith
7283926Sdes#include <net/if.h>
7383926Sdes
7459412Smsmith#include <vm/vm.h>
7559412Smsmith#include <vm/pmap.h>
7667588Sdes#include <vm/vm_map.h>
7759412Smsmith#include <vm/vm_param.h>
7860860Sdes#include <vm/vm_object.h>
7959412Smsmith#include <vm/swap_pager.h>
8069799Sdes
8167589Sdes#include <machine/clock.h>
8278113Sdes
83133822Stjr#if defined(__i386__) || defined(__amd64__)
8467589Sdes#include <machine/cputypes.h>
8559412Smsmith#include <machine/md_var.h>
86133822Stjr#endif /* __i386__ || __amd64__ */
8759412Smsmith
88133822Stjr#include "opt_compat.h"
89140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
90140214Sobrien#include <machine/../linux32/linux.h>
91140214Sobrien#else
9287275Srwatson#include <machine/../linux/linux.h>
93133822Stjr#endif
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
110159995Snetchild/**
111159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
112159995Snetchild *
113159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
114159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
115159995Snetchild * uninteruptible disk sleep, a zombie process, process is being traced
116159995Snetchild * or stopped, or process is paging respectively.
117159995Snetchild *
118159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
119159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
120159995Snetchild *
121159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
122159995Snetchild * map our states to suitable linux states.
123159995Snetchild */
124159995Snetchildstatic char *linux_state = "RRSTZDD";
125159995Snetchild
12678113Sdes/*
12778113Sdes * Filler function for proc/meminfo
12878113Sdes */
12978025Sdesstatic int
13078025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13159412Smsmith{
13259412Smsmith	unsigned long memtotal;		/* total memory in bytes */
13359412Smsmith	unsigned long memused;		/* used memory in bytes */
13459412Smsmith	unsigned long memfree;		/* free memory in bytes */
13559412Smsmith	unsigned long memshared;	/* shared memory ??? */
13659412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
137113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
138113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
139113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14060860Sdes	vm_object_t object;
141117723Sphk	int i, j;
14259412Smsmith
14359412Smsmith	memtotal = physmem * PAGE_SIZE;
14459412Smsmith	/*
14559412Smsmith	 * The correct thing here would be:
14659412Smsmith	 *
14759412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
14859412Smsmith	memused = memtotal - memfree;
14959412Smsmith	 *
15059412Smsmith	 * but it might mislead linux binaries into thinking there
15159412Smsmith	 * is very little memory left, so we cheat and tell them that
15259412Smsmith	 * all memory that isn't wired down is free.
15359412Smsmith	 */
15459412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
15559412Smsmith	memfree = memtotal - memused;
156117723Sphk	swap_pager_status(&i, &j);
157153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
158153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
159117723Sphk	swapfree = swaptotal - swapused;
16060860Sdes	memshared = 0;
161124082Salc	mtx_lock(&vm_object_list_mtx);
16271471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
16360860Sdes		if (object->shadow_count > 1)
16460860Sdes			memshared += object->resident_page_count;
165124082Salc	mtx_unlock(&vm_object_list_mtx);
16660860Sdes	memshared *= PAGE_SIZE;
16759412Smsmith	/*
16859412Smsmith	 * We'd love to be able to write:
16959412Smsmith	 *
17059412Smsmith	buffers = bufspace;
17159412Smsmith	 *
17259412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
17359412Smsmith	 * like unstaticizing it just for linprocfs's sake.
17459412Smsmith	 */
17559412Smsmith	buffers = 0;
17659412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
17759412Smsmith
17878025Sdes	sbuf_printf(sb,
17978031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18069799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18176839Sjlemon	    "Swap: %llu %llu %llu\n"
18269799Sdes	    "MemTotal: %9lu kB\n"
18369799Sdes	    "MemFree:  %9lu kB\n"
18469799Sdes	    "MemShared:%9lu kB\n"
18569799Sdes	    "Buffers:  %9lu kB\n"
18669799Sdes	    "Cached:   %9lu kB\n"
18776839Sjlemon	    "SwapTotal:%9llu kB\n"
18876839Sjlemon	    "SwapFree: %9llu kB\n",
18969799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19069799Sdes	    swaptotal, swapused, swapfree,
19169799Sdes	    B2K(memtotal), B2K(memfree),
19269799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
19369799Sdes	    B2K(swaptotal), B2K(swapfree));
19459412Smsmith
19578025Sdes	return (0);
19659412Smsmith}
19759412Smsmith
198133822Stjr#if defined(__i386__) || defined(__amd64__)
19978113Sdes/*
200133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20178113Sdes */
20278113Sdesstatic int
20378113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
20478113Sdes{
205159544Sdes	int hw_model[2];
206159544Sdes	char model[128];
207159544Sdes	size_t size;
208123246Sdes	int class, fqmhz, fqkhz;
209118421Sdes	int i;
21059412Smsmith
21169799Sdes	/*
21278031Sdes	 * We default the flags to include all non-conflicting flags,
21378031Sdes	 * and the Intel versions of conflicting flags.
21469799Sdes	 */
21578031Sdes	static char *flags[] = {
21678031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
21778031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
21878031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
21978031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22078031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22178031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22267589Sdes		"3dnowext", "3dnow"
22367589Sdes	};
22467589Sdes
22559412Smsmith	switch (cpu_class) {
226133822Stjr#ifdef __i386__
22759412Smsmith	case CPUCLASS_286:
22867589Sdes		class = 2;
22959412Smsmith		break;
23059412Smsmith	case CPUCLASS_386:
23167589Sdes		class = 3;
23259412Smsmith		break;
23359412Smsmith	case CPUCLASS_486:
23467589Sdes		class = 4;
23559412Smsmith		break;
23659412Smsmith	case CPUCLASS_586:
23767589Sdes		class = 5;
23859412Smsmith		break;
23959412Smsmith	case CPUCLASS_686:
24067589Sdes		class = 6;
24159412Smsmith		break;
24259412Smsmith	default:
24378031Sdes		class = 0;
24459412Smsmith		break;
245159170Sdes#else /* __amd64__ */
246133822Stjr	default:
247159170Sdes		class = 15;
248133822Stjr		break;
249133822Stjr#endif
25059412Smsmith	}
25159412Smsmith
252159544Sdes	hw_model[0] = CTL_HW;
253159544Sdes	hw_model[1] = HW_MODEL;
254159544Sdes	model[0] = '\0';
255159544Sdes	size = sizeof(model);
256159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
257159544Sdes		strcpy(model, "unknown");
258123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
259118421Sdes		sbuf_printf(sb,
260118421Sdes		    "processor\t: %d\n"
261118421Sdes		    "vendor_id\t: %.20s\n"
262118421Sdes		    "cpu family\t: %d\n"
263118421Sdes		    "model\t\t: %d\n"
264159544Sdes		    "model name\t: %s\n"
265118421Sdes		    "stepping\t: %d\n",
266159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
267159544Sdes		/* XXX per-cpu vendor / class / model / id? */
268118421Sdes	}
26959412Smsmith
27078031Sdes	sbuf_cat(sb,
27178031Sdes	    "flags\t\t:");
27267589Sdes
27378031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
27467589Sdes		flags[16] = "fcmov";
27578031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
27667589Sdes		flags[24] = "cxmmx";
27778031Sdes	}
278119068Sdes
27978031Sdes	for (i = 0; i < 32; i++)
28067589Sdes		if (cpu_feature & (1 << i))
28178025Sdes			sbuf_printf(sb, " %s", flags[i]);
28278025Sdes	sbuf_cat(sb, "\n");
28378031Sdes	if (class >= 5) {
28469799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
28569799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
28678025Sdes		sbuf_printf(sb,
28769799Sdes		    "cpu MHz\t\t: %d.%02d\n"
28869799Sdes		    "bogomips\t: %d.%02d\n",
28969799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
29078031Sdes	}
29169995Sdes
29278025Sdes	return (0);
29359412Smsmith}
294133822Stjr#endif /* __i386__ || __amd64__ */
29565633Sdes
29678113Sdes/*
29785289Sdes * Filler function for proc/mtab
29885289Sdes *
29985289Sdes * This file doesn't exist in Linux' procfs, but is included here so
30085289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
30185289Sdes */
30285289Sdesstatic int
30385289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
30485289Sdes{
30585289Sdes	struct nameidata nd;
30685289Sdes	struct mount *mp;
30791334Sjulian	const char *lep;
30891334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
30985289Sdes	size_t lep_len;
31085289Sdes	int error;
31185289Sdes
31285289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
31385289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
31485289Sdes	flep = NULL;
315124407Srwatson	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
31685289Sdes		lep = linux_emul_path;
31791334Sjulian	else
31891334Sjulian		lep = dlep;
31985289Sdes	lep_len = strlen(lep);
320119068Sdes
32185289Sdes	mtx_lock(&mountlist_mtx);
32285289Sdes	error = 0;
32385289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
32485289Sdes		/* determine device name */
32585289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
326119068Sdes
32785289Sdes		/* determine mount point */
32885289Sdes		mntto = mp->mnt_stat.f_mntonname;
32985289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
33085289Sdes		    mntto[lep_len] == '/')
33185289Sdes			mntto += lep_len;
33285289Sdes
33385289Sdes		/* determine fs type */
33485289Sdes		fstype = mp->mnt_stat.f_fstypename;
33585289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
33685289Sdes			mntfrom = fstype = "proc";
33785289Sdes		else if (strcmp(fstype, "procfs") == 0)
33885289Sdes			continue;
339119068Sdes
340158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
341158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
342158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
343158311Sambrisko		} else {
344158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
345158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
346158311Sambrisko		}
34785289Sdes#define ADD_OPTION(opt, name) \
34885289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
34985289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
35085289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
35185289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
35285289Sdes		ADD_OPTION(MNT_UNION,		"union");
35385289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
35485289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
35585289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
35685289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
35785289Sdes#undef ADD_OPTION
35885289Sdes		/* a real Linux mtab will also show NFS options */
35985289Sdes		sbuf_printf(sb, " 0 0\n");
36085289Sdes	}
36185289Sdes	mtx_unlock(&mountlist_mtx);
36285289Sdes	if (flep != NULL)
36385289Sdes		free(flep, M_TEMP);
36485289Sdes	return (error);
36585289Sdes}
36685289Sdes
36785289Sdes/*
36878113Sdes * Filler function for proc/stat
36978113Sdes */
37078025Sdesstatic int
37178025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
37265633Sdes{
373123246Sdes	int i;
374120339Sdes
375120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
376120339Sdes	    T2J(cp_time[CP_USER]),
377120339Sdes	    T2J(cp_time[CP_NICE]),
378120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
379120339Sdes	    T2J(cp_time[CP_IDLE]));
380143194Ssobomax	for (i = 0; i < mp_ncpus; ++i)
381143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
382143194Ssobomax		    T2J(cp_time[CP_USER]) / mp_ncpus,
383143194Ssobomax		    T2J(cp_time[CP_NICE]) / mp_ncpus,
384143194Ssobomax		    T2J(cp_time[CP_SYS]) / mp_ncpus,
385143194Ssobomax		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
38678025Sdes	sbuf_printf(sb,
38769799Sdes	    "disk 0 0 0 0\n"
38869799Sdes	    "page %u %u\n"
38969799Sdes	    "swap %u %u\n"
39069799Sdes	    "intr %u\n"
39169799Sdes	    "ctxt %u\n"
39285657Sdillon	    "btime %lld\n",
39369799Sdes	    cnt.v_vnodepgsin,
39469799Sdes	    cnt.v_vnodepgsout,
39569799Sdes	    cnt.v_swappgsin,
39669799Sdes	    cnt.v_swappgsout,
39769799Sdes	    cnt.v_intr,
39869799Sdes	    cnt.v_swtch,
399113574Sjhb	    (long long)boottime.tv_sec);
40078025Sdes	return (0);
40165633Sdes}
40265633Sdes
40378113Sdes/*
40478113Sdes * Filler function for proc/uptime
40578113Sdes */
40678025Sdesstatic int
40778025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
40865633Sdes{
40965633Sdes	struct timeval tv;
41065633Sdes
41165633Sdes	getmicrouptime(&tv);
41285657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
413113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
41469799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
41578025Sdes	return (0);
41665633Sdes}
41765633Sdes
41878113Sdes/*
41978113Sdes * Filler function for proc/version
42078113Sdes */
42178025Sdesstatic int
42278025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
42365633Sdes{
42487275Srwatson	char osname[LINUX_MAX_UTSNAME];
42587275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
42687275Srwatson
427112206Sjhb	linux_get_osname(td, osname);
428112206Sjhb	linux_get_osrelease(td, osrelease);
42987275Srwatson
43078025Sdes	sbuf_printf(sb,
43169995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
43287275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
43378025Sdes	return (0);
43465633Sdes}
43565633Sdes
43678113Sdes/*
43778113Sdes * Filler function for proc/loadavg
43878113Sdes */
43978025Sdesstatic int
44078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
44176839Sjlemon{
44278025Sdes	sbuf_printf(sb,
44376839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
44476839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
44576839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
44676839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
44776839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
44876839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
44976839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
45076839Sjlemon	    1,				/* number of running tasks */
45176839Sjlemon	    nprocs,			/* number of tasks */
45278116Sdes	    lastpid			/* the last pid */
45376839Sjlemon	);
454119068Sdes
45578025Sdes	return (0);
45676839Sjlemon}
45776839Sjlemon
45878113Sdes/*
45978113Sdes * Filler function for proc/pid/stat
46078113Sdes */
46178025Sdesstatic int
46278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
46367588Sdes{
46469995Sdes	struct kinfo_proc kp;
46567588Sdes
46694307Sjhb	PROC_LOCK(p);
46769995Sdes	fill_kinfo_proc(p, &kp);
46878025Sdes	sbuf_printf(sb, "%d", p->p_pid);
46978025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
47067588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
471159995Snetchild	KASSERT(kp.ki_stat <= sizeof(linux_state),
472159995Snetchild		("linprocfs: don't know how to handle unknown FreeBSD state"));
473159995Snetchild	PS_ADD("state",		"%c",	linux_state[kp.ki_stat - 1]);
47473923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
47567588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
47667588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
47791140Stanimura	PROC_UNLOCK(p);
47867588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
479159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
48067588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
481159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
482159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
483159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
484159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
485159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
486159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
487159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
488159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
489159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
490159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
491159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
492159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
493159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
494159995Snetchild	   It should be the number of jiffies between system boot and process
495159995Snetchild	   start. */
496159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
497159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
498159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
499159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
50069995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
50167588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
50267588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
503159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
504159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
505159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
506159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
507159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
508159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
50967588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
510159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
511159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
51269799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
513159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
514159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
515159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
51667588Sdes#undef PS_ADD
51778025Sdes	sbuf_putc(sb, '\n');
518119068Sdes
51978025Sdes	return (0);
52067588Sdes}
52167588Sdes
52267588Sdes/*
523119911Sdes * Filler function for proc/pid/statm
524119911Sdes */
525119911Sdesstatic int
526119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
527119911Sdes{
528119911Sdes	struct kinfo_proc kp;
529119911Sdes	segsz_t lsize;
530120340Sdes
531119911Sdes	PROC_LOCK(p);
532119911Sdes	fill_kinfo_proc(p, &kp);
533119911Sdes	PROC_UNLOCK(p);
534119911Sdes
535119911Sdes	/*
536119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
537119911Sdes	 * computation of lsize.
538119911Sdes	 */
539119911Sdes	/* size resident share trs drs lrs dt */
540119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
541119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
542119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
543119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
544119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
545119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
546119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
547119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
548119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
549119911Sdes
550119911Sdes	return (0);
551119911Sdes}
552119911Sdes
553119911Sdes/*
55478113Sdes * Filler function for proc/pid/status
55578113Sdes */
55678025Sdesstatic int
55778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
55867588Sdes{
55969995Sdes	struct kinfo_proc kp;
56067588Sdes	char *state;
56169799Sdes	segsz_t lsize;
56299072Sjulian	struct thread *td2;
563114983Sjhb	struct sigacts *ps;
56474135Sjlemon	int i;
56567588Sdes
566113611Sjhb	PROC_LOCK(p);
56799072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
56899072Sjulian
56999072Sjulian	if (P_SHOULDSTOP(p)) {
57099072Sjulian		state = "T (stopped)";
57199072Sjulian	} else {
572113611Sjhb		mtx_lock_spin(&sched_lock);
57399072Sjulian		switch(p->p_state) {
57499072Sjulian		case PRS_NEW:
57599072Sjulian			state = "I (idle)";
57699072Sjulian			break;
57799072Sjulian		case PRS_NORMAL:
57899072Sjulian			if (p->p_flag & P_WEXIT) {
57999072Sjulian				state = "X (exiting)";
58099072Sjulian				break;
58199072Sjulian			}
58299072Sjulian			switch(td2->td_state) {
583103216Sjulian			case TDS_INHIBITED:
58499072Sjulian				state = "S (sleeping)";
58599072Sjulian				break;
58699072Sjulian			case TDS_RUNQ:
58799072Sjulian			case TDS_RUNNING:
58899072Sjulian				state = "R (running)";
58999072Sjulian				break;
59099072Sjulian			default:
59199072Sjulian				state = "? (unknown)";
59299072Sjulian				break;
59399072Sjulian			}
59499072Sjulian			break;
59599072Sjulian		case PRS_ZOMBIE:
59699072Sjulian			state = "Z (zombie)";
59799072Sjulian			break;
59899072Sjulian		default:
59999072Sjulian			state = "? (unknown)";
60099072Sjulian			break;
60199072Sjulian		}
602113611Sjhb		mtx_unlock_spin(&sched_lock);
60399072Sjulian	}
60467588Sdes
60569995Sdes	fill_kinfo_proc(p, &kp);
60678025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
60778031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
60867588Sdes
60967588Sdes	/*
61067588Sdes	 * Credentials
61167588Sdes	 */
61278025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
61378025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
61473923Sjhb						p->p_pptr->p_pid : 0);
61578031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
61678031Sdes						p->p_ucred->cr_uid,
61778031Sdes						p->p_ucred->cr_svuid,
61878031Sdes						/* FreeBSD doesn't have fsuid */
61978031Sdes						p->p_ucred->cr_uid);
62078031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
62178031Sdes						p->p_ucred->cr_gid,
62278031Sdes						p->p_ucred->cr_svgid,
62378031Sdes						/* FreeBSD doesn't have fsgid */
62478031Sdes						p->p_ucred->cr_gid);
62578025Sdes	sbuf_cat(sb, "Groups:\t");
62667588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
62778031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
62871471Sjhb	PROC_UNLOCK(p);
62978025Sdes	sbuf_putc(sb, '\n');
630119068Sdes
63167588Sdes	/*
63267588Sdes	 * Memory
63369799Sdes	 *
63469799Sdes	 * While our approximation of VmLib may not be accurate (I
63569799Sdes	 * don't know of a simple way to verify it, and I'm not sure
63669799Sdes	 * it has much meaning anyway), I believe it's good enough.
63769799Sdes	 *
63869799Sdes	 * The same code that could (I think) accurately compute VmLib
63969799Sdes	 * could also compute VmLck, but I don't really care enough to
64069799Sdes	 * implement it. Submissions are welcome.
64167588Sdes	 */
642113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
64378025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
644113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
645113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
646113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
647113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
64869995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
64969995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
650113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
65167588Sdes
65267588Sdes	/*
65367588Sdes	 * Signal masks
65467588Sdes	 *
65567588Sdes	 * We support up to 128 signals, while Linux supports 32,
65667588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
65767588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
65867588Sdes	 *
65967588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
66067588Sdes	 * supports 64 signals, but this code is a long way from
66167588Sdes	 * running on anything but i386, so ignore that for now.
66267588Sdes	 */
66371471Sjhb	PROC_LOCK(p);
664104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
66569799Sdes	/*
66669799Sdes	 * I can't seem to find out where the signal mask is in
66769799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
66869799Sdes	 */
66978025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
670114983Sjhb	ps = p->p_sigacts;
671114983Sjhb	mtx_lock(&ps->ps_mtx);
672114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
673114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
674114983Sjhb	mtx_unlock(&ps->ps_mtx);
67571471Sjhb	PROC_UNLOCK(p);
676119068Sdes
67767588Sdes	/*
67867588Sdes	 * Linux also prints the capability masks, but we don't have
67967588Sdes	 * capabilities yet, and when we do get them they're likely to
68067588Sdes	 * be meaningless to Linux programs, so we lie. XXX
68167588Sdes	 */
68278025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
68378025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
68478025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
685119068Sdes
68678025Sdes	return (0);
68767588Sdes}
68874135Sjlemon
689119911Sdes
69078113Sdes/*
691119911Sdes * Filler function for proc/pid/cwd
692119911Sdes */
693119911Sdesstatic int
694119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
695119911Sdes{
696119911Sdes	char *fullpath = "unknown";
697119911Sdes	char *freepath = NULL;
698119911Sdes
699119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
700119911Sdes	sbuf_printf(sb, "%s", fullpath);
701119911Sdes	if (freepath)
702119911Sdes		free(freepath, M_TEMP);
703119911Sdes	return (0);
704119911Sdes}
705119911Sdes
706119911Sdes/*
707119911Sdes * Filler function for proc/pid/root
708119911Sdes */
709119911Sdesstatic int
710119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
711119911Sdes{
712119911Sdes	struct vnode *rvp;
713119911Sdes	char *fullpath = "unknown";
714119911Sdes	char *freepath = NULL;
715119911Sdes
716119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
717119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
718119911Sdes	sbuf_printf(sb, "%s", fullpath);
719119911Sdes	if (freepath)
720119911Sdes		free(freepath, M_TEMP);
721119911Sdes	return (0);
722119911Sdes}
723119911Sdes
724119911Sdes/*
72578113Sdes * Filler function for proc/pid/cmdline
72678113Sdes */
72778025Sdesstatic int
72878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
72978113Sdes{
73078113Sdes	struct ps_strings pstr;
731138281Scperciva	char **ps_argvstr;
73278113Sdes	int error, i;
73378113Sdes
73478113Sdes	/*
73578113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
73678113Sdes	 * revert back to the old way which only implements full cmdline
73778113Sdes	 * for the currept process and just p->p_comm for all other
73878113Sdes	 * processes.
73978113Sdes	 * Note that if the argv is no longer available, we deliberately
74078113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
74178113Sdes	 * Linux behaviour is to return zero-length in this case.
74278113Sdes	 */
74378113Sdes
74494620Sjhb	PROC_LOCK(p);
745127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
74694620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
74794620Sjhb		PROC_UNLOCK(p);
74894620Sjhb	} else if (p != td->td_proc) {
74994620Sjhb		PROC_UNLOCK(p);
75094620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
75194620Sjhb	} else {
75294620Sjhb		PROC_UNLOCK(p);
753103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
754103767Sjake		    sizeof(pstr));
75594620Sjhb		if (error)
75694620Sjhb			return (error);
757138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
758138281Scperciva			return (E2BIG);
759138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
760138281Scperciva		    M_TEMP, M_WAITOK);
761138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
762138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
763138281Scperciva		if (error) {
764138281Scperciva			free(ps_argvstr, M_TEMP);
765138281Scperciva			return (error);
766138281Scperciva		}
76794620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
768138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
76994620Sjhb			sbuf_printf(sb, "%c", '\0');
77078113Sdes		}
771138281Scperciva		free(ps_argvstr, M_TEMP);
77278113Sdes	}
77378113Sdes
77478113Sdes	return (0);
77578113Sdes}
77678113Sdes
77778113Sdes/*
778116173Sobrien * Filler function for proc/pid/environ
779116173Sobrien */
780116173Sobrienstatic int
781116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
782116173Sobrien{
783116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
784116173Sobrien
785116173Sobrien	return (0);
786116173Sobrien}
787116173Sobrien
788116173Sobrien/*
789116173Sobrien * Filler function for proc/pid/maps
790116173Sobrien */
791116173Sobrienstatic int
792116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
793116173Sobrien{
794121265Scognet	char mebuffer[512];
795121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
796121246Scognet	vm_map_entry_t entry;
797121265Scognet	vm_object_t obj, tobj, lobj;
798121265Scognet	vm_ooffset_t off = 0;
799121265Scognet	char *name = "", *freename = NULL;
800121265Scognet	size_t len;
801121265Scognet	ino_t ino;
802121265Scognet	int ref_count, shadow_count, flags;
803121265Scognet	int error;
804137507Sphk	struct vnode *vp;
805137507Sphk	struct vattr vat;
806161094Skib	int locked;
807121246Scognet
808121246Scognet	PROC_LOCK(p);
809121246Scognet	error = p_candebug(td, p);
810121246Scognet	PROC_UNLOCK(p);
811121246Scognet	if (error)
812121246Scognet		return (error);
813121246Scognet
814121246Scognet	if (uio->uio_rw != UIO_READ)
815121246Scognet		return (EOPNOTSUPP);
816121246Scognet
817121246Scognet	if (uio->uio_offset != 0)
818121246Scognet		return (0);
819121246Scognet
820121246Scognet	error = 0;
821121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
822121246Scognet		vm_map_lock_read(map);
823121246Scognet        for (entry = map->header.next;
824121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
825121246Scognet	    entry = entry->next) {
826121265Scognet		name = "";
827121265Scognet		freename = NULL;
828121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
829121246Scognet			continue;
830121246Scognet		obj = entry->object.vm_object;
831121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
832121246Scognet			lobj = tobj;
833121246Scognet		ino = 0;
834121246Scognet		if (lobj) {
835121246Scognet			VM_OBJECT_LOCK(lobj);
836121246Scognet			off = IDX_TO_OFF(lobj->size);
837161094Skib			if (lobj->type == OBJT_VNODE) {
838161094Skib				vp = lobj->handle;
839161094Skib				if (vp)
840161094Skib					vref(vp);
841121246Scognet			}
842161094Skib			else
843161094Skib				vp = NULL;
844121246Scognet			flags = obj->flags;
845121246Scognet			ref_count = obj->ref_count;
846121246Scognet			shadow_count = obj->shadow_count;
847121246Scognet			VM_OBJECT_UNLOCK(lobj);
848161094Skib			if (vp) {
849161094Skib				vn_fullpath(td, vp, &name, &freename);
850161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
851161094Skib				vn_lock(vp, LK_SHARED | LK_RETRY, td);
852161094Skib				VOP_GETATTR(vp, &vat, td->td_ucred, td);
853161094Skib				ino = vat.va_fileid;
854161094Skib				vput(vp);
855161094Skib				VFS_UNLOCK_GIANT(locked);
856161094Skib			}
857121246Scognet		} else {
858121246Scognet			flags = 0;
859121246Scognet			ref_count = 0;
860121246Scognet			shadow_count = 0;
861121246Scognet		}
862121246Scognet
863121246Scognet		/*
864121246Scognet	     	 * format:
865121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
866121246Scognet		 */
867121246Scognet		snprintf(mebuffer, sizeof mebuffer,
868121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
869121246Scognet		    (u_long)entry->start, (u_long)entry->end,
870121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
871121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
872121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
873121246Scognet		    "p",
874121265Scognet		    (u_long)off,
875121246Scognet		    0,
876121246Scognet		    0,
877121265Scognet		    (u_long)ino,
878121246Scognet		    *name ? "     " : "",
879121246Scognet		    name
880121246Scognet		    );
881121246Scognet		if (freename)
882121246Scognet			free(freename, M_TEMP);
883121246Scognet		len = strlen(mebuffer);
884121246Scognet		if (len > uio->uio_resid)
885121246Scognet			len = uio->uio_resid; /*
886121246Scognet					       * XXX We should probably return
887121246Scognet					       * EFBIG here, as in procfs.
888121246Scognet					       */
889121246Scognet		error = uiomove(mebuffer, len, uio);
890121246Scognet		if (error)
891121246Scognet			break;
892121246Scognet	}
893121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
894121246Scognet		vm_map_unlock_read(map);
895121246Scognet
896121246Scognet	return (error);
897121246Scognet}
898121246Scognet
899116173Sobrien/*
90078113Sdes * Filler function for proc/net/dev
90178113Sdes */
90278025Sdesstatic int
90378025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
90474135Sjlemon{
90585129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
90674135Sjlemon	struct ifnet *ifp;
90774135Sjlemon
90885129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
90983926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
91085129Sdes	    "bytes    packets errs drop fifo frame compressed",
91183926Sdes	    "bytes    packets errs drop fifo frame compressed");
91274135Sjlemon
913108172Shsu	IFNET_RLOCK();
91474135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
91585129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
91685129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
91783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
91883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
91983926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
92083926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
92174135Sjlemon	}
922108172Shsu	IFNET_RUNLOCK();
923119068Sdes
92478025Sdes	return (0);
92574135Sjlemon}
92674135Sjlemon
927158311Sambrisko/*
928158311Sambrisko * Filler function for proc/scsi/device_info
929158311Sambrisko */
930158311Sambriskostatic int
931158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
932158311Sambrisko{
933158311Sambrisko	return (0);
934158311Sambrisko}
935158311Sambrisko
936158311Sambrisko/*
937158311Sambrisko * Filler function for proc/scsi/scsi
938158311Sambrisko */
939158311Sambriskostatic int
940158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
941158311Sambrisko{
942158311Sambrisko	return (0);
943158311Sambrisko}
944158311Sambrisko
94585538Sphkextern struct cdevsw *cdevsw[];
94685538Sphk
94778113Sdes/*
94878113Sdes * Filler function for proc/devices
94978113Sdes */
95078025Sdesstatic int
95178025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
95274135Sjlemon{
953158311Sambrisko	char *char_devices;
95478025Sdes	sbuf_printf(sb, "Character devices:\n");
95574135Sjlemon
956158311Sambrisko	char_devices = linux_get_char_devices();
957158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
958158311Sambrisko	linux_free_get_char_devices(char_devices);
95974135Sjlemon
96078025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
961119068Sdes
96278025Sdes	return (0);
96374135Sjlemon}
96474135Sjlemon
96578113Sdes/*
96678113Sdes * Filler function for proc/cmdline
96778113Sdes */
96878025Sdesstatic int
96978025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
97074135Sjlemon{
97178025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
97278025Sdes	sbuf_printf(sb, " ro root=302\n");
97378025Sdes	return (0);
97478025Sdes}
97574135Sjlemon
97683926Sdes#if 0
97778025Sdes/*
97883926Sdes * Filler function for proc/modules
97983926Sdes */
98083926Sdesstatic int
98183926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
98283926Sdes{
98383926Sdes	struct linker_file *lf;
984119068Sdes
98583926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
98683926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
98783926Sdes		    (unsigned long)lf->size, lf->refs);
98883926Sdes	}
98983926Sdes	return (0);
99083926Sdes}
99183926Sdes#endif
99283926Sdes
99383926Sdes/*
99485129Sdes * Constructor
99578025Sdes */
99685129Sdesstatic int
99785129Sdeslinprocfs_init(PFS_INIT_ARGS)
99885129Sdes{
99985129Sdes	struct pfs_node *root;
100085129Sdes	struct pfs_node *dir;
100174135Sjlemon
100285129Sdes	root = pi->pi_root;
100378025Sdes
1004119923Sdes	/* /proc/... */
1005119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1006119911Sdes	    NULL, NULL, PFS_RD);
1007119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1008119911Sdes	    NULL, NULL, PFS_RD);
1009119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1010119911Sdes	    NULL, NULL, PFS_RD);
1011119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1012119911Sdes	    NULL, NULL, PFS_RD);
1013119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1014119911Sdes	    NULL, NULL, PFS_RD);
101583926Sdes#if 0
1016119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1017119911Sdes	    NULL, NULL, PFS_RD);
101883926Sdes#endif
1019158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1020158311Sambrisko	    NULL, NULL, PFS_RD);
1021119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1022119911Sdes	    NULL, NULL, PFS_RD);
102387543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
102485129Sdes	    NULL, NULL, 0);
1025119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1026119911Sdes	    NULL, NULL, PFS_RD);
1027119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1028119911Sdes	    NULL, NULL, PFS_RD);
1029119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1030119911Sdes	    NULL, NULL, PFS_RD);
103178025Sdes
1032119923Sdes	/* /proc/net/... */
103385129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
103485129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
103585129Sdes	    NULL, NULL, PFS_RD);
103678025Sdes
1037119923Sdes	/* /proc/<pid>/... */
103885129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
103985129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
104085129Sdes	    NULL, NULL, PFS_RD);
1041119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1042119911Sdes	    NULL, NULL, 0);
1043116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1044116173Sobrien	    NULL, NULL, PFS_RD);
104587543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
104687543Sdes	    NULL, &procfs_notsystem, 0);
1047116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1048116173Sobrien	    NULL, NULL, PFS_RD);
104985129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
105085129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1051119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1052119911Sdes	    NULL, NULL, 0);
105385129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
105485129Sdes	    NULL, NULL, PFS_RD);
1055119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1056119911Sdes	    NULL, NULL, PFS_RD);
105785129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
105885129Sdes	    NULL, NULL, PFS_RD);
105985129Sdes
1060158311Sambrisko	/* /proc/scsi/... */
1061158311Sambrisko	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1062158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1063158311Sambrisko	    NULL, NULL, PFS_RD);
1064158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1065158311Sambrisko	    NULL, NULL, PFS_RD);
106685129Sdes	return (0);
106785129Sdes}
106885129Sdes
106985129Sdes/*
107085129Sdes * Destructor
107185129Sdes */
107285129Sdesstatic int
107385129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
107485129Sdes{
107585129Sdes
107685129Sdes	/* nothing to do, pseudofs will GC */
107785129Sdes	return (0);
107885129Sdes}
107985129Sdes
108085129SdesPSEUDOFS(linprocfs, 1);
108178025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
108278025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1083