linprocfs.c revision 159544
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 159544 2006-06-12 18:14:49Z des $");
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>
6665633Sdes#include <sys/tty.h>
6783926Sdes#include <sys/user.h>
6883926Sdes#include <sys/vmmeter.h>
6959412Smsmith#include <sys/vnode.h>
7059412Smsmith
7183926Sdes#include <net/if.h>
7283926Sdes
7359412Smsmith#include <vm/vm.h>
7459412Smsmith#include <vm/pmap.h>
7567588Sdes#include <vm/vm_map.h>
7659412Smsmith#include <vm/vm_param.h>
7760860Sdes#include <vm/vm_object.h>
7859412Smsmith#include <vm/swap_pager.h>
7969799Sdes
8067589Sdes#include <machine/clock.h>
8178113Sdes
82133822Stjr#if defined(__i386__) || defined(__amd64__)
8367589Sdes#include <machine/cputypes.h>
8459412Smsmith#include <machine/md_var.h>
85133822Stjr#endif /* __i386__ || __amd64__ */
8659412Smsmith
87133822Stjr#include "opt_compat.h"
88140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
89140214Sobrien#include <machine/../linux32/linux.h>
90140214Sobrien#else
9187275Srwatson#include <machine/../linux/linux.h>
92133822Stjr#endif
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;
124117723Sphk	int i, j;
12559412Smsmith
12659412Smsmith	memtotal = physmem * PAGE_SIZE;
12759412Smsmith	/*
12859412Smsmith	 * The correct thing here would be:
12959412Smsmith	 *
13059412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
13159412Smsmith	memused = memtotal - memfree;
13259412Smsmith	 *
13359412Smsmith	 * but it might mislead linux binaries into thinking there
13459412Smsmith	 * is very little memory left, so we cheat and tell them that
13559412Smsmith	 * all memory that isn't wired down is free.
13659412Smsmith	 */
13759412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
13859412Smsmith	memfree = memtotal - memused;
139117723Sphk	swap_pager_status(&i, &j);
140153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
141153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
142117723Sphk	swapfree = swaptotal - swapused;
14360860Sdes	memshared = 0;
144124082Salc	mtx_lock(&vm_object_list_mtx);
14571471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
14660860Sdes		if (object->shadow_count > 1)
14760860Sdes			memshared += object->resident_page_count;
148124082Salc	mtx_unlock(&vm_object_list_mtx);
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
181133822Stjr#if defined(__i386__) || defined(__amd64__)
18278113Sdes/*
183133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
18478113Sdes */
18578113Sdesstatic int
18678113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
18778113Sdes{
188159544Sdes	int hw_model[2];
189159544Sdes	char model[128];
190159544Sdes	size_t size;
191123246Sdes	int class, fqmhz, fqkhz;
192118421Sdes	int i;
19359412Smsmith
19469799Sdes	/*
19578031Sdes	 * We default the flags to include all non-conflicting flags,
19678031Sdes	 * and the Intel versions of conflicting flags.
19769799Sdes	 */
19878031Sdes	static char *flags[] = {
19978031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
20078031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
20178031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
20278031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
20378031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
20478031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
20567589Sdes		"3dnowext", "3dnow"
20667589Sdes	};
20767589Sdes
20859412Smsmith	switch (cpu_class) {
209133822Stjr#ifdef __i386__
21059412Smsmith	case CPUCLASS_286:
21167589Sdes		class = 2;
21259412Smsmith		break;
21359412Smsmith	case CPUCLASS_386:
21467589Sdes		class = 3;
21559412Smsmith		break;
21659412Smsmith	case CPUCLASS_486:
21767589Sdes		class = 4;
21859412Smsmith		break;
21959412Smsmith	case CPUCLASS_586:
22067589Sdes		class = 5;
22159412Smsmith		break;
22259412Smsmith	case CPUCLASS_686:
22367589Sdes		class = 6;
22459412Smsmith		break;
22559412Smsmith	default:
22678031Sdes		class = 0;
22759412Smsmith		break;
228159170Sdes#else /* __amd64__ */
229133822Stjr	default:
230159170Sdes		class = 15;
231133822Stjr		break;
232133822Stjr#endif
23359412Smsmith	}
23459412Smsmith
235159544Sdes	hw_model[0] = CTL_HW;
236159544Sdes	hw_model[1] = HW_MODEL;
237159544Sdes	model[0] = '\0';
238159544Sdes	size = sizeof(model);
239159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
240159544Sdes		strcpy(model, "unknown");
241123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
242118421Sdes		sbuf_printf(sb,
243118421Sdes		    "processor\t: %d\n"
244118421Sdes		    "vendor_id\t: %.20s\n"
245118421Sdes		    "cpu family\t: %d\n"
246118421Sdes		    "model\t\t: %d\n"
247159544Sdes		    "model name\t: %s\n"
248118421Sdes		    "stepping\t: %d\n",
249159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
250159544Sdes		/* XXX per-cpu vendor / class / model / id? */
251118421Sdes	}
25259412Smsmith
25378031Sdes	sbuf_cat(sb,
25478031Sdes	    "flags\t\t:");
25567589Sdes
25678031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
25767589Sdes		flags[16] = "fcmov";
25878031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
25967589Sdes		flags[24] = "cxmmx";
26078031Sdes	}
261119068Sdes
26278031Sdes	for (i = 0; i < 32; i++)
26367589Sdes		if (cpu_feature & (1 << i))
26478025Sdes			sbuf_printf(sb, " %s", flags[i]);
26578025Sdes	sbuf_cat(sb, "\n");
26678031Sdes	if (class >= 5) {
26769799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
26869799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
26978025Sdes		sbuf_printf(sb,
27069799Sdes		    "cpu MHz\t\t: %d.%02d\n"
27169799Sdes		    "bogomips\t: %d.%02d\n",
27269799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
27378031Sdes	}
27469995Sdes
27578025Sdes	return (0);
27659412Smsmith}
277133822Stjr#endif /* __i386__ || __amd64__ */
27865633Sdes
27978113Sdes/*
28085289Sdes * Filler function for proc/mtab
28185289Sdes *
28285289Sdes * This file doesn't exist in Linux' procfs, but is included here so
28385289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
28485289Sdes */
28585289Sdesstatic int
28685289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
28785289Sdes{
28885289Sdes	struct nameidata nd;
28985289Sdes	struct mount *mp;
29091334Sjulian	const char *lep;
29191334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
29285289Sdes	size_t lep_len;
29385289Sdes	int error;
29485289Sdes
29585289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
29685289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
29785289Sdes	flep = NULL;
298124407Srwatson	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
29985289Sdes		lep = linux_emul_path;
30091334Sjulian	else
30191334Sjulian		lep = dlep;
30285289Sdes	lep_len = strlen(lep);
303119068Sdes
30485289Sdes	mtx_lock(&mountlist_mtx);
30585289Sdes	error = 0;
30685289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
30785289Sdes		/* determine device name */
30885289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
309119068Sdes
31085289Sdes		/* determine mount point */
31185289Sdes		mntto = mp->mnt_stat.f_mntonname;
31285289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
31385289Sdes		    mntto[lep_len] == '/')
31485289Sdes			mntto += lep_len;
31585289Sdes
31685289Sdes		/* determine fs type */
31785289Sdes		fstype = mp->mnt_stat.f_fstypename;
31885289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
31985289Sdes			mntfrom = fstype = "proc";
32085289Sdes		else if (strcmp(fstype, "procfs") == 0)
32185289Sdes			continue;
322119068Sdes
323158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
324158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
325158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
326158311Sambrisko		} else {
327158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
328158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
329158311Sambrisko		}
33085289Sdes#define ADD_OPTION(opt, name) \
33185289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
33285289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
33385289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
33485289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
33585289Sdes		ADD_OPTION(MNT_UNION,		"union");
33685289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
33785289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
33885289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
33985289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
34085289Sdes#undef ADD_OPTION
34185289Sdes		/* a real Linux mtab will also show NFS options */
34285289Sdes		sbuf_printf(sb, " 0 0\n");
34385289Sdes	}
34485289Sdes	mtx_unlock(&mountlist_mtx);
34585289Sdes	if (flep != NULL)
34685289Sdes		free(flep, M_TEMP);
34785289Sdes	return (error);
34885289Sdes}
34985289Sdes
35085289Sdes/*
35178113Sdes * Filler function for proc/stat
35278113Sdes */
35378025Sdesstatic int
35478025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
35565633Sdes{
356123246Sdes	int i;
357120339Sdes
358120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
359120339Sdes	    T2J(cp_time[CP_USER]),
360120339Sdes	    T2J(cp_time[CP_NICE]),
361120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
362120339Sdes	    T2J(cp_time[CP_IDLE]));
363143194Ssobomax	for (i = 0; i < mp_ncpus; ++i)
364143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
365143194Ssobomax		    T2J(cp_time[CP_USER]) / mp_ncpus,
366143194Ssobomax		    T2J(cp_time[CP_NICE]) / mp_ncpus,
367143194Ssobomax		    T2J(cp_time[CP_SYS]) / mp_ncpus,
368143194Ssobomax		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
36978025Sdes	sbuf_printf(sb,
37069799Sdes	    "disk 0 0 0 0\n"
37169799Sdes	    "page %u %u\n"
37269799Sdes	    "swap %u %u\n"
37369799Sdes	    "intr %u\n"
37469799Sdes	    "ctxt %u\n"
37585657Sdillon	    "btime %lld\n",
37669799Sdes	    cnt.v_vnodepgsin,
37769799Sdes	    cnt.v_vnodepgsout,
37869799Sdes	    cnt.v_swappgsin,
37969799Sdes	    cnt.v_swappgsout,
38069799Sdes	    cnt.v_intr,
38169799Sdes	    cnt.v_swtch,
382113574Sjhb	    (long long)boottime.tv_sec);
38378025Sdes	return (0);
38465633Sdes}
38565633Sdes
38678113Sdes/*
38778113Sdes * Filler function for proc/uptime
38878113Sdes */
38978025Sdesstatic int
39078025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
39165633Sdes{
39265633Sdes	struct timeval tv;
39365633Sdes
39465633Sdes	getmicrouptime(&tv);
39585657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
396113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
39769799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
39878025Sdes	return (0);
39965633Sdes}
40065633Sdes
40178113Sdes/*
40278113Sdes * Filler function for proc/version
40378113Sdes */
40478025Sdesstatic int
40578025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
40665633Sdes{
40787275Srwatson	char osname[LINUX_MAX_UTSNAME];
40887275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
40987275Srwatson
410112206Sjhb	linux_get_osname(td, osname);
411112206Sjhb	linux_get_osrelease(td, osrelease);
41287275Srwatson
41378025Sdes	sbuf_printf(sb,
41469995Sdes	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
41587275Srwatson	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
41678025Sdes	return (0);
41765633Sdes}
41865633Sdes
41978113Sdes/*
42078113Sdes * Filler function for proc/loadavg
42178113Sdes */
42278025Sdesstatic int
42378025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
42476839Sjlemon{
42578025Sdes	sbuf_printf(sb,
42676839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
42776839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
42876839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
42976839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
43076839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
43176839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
43276839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
43376839Sjlemon	    1,				/* number of running tasks */
43476839Sjlemon	    nprocs,			/* number of tasks */
43578116Sdes	    lastpid			/* the last pid */
43676839Sjlemon	);
437119068Sdes
43878025Sdes	return (0);
43976839Sjlemon}
44076839Sjlemon
44178113Sdes/*
44278113Sdes * Filler function for proc/pid/stat
44378113Sdes */
44478025Sdesstatic int
44578025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
44667588Sdes{
44769995Sdes	struct kinfo_proc kp;
44867588Sdes
44994307Sjhb	PROC_LOCK(p);
45069995Sdes	fill_kinfo_proc(p, &kp);
45178025Sdes	sbuf_printf(sb, "%d", p->p_pid);
45278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
45367588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
45467588Sdes	PS_ADD("statr",		"%c",	'0'); /* XXX */
45573923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
45667588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
45767588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
45891140Stanimura	PROC_UNLOCK(p);
45967588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
46067588Sdes	PS_ADD("tpgid",		"%d",	0); /* XXX */
46167588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
46267588Sdes	PS_ADD("minflt",	"%u",	0); /* XXX */
46367588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
46467588Sdes	PS_ADD("majflt",	"%u",	0); /* XXX */
46567588Sdes	PS_ADD("cminflt",	"%u",	0); /* XXX */
46667588Sdes	PS_ADD("utime",		"%d",	0); /* XXX */
46767588Sdes	PS_ADD("stime",		"%d",	0); /* XXX */
46867588Sdes	PS_ADD("cutime",	"%d",	0); /* XXX */
46967588Sdes	PS_ADD("cstime",	"%d",	0); /* XXX */
47067588Sdes	PS_ADD("counter",	"%d",	0); /* XXX */
47167588Sdes	PS_ADD("priority",	"%d",	0); /* XXX */
47267588Sdes	PS_ADD("timeout",	"%u",	0); /* XXX */
47367588Sdes	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
47467588Sdes	PS_ADD("starttime",	"%d",	0); /* XXX */
475113574Sjhb	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
476113574Sjhb	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
47767588Sdes	PS_ADD("rlim",		"%u",	0); /* XXX */
47869995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
47967588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
48067588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
48169799Sdes	PS_ADD("esp",		"%u",	0); /* XXX */
48269799Sdes	PS_ADD("eip",		"%u",	0); /* XXX */
48367588Sdes	PS_ADD("signal",	"%d",	0); /* XXX */
48467588Sdes	PS_ADD("blocked",	"%d",	0); /* XXX */
48567588Sdes	PS_ADD("sigignore",	"%d",	0); /* XXX */
48667588Sdes	PS_ADD("sigcatch",	"%d",	0); /* XXX */
48767588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
48869799Sdes	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
48969799Sdes	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
49069799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
49169799Sdes	PS_ADD("processor",	"%d",	0); /* XXX */
49267588Sdes#undef PS_ADD
49378025Sdes	sbuf_putc(sb, '\n');
494119068Sdes
49578025Sdes	return (0);
49667588Sdes}
49767588Sdes
49867588Sdes/*
499119911Sdes * Filler function for proc/pid/statm
500119911Sdes */
501119911Sdesstatic int
502119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
503119911Sdes{
504119911Sdes	struct kinfo_proc kp;
505119911Sdes	segsz_t lsize;
506120340Sdes
507119911Sdes	PROC_LOCK(p);
508119911Sdes	fill_kinfo_proc(p, &kp);
509119911Sdes	PROC_UNLOCK(p);
510119911Sdes
511119911Sdes	/*
512119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
513119911Sdes	 * computation of lsize.
514119911Sdes	 */
515119911Sdes	/* size resident share trs drs lrs dt */
516119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
517119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
518119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
519119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
520119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
521119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
522119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
523119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
524119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
525119911Sdes
526119911Sdes	return (0);
527119911Sdes}
528119911Sdes
529119911Sdes/*
53078113Sdes * Filler function for proc/pid/status
53178113Sdes */
53278025Sdesstatic int
53378025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
53467588Sdes{
53569995Sdes	struct kinfo_proc kp;
53667588Sdes	char *state;
53769799Sdes	segsz_t lsize;
53899072Sjulian	struct thread *td2;
539114983Sjhb	struct sigacts *ps;
54074135Sjlemon	int i;
54167588Sdes
542113611Sjhb	PROC_LOCK(p);
54399072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
54499072Sjulian
54599072Sjulian	if (P_SHOULDSTOP(p)) {
54699072Sjulian		state = "T (stopped)";
54799072Sjulian	} else {
548113611Sjhb		mtx_lock_spin(&sched_lock);
54999072Sjulian		switch(p->p_state) {
55099072Sjulian		case PRS_NEW:
55199072Sjulian			state = "I (idle)";
55299072Sjulian			break;
55399072Sjulian		case PRS_NORMAL:
55499072Sjulian			if (p->p_flag & P_WEXIT) {
55599072Sjulian				state = "X (exiting)";
55699072Sjulian				break;
55799072Sjulian			}
55899072Sjulian			switch(td2->td_state) {
559103216Sjulian			case TDS_INHIBITED:
56099072Sjulian				state = "S (sleeping)";
56199072Sjulian				break;
56299072Sjulian			case TDS_RUNQ:
56399072Sjulian			case TDS_RUNNING:
56499072Sjulian				state = "R (running)";
56599072Sjulian				break;
56699072Sjulian			default:
56799072Sjulian				state = "? (unknown)";
56899072Sjulian				break;
56999072Sjulian			}
57099072Sjulian			break;
57199072Sjulian		case PRS_ZOMBIE:
57299072Sjulian			state = "Z (zombie)";
57399072Sjulian			break;
57499072Sjulian		default:
57599072Sjulian			state = "? (unknown)";
57699072Sjulian			break;
57799072Sjulian		}
578113611Sjhb		mtx_unlock_spin(&sched_lock);
57999072Sjulian	}
58067588Sdes
58169995Sdes	fill_kinfo_proc(p, &kp);
58278025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
58378031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
58467588Sdes
58567588Sdes	/*
58667588Sdes	 * Credentials
58767588Sdes	 */
58878025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
58978025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
59073923Sjhb						p->p_pptr->p_pid : 0);
59178031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
59278031Sdes						p->p_ucred->cr_uid,
59378031Sdes						p->p_ucred->cr_svuid,
59478031Sdes						/* FreeBSD doesn't have fsuid */
59578031Sdes						p->p_ucred->cr_uid);
59678031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
59778031Sdes						p->p_ucred->cr_gid,
59878031Sdes						p->p_ucred->cr_svgid,
59978031Sdes						/* FreeBSD doesn't have fsgid */
60078031Sdes						p->p_ucred->cr_gid);
60178025Sdes	sbuf_cat(sb, "Groups:\t");
60267588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
60378031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
60471471Sjhb	PROC_UNLOCK(p);
60578025Sdes	sbuf_putc(sb, '\n');
606119068Sdes
60767588Sdes	/*
60867588Sdes	 * Memory
60969799Sdes	 *
61069799Sdes	 * While our approximation of VmLib may not be accurate (I
61169799Sdes	 * don't know of a simple way to verify it, and I'm not sure
61269799Sdes	 * it has much meaning anyway), I believe it's good enough.
61369799Sdes	 *
61469799Sdes	 * The same code that could (I think) accurately compute VmLib
61569799Sdes	 * could also compute VmLck, but I don't really care enough to
61669799Sdes	 * implement it. Submissions are welcome.
61767588Sdes	 */
618113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
61978025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
620113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
621113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
622113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
623113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
62469995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
62569995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
626113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
62767588Sdes
62867588Sdes	/*
62967588Sdes	 * Signal masks
63067588Sdes	 *
63167588Sdes	 * We support up to 128 signals, while Linux supports 32,
63267588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
63367588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
63467588Sdes	 *
63567588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
63667588Sdes	 * supports 64 signals, but this code is a long way from
63767588Sdes	 * running on anything but i386, so ignore that for now.
63867588Sdes	 */
63971471Sjhb	PROC_LOCK(p);
640104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
64169799Sdes	/*
64269799Sdes	 * I can't seem to find out where the signal mask is in
64369799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
64469799Sdes	 */
64578025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
646114983Sjhb	ps = p->p_sigacts;
647114983Sjhb	mtx_lock(&ps->ps_mtx);
648114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
649114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
650114983Sjhb	mtx_unlock(&ps->ps_mtx);
65171471Sjhb	PROC_UNLOCK(p);
652119068Sdes
65367588Sdes	/*
65467588Sdes	 * Linux also prints the capability masks, but we don't have
65567588Sdes	 * capabilities yet, and when we do get them they're likely to
65667588Sdes	 * be meaningless to Linux programs, so we lie. XXX
65767588Sdes	 */
65878025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
65978025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
66078025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
661119068Sdes
66278025Sdes	return (0);
66367588Sdes}
66474135Sjlemon
665119911Sdes
66678113Sdes/*
667119911Sdes * Filler function for proc/pid/cwd
668119911Sdes */
669119911Sdesstatic int
670119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
671119911Sdes{
672119911Sdes	char *fullpath = "unknown";
673119911Sdes	char *freepath = NULL;
674119911Sdes
675119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
676119911Sdes	sbuf_printf(sb, "%s", fullpath);
677119911Sdes	if (freepath)
678119911Sdes		free(freepath, M_TEMP);
679119911Sdes	return (0);
680119911Sdes}
681119911Sdes
682119911Sdes/*
683119911Sdes * Filler function for proc/pid/root
684119911Sdes */
685119911Sdesstatic int
686119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
687119911Sdes{
688119911Sdes	struct vnode *rvp;
689119911Sdes	char *fullpath = "unknown";
690119911Sdes	char *freepath = NULL;
691119911Sdes
692119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
693119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
694119911Sdes	sbuf_printf(sb, "%s", fullpath);
695119911Sdes	if (freepath)
696119911Sdes		free(freepath, M_TEMP);
697119911Sdes	return (0);
698119911Sdes}
699119911Sdes
700119911Sdes/*
70178113Sdes * Filler function for proc/pid/cmdline
70278113Sdes */
70378025Sdesstatic int
70478113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
70578113Sdes{
70678113Sdes	struct ps_strings pstr;
707138281Scperciva	char **ps_argvstr;
70878113Sdes	int error, i;
70978113Sdes
71078113Sdes	/*
71178113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
71278113Sdes	 * revert back to the old way which only implements full cmdline
71378113Sdes	 * for the currept process and just p->p_comm for all other
71478113Sdes	 * processes.
71578113Sdes	 * Note that if the argv is no longer available, we deliberately
71678113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
71778113Sdes	 * Linux behaviour is to return zero-length in this case.
71878113Sdes	 */
71978113Sdes
72094620Sjhb	PROC_LOCK(p);
721127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
72294620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
72394620Sjhb		PROC_UNLOCK(p);
72494620Sjhb	} else if (p != td->td_proc) {
72594620Sjhb		PROC_UNLOCK(p);
72694620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
72794620Sjhb	} else {
72894620Sjhb		PROC_UNLOCK(p);
729103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
730103767Sjake		    sizeof(pstr));
73194620Sjhb		if (error)
73294620Sjhb			return (error);
733138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
734138281Scperciva			return (E2BIG);
735138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
736138281Scperciva		    M_TEMP, M_WAITOK);
737138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
738138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
739138281Scperciva		if (error) {
740138281Scperciva			free(ps_argvstr, M_TEMP);
741138281Scperciva			return (error);
742138281Scperciva		}
74394620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
744138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
74594620Sjhb			sbuf_printf(sb, "%c", '\0');
74678113Sdes		}
747138281Scperciva		free(ps_argvstr, M_TEMP);
74878113Sdes	}
74978113Sdes
75078113Sdes	return (0);
75178113Sdes}
75278113Sdes
75378113Sdes/*
754116173Sobrien * Filler function for proc/pid/environ
755116173Sobrien */
756116173Sobrienstatic int
757116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
758116173Sobrien{
759116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
760116173Sobrien
761116173Sobrien	return (0);
762116173Sobrien}
763116173Sobrien
764116173Sobrien/*
765116173Sobrien * Filler function for proc/pid/maps
766116173Sobrien */
767116173Sobrienstatic int
768116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
769116173Sobrien{
770121265Scognet	char mebuffer[512];
771121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
772121246Scognet	vm_map_entry_t entry;
773121265Scognet	vm_object_t obj, tobj, lobj;
774121265Scognet	vm_ooffset_t off = 0;
775121265Scognet	char *name = "", *freename = NULL;
776121265Scognet	size_t len;
777121265Scognet	ino_t ino;
778121265Scognet	int ref_count, shadow_count, flags;
779121265Scognet	int error;
780137507Sphk	struct vnode *vp;
781137507Sphk	struct vattr vat;
782121246Scognet
783121246Scognet	PROC_LOCK(p);
784121246Scognet	error = p_candebug(td, p);
785121246Scognet	PROC_UNLOCK(p);
786121246Scognet	if (error)
787121246Scognet		return (error);
788121246Scognet
789121246Scognet	if (uio->uio_rw != UIO_READ)
790121246Scognet		return (EOPNOTSUPP);
791121246Scognet
792121246Scognet	if (uio->uio_offset != 0)
793121246Scognet		return (0);
794121246Scognet
795121246Scognet	error = 0;
796121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
797121246Scognet		vm_map_lock_read(map);
798121246Scognet        for (entry = map->header.next;
799121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
800121246Scognet	    entry = entry->next) {
801121265Scognet		name = "";
802121265Scognet		freename = NULL;
803121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
804121246Scognet			continue;
805121246Scognet		obj = entry->object.vm_object;
806121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
807121246Scognet			lobj = tobj;
808121246Scognet		ino = 0;
809121246Scognet		if (lobj) {
810137507Sphk			vp = lobj->handle;
811121246Scognet			VM_OBJECT_LOCK(lobj);
812121246Scognet			off = IDX_TO_OFF(lobj->size);
813121246Scognet			if (lobj->type == OBJT_VNODE && lobj->handle) {
814137507Sphk				vn_fullpath(td, vp, &name, &freename);
815137507Sphk				VOP_GETATTR(vp, &vat, td->td_ucred, td);
816137507Sphk				ino = vat.va_fileid;
817121246Scognet			}
818121246Scognet			flags = obj->flags;
819121246Scognet			ref_count = obj->ref_count;
820121246Scognet			shadow_count = obj->shadow_count;
821121246Scognet			VM_OBJECT_UNLOCK(lobj);
822121246Scognet		} else {
823121246Scognet			flags = 0;
824121246Scognet			ref_count = 0;
825121246Scognet			shadow_count = 0;
826121246Scognet		}
827121246Scognet
828121246Scognet		/*
829121246Scognet	     	 * format:
830121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
831121246Scognet		 */
832121246Scognet		snprintf(mebuffer, sizeof mebuffer,
833121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
834121246Scognet		    (u_long)entry->start, (u_long)entry->end,
835121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
836121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
837121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
838121246Scognet		    "p",
839121265Scognet		    (u_long)off,
840121246Scognet		    0,
841121246Scognet		    0,
842121265Scognet		    (u_long)ino,
843121246Scognet		    *name ? "     " : "",
844121246Scognet		    name
845121246Scognet		    );
846121246Scognet		if (freename)
847121246Scognet			free(freename, M_TEMP);
848121246Scognet		len = strlen(mebuffer);
849121246Scognet		if (len > uio->uio_resid)
850121246Scognet			len = uio->uio_resid; /*
851121246Scognet					       * XXX We should probably return
852121246Scognet					       * EFBIG here, as in procfs.
853121246Scognet					       */
854121246Scognet		error = uiomove(mebuffer, len, uio);
855121246Scognet		if (error)
856121246Scognet			break;
857121246Scognet	}
858121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
859121246Scognet		vm_map_unlock_read(map);
860121246Scognet
861121246Scognet	return (error);
862121246Scognet}
863121246Scognet
864116173Sobrien/*
86578113Sdes * Filler function for proc/net/dev
86678113Sdes */
86778025Sdesstatic int
86878025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
86974135Sjlemon{
87085129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
87174135Sjlemon	struct ifnet *ifp;
87274135Sjlemon
87385129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
87483926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
87585129Sdes	    "bytes    packets errs drop fifo frame compressed",
87683926Sdes	    "bytes    packets errs drop fifo frame compressed");
87774135Sjlemon
878108172Shsu	IFNET_RLOCK();
87974135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
88085129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
88185129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
88283926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
88383926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
88483926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
88583926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
88674135Sjlemon	}
887108172Shsu	IFNET_RUNLOCK();
888119068Sdes
88978025Sdes	return (0);
89074135Sjlemon}
89174135Sjlemon
892158311Sambrisko/*
893158311Sambrisko * Filler function for proc/scsi/device_info
894158311Sambrisko */
895158311Sambriskostatic int
896158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
897158311Sambrisko{
898158311Sambrisko	return (0);
899158311Sambrisko}
900158311Sambrisko
901158311Sambrisko/*
902158311Sambrisko * Filler function for proc/scsi/scsi
903158311Sambrisko */
904158311Sambriskostatic int
905158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
906158311Sambrisko{
907158311Sambrisko	return (0);
908158311Sambrisko}
909158311Sambrisko
91085538Sphkextern struct cdevsw *cdevsw[];
91185538Sphk
91278113Sdes/*
91378113Sdes * Filler function for proc/devices
91478113Sdes */
91578025Sdesstatic int
91678025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
91774135Sjlemon{
918158311Sambrisko	char *char_devices;
91978025Sdes	sbuf_printf(sb, "Character devices:\n");
92074135Sjlemon
921158311Sambrisko	char_devices = linux_get_char_devices();
922158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
923158311Sambrisko	linux_free_get_char_devices(char_devices);
92474135Sjlemon
92578025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
926119068Sdes
92778025Sdes	return (0);
92874135Sjlemon}
92974135Sjlemon
93078113Sdes/*
93178113Sdes * Filler function for proc/cmdline
93278113Sdes */
93378025Sdesstatic int
93478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
93574135Sjlemon{
93678025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
93778025Sdes	sbuf_printf(sb, " ro root=302\n");
93878025Sdes	return (0);
93978025Sdes}
94074135Sjlemon
94183926Sdes#if 0
94278025Sdes/*
94383926Sdes * Filler function for proc/modules
94483926Sdes */
94583926Sdesstatic int
94683926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
94783926Sdes{
94883926Sdes	struct linker_file *lf;
949119068Sdes
95083926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
95183926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
95283926Sdes		    (unsigned long)lf->size, lf->refs);
95383926Sdes	}
95483926Sdes	return (0);
95583926Sdes}
95683926Sdes#endif
95783926Sdes
95883926Sdes/*
95985129Sdes * Constructor
96078025Sdes */
96185129Sdesstatic int
96285129Sdeslinprocfs_init(PFS_INIT_ARGS)
96385129Sdes{
96485129Sdes	struct pfs_node *root;
96585129Sdes	struct pfs_node *dir;
96674135Sjlemon
96785129Sdes	root = pi->pi_root;
96878025Sdes
969119923Sdes	/* /proc/... */
970119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
971119911Sdes	    NULL, NULL, PFS_RD);
972119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
973119911Sdes	    NULL, NULL, PFS_RD);
974119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
975119911Sdes	    NULL, NULL, PFS_RD);
976119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
977119911Sdes	    NULL, NULL, PFS_RD);
978119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
979119911Sdes	    NULL, NULL, PFS_RD);
98083926Sdes#if 0
981119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
982119911Sdes	    NULL, NULL, PFS_RD);
98383926Sdes#endif
984158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
985158311Sambrisko	    NULL, NULL, PFS_RD);
986119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
987119911Sdes	    NULL, NULL, PFS_RD);
98887543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
98985129Sdes	    NULL, NULL, 0);
990119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
991119911Sdes	    NULL, NULL, PFS_RD);
992119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
993119911Sdes	    NULL, NULL, PFS_RD);
994119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
995119911Sdes	    NULL, NULL, PFS_RD);
99678025Sdes
997119923Sdes	/* /proc/net/... */
99885129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
99985129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
100085129Sdes	    NULL, NULL, PFS_RD);
100178025Sdes
1002119923Sdes	/* /proc/<pid>/... */
100385129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
100485129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
100585129Sdes	    NULL, NULL, PFS_RD);
1006119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1007119911Sdes	    NULL, NULL, 0);
1008116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1009116173Sobrien	    NULL, NULL, PFS_RD);
101087543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
101187543Sdes	    NULL, &procfs_notsystem, 0);
1012116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1013116173Sobrien	    NULL, NULL, PFS_RD);
101485129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
101585129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1016119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1017119911Sdes	    NULL, NULL, 0);
101885129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
101985129Sdes	    NULL, NULL, PFS_RD);
1020119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1021119911Sdes	    NULL, NULL, PFS_RD);
102285129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
102385129Sdes	    NULL, NULL, PFS_RD);
102485129Sdes
1025158311Sambrisko	/* /proc/scsi/... */
1026158311Sambrisko	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1027158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1028158311Sambrisko	    NULL, NULL, PFS_RD);
1029158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1030158311Sambrisko	    NULL, NULL, PFS_RD);
103185129Sdes	return (0);
103285129Sdes}
103385129Sdes
103485129Sdes/*
103585129Sdes * Destructor
103685129Sdes */
103785129Sdesstatic int
103885129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
103985129Sdes{
104085129Sdes
104185129Sdes	/* nothing to do, pseudofs will GC */
104285129Sdes	return (0);
104385129Sdes}
104485129Sdes
104585129SdesPSEUDOFS(linprocfs, 1);
104678025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
104778025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1048