linprocfs.c revision 168067
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 168067 2007-03-30 17:56:44Z jkim $");
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>
57168067Sjkim#include <sys/msg.h>
5876827Salfred#include <sys/mutex.h>
5985289Sdes#include <sys/namei.h>
6065633Sdes#include <sys/proc.h>
6165633Sdes#include <sys/resourcevar.h>
6269995Sdes#include <sys/sbuf.h>
63168067Sjkim#include <sys/sem.h>
64123246Sdes#include <sys/smp.h>
6583926Sdes#include <sys/socket.h>
6676839Sjlemon#include <sys/sysctl.h>
6783926Sdes#include <sys/systm.h>
68159995Snetchild#include <sys/time.h>
6965633Sdes#include <sys/tty.h>
7083926Sdes#include <sys/user.h>
7183926Sdes#include <sys/vmmeter.h>
7259412Smsmith#include <sys/vnode.h>
7359412Smsmith
7483926Sdes#include <net/if.h>
7583926Sdes
7659412Smsmith#include <vm/vm.h>
7759412Smsmith#include <vm/pmap.h>
7867588Sdes#include <vm/vm_map.h>
7959412Smsmith#include <vm/vm_param.h>
8060860Sdes#include <vm/vm_object.h>
8159412Smsmith#include <vm/swap_pager.h>
8269799Sdes
8367589Sdes#include <machine/clock.h>
8478113Sdes
85133822Stjr#if defined(__i386__) || defined(__amd64__)
8667589Sdes#include <machine/cputypes.h>
8759412Smsmith#include <machine/md_var.h>
88133822Stjr#endif /* __i386__ || __amd64__ */
8959412Smsmith
90133822Stjr#include "opt_compat.h"
91140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
92140214Sobrien#include <machine/../linux32/linux.h>
93140214Sobrien#else
9487275Srwatson#include <machine/../linux/linux.h>
95133822Stjr#endif
9685129Sdes#include <compat/linux/linux_ioctl.h>
9769995Sdes#include <compat/linux/linux_mib.h>
9885289Sdes#include <compat/linux/linux_util.h>
9978025Sdes#include <fs/pseudofs/pseudofs.h>
10084248Sdes#include <fs/procfs/procfs.h>
10159412Smsmith
10267588Sdes/*
10367588Sdes * Various conversion macros
10467588Sdes */
10576405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10667588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10767588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10869799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10967588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11067588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11174135Sjlemon
112159995Snetchild/**
113159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
114159995Snetchild *
115159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
116159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
117159995Snetchild * uninteruptible disk sleep, a zombie process, process is being traced
118159995Snetchild * or stopped, or process is paging respectively.
119159995Snetchild *
120159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
121159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
122159995Snetchild *
123159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
124159995Snetchild * map our states to suitable linux states.
125159995Snetchild */
126166140Snetchildstatic char linux_state[] = "RRSTZDD";
127159995Snetchild
12878113Sdes/*
12978113Sdes * Filler function for proc/meminfo
13078113Sdes */
13178025Sdesstatic int
13278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13359412Smsmith{
13459412Smsmith	unsigned long memtotal;		/* total memory in bytes */
13559412Smsmith	unsigned long memused;		/* used memory in bytes */
13659412Smsmith	unsigned long memfree;		/* free memory in bytes */
13759412Smsmith	unsigned long memshared;	/* shared memory ??? */
13859412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
139113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
140113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
141113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14260860Sdes	vm_object_t object;
143117723Sphk	int i, j;
14459412Smsmith
14559412Smsmith	memtotal = physmem * PAGE_SIZE;
14659412Smsmith	/*
14759412Smsmith	 * The correct thing here would be:
14859412Smsmith	 *
14959412Smsmith	memfree = cnt.v_free_count * PAGE_SIZE;
15059412Smsmith	memused = memtotal - memfree;
15159412Smsmith	 *
15259412Smsmith	 * but it might mislead linux binaries into thinking there
15359412Smsmith	 * is very little memory left, so we cheat and tell them that
15459412Smsmith	 * all memory that isn't wired down is free.
15559412Smsmith	 */
15659412Smsmith	memused = cnt.v_wire_count * PAGE_SIZE;
15759412Smsmith	memfree = memtotal - memused;
158117723Sphk	swap_pager_status(&i, &j);
159153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
160153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
161117723Sphk	swapfree = swaptotal - swapused;
16260860Sdes	memshared = 0;
163124082Salc	mtx_lock(&vm_object_list_mtx);
16471471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
16560860Sdes		if (object->shadow_count > 1)
16660860Sdes			memshared += object->resident_page_count;
167124082Salc	mtx_unlock(&vm_object_list_mtx);
16860860Sdes	memshared *= PAGE_SIZE;
16959412Smsmith	/*
17059412Smsmith	 * We'd love to be able to write:
17159412Smsmith	 *
17259412Smsmith	buffers = bufspace;
17359412Smsmith	 *
17459412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
17559412Smsmith	 * like unstaticizing it just for linprocfs's sake.
17659412Smsmith	 */
17759412Smsmith	buffers = 0;
17859412Smsmith	cached = cnt.v_cache_count * PAGE_SIZE;
17959412Smsmith
18078025Sdes	sbuf_printf(sb,
18178031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18269799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18376839Sjlemon	    "Swap: %llu %llu %llu\n"
18469799Sdes	    "MemTotal: %9lu kB\n"
18569799Sdes	    "MemFree:  %9lu kB\n"
18669799Sdes	    "MemShared:%9lu kB\n"
18769799Sdes	    "Buffers:  %9lu kB\n"
18869799Sdes	    "Cached:   %9lu kB\n"
18976839Sjlemon	    "SwapTotal:%9llu kB\n"
19076839Sjlemon	    "SwapFree: %9llu kB\n",
19169799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19269799Sdes	    swaptotal, swapused, swapfree,
19369799Sdes	    B2K(memtotal), B2K(memfree),
19469799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
19569799Sdes	    B2K(swaptotal), B2K(swapfree));
19659412Smsmith
19778025Sdes	return (0);
19859412Smsmith}
19959412Smsmith
200133822Stjr#if defined(__i386__) || defined(__amd64__)
20178113Sdes/*
202133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20378113Sdes */
20478113Sdesstatic int
20578113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
20678113Sdes{
207159544Sdes	int hw_model[2];
208159544Sdes	char model[128];
209159544Sdes	size_t size;
210123246Sdes	int class, fqmhz, fqkhz;
211118421Sdes	int i;
21259412Smsmith
21369799Sdes	/*
21478031Sdes	 * We default the flags to include all non-conflicting flags,
21578031Sdes	 * and the Intel versions of conflicting flags.
21669799Sdes	 */
21778031Sdes	static char *flags[] = {
21878031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
21978031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22078031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22178031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22278031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22378031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22467589Sdes		"3dnowext", "3dnow"
22567589Sdes	};
22667589Sdes
22759412Smsmith	switch (cpu_class) {
228133822Stjr#ifdef __i386__
22959412Smsmith	case CPUCLASS_286:
23067589Sdes		class = 2;
23159412Smsmith		break;
23259412Smsmith	case CPUCLASS_386:
23367589Sdes		class = 3;
23459412Smsmith		break;
23559412Smsmith	case CPUCLASS_486:
23667589Sdes		class = 4;
23759412Smsmith		break;
23859412Smsmith	case CPUCLASS_586:
23967589Sdes		class = 5;
24059412Smsmith		break;
24159412Smsmith	case CPUCLASS_686:
24267589Sdes		class = 6;
24359412Smsmith		break;
24459412Smsmith	default:
24578031Sdes		class = 0;
24659412Smsmith		break;
247159170Sdes#else /* __amd64__ */
248133822Stjr	default:
249159170Sdes		class = 15;
250133822Stjr		break;
251133822Stjr#endif
25259412Smsmith	}
25359412Smsmith
254159544Sdes	hw_model[0] = CTL_HW;
255159544Sdes	hw_model[1] = HW_MODEL;
256159544Sdes	model[0] = '\0';
257159544Sdes	size = sizeof(model);
258159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
259159544Sdes		strcpy(model, "unknown");
260123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
261118421Sdes		sbuf_printf(sb,
262118421Sdes		    "processor\t: %d\n"
263118421Sdes		    "vendor_id\t: %.20s\n"
264118421Sdes		    "cpu family\t: %d\n"
265118421Sdes		    "model\t\t: %d\n"
266159544Sdes		    "model name\t: %s\n"
267118421Sdes		    "stepping\t: %d\n",
268159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
269159544Sdes		/* XXX per-cpu vendor / class / model / id? */
270118421Sdes	}
27159412Smsmith
27278031Sdes	sbuf_cat(sb,
27378031Sdes	    "flags\t\t:");
27467589Sdes
27578031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
27667589Sdes		flags[16] = "fcmov";
27778031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
27867589Sdes		flags[24] = "cxmmx";
27978031Sdes	}
280119068Sdes
28178031Sdes	for (i = 0; i < 32; i++)
28267589Sdes		if (cpu_feature & (1 << i))
28378025Sdes			sbuf_printf(sb, " %s", flags[i]);
28478025Sdes	sbuf_cat(sb, "\n");
28578031Sdes	if (class >= 5) {
28669799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
28769799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
28878025Sdes		sbuf_printf(sb,
28969799Sdes		    "cpu MHz\t\t: %d.%02d\n"
29069799Sdes		    "bogomips\t: %d.%02d\n",
29169799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
29278031Sdes	}
29369995Sdes
29478025Sdes	return (0);
29559412Smsmith}
296133822Stjr#endif /* __i386__ || __amd64__ */
29765633Sdes
29878113Sdes/*
29985289Sdes * Filler function for proc/mtab
30085289Sdes *
30185289Sdes * This file doesn't exist in Linux' procfs, but is included here so
30285289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
30385289Sdes */
30485289Sdesstatic int
30585289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
30685289Sdes{
30785289Sdes	struct nameidata nd;
30885289Sdes	struct mount *mp;
30991334Sjulian	const char *lep;
31091334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
31185289Sdes	size_t lep_len;
31285289Sdes	int error;
31385289Sdes
31485289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
31585289Sdes	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
31685289Sdes	flep = NULL;
317124407Srwatson	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
31885289Sdes		lep = linux_emul_path;
31991334Sjulian	else
32091334Sjulian		lep = dlep;
32185289Sdes	lep_len = strlen(lep);
322119068Sdes
32385289Sdes	mtx_lock(&mountlist_mtx);
32485289Sdes	error = 0;
32585289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
32685289Sdes		/* determine device name */
32785289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
328119068Sdes
32985289Sdes		/* determine mount point */
33085289Sdes		mntto = mp->mnt_stat.f_mntonname;
33185289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
33285289Sdes		    mntto[lep_len] == '/')
33385289Sdes			mntto += lep_len;
33485289Sdes
33585289Sdes		/* determine fs type */
33685289Sdes		fstype = mp->mnt_stat.f_fstypename;
33785289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
33885289Sdes			mntfrom = fstype = "proc";
33985289Sdes		else if (strcmp(fstype, "procfs") == 0)
34085289Sdes			continue;
341119068Sdes
342158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
343158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
344158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
345158311Sambrisko		} else {
346158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
347158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
348158311Sambrisko		}
34985289Sdes#define ADD_OPTION(opt, name) \
35085289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
35185289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
35285289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
35385289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
35485289Sdes		ADD_OPTION(MNT_UNION,		"union");
35585289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
35685289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
35785289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
35885289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
35985289Sdes#undef ADD_OPTION
36085289Sdes		/* a real Linux mtab will also show NFS options */
36185289Sdes		sbuf_printf(sb, " 0 0\n");
36285289Sdes	}
36385289Sdes	mtx_unlock(&mountlist_mtx);
36485289Sdes	if (flep != NULL)
36585289Sdes		free(flep, M_TEMP);
36685289Sdes	return (error);
36785289Sdes}
36885289Sdes
36985289Sdes/*
37078113Sdes * Filler function for proc/stat
37178113Sdes */
37278025Sdesstatic int
37378025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
37465633Sdes{
375123246Sdes	int i;
376120339Sdes
377120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
378120339Sdes	    T2J(cp_time[CP_USER]),
379120339Sdes	    T2J(cp_time[CP_NICE]),
380120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
381120339Sdes	    T2J(cp_time[CP_IDLE]));
382143194Ssobomax	for (i = 0; i < mp_ncpus; ++i)
383143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
384143194Ssobomax		    T2J(cp_time[CP_USER]) / mp_ncpus,
385143194Ssobomax		    T2J(cp_time[CP_NICE]) / mp_ncpus,
386143194Ssobomax		    T2J(cp_time[CP_SYS]) / mp_ncpus,
387143194Ssobomax		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
38878025Sdes	sbuf_printf(sb,
38969799Sdes	    "disk 0 0 0 0\n"
39069799Sdes	    "page %u %u\n"
39169799Sdes	    "swap %u %u\n"
39269799Sdes	    "intr %u\n"
39369799Sdes	    "ctxt %u\n"
39485657Sdillon	    "btime %lld\n",
39569799Sdes	    cnt.v_vnodepgsin,
39669799Sdes	    cnt.v_vnodepgsout,
39769799Sdes	    cnt.v_swappgsin,
39869799Sdes	    cnt.v_swappgsout,
39969799Sdes	    cnt.v_intr,
40069799Sdes	    cnt.v_swtch,
401113574Sjhb	    (long long)boottime.tv_sec);
40278025Sdes	return (0);
40365633Sdes}
40465633Sdes
40578113Sdes/*
40678113Sdes * Filler function for proc/uptime
40778113Sdes */
40878025Sdesstatic int
40978025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
41065633Sdes{
41165633Sdes	struct timeval tv;
41265633Sdes
41365633Sdes	getmicrouptime(&tv);
41485657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
415113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
41669799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
41778025Sdes	return (0);
41865633Sdes}
41965633Sdes
42078113Sdes/*
421167159Sjkim * Get OS build date
422167159Sjkim */
423167159Sjkimstatic void
424167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
425167159Sjkim{
426167159Sjkim#if 0
427167159Sjkim	char osbuild[256];
428167159Sjkim	char *cp1, *cp2;
429167159Sjkim
430167159Sjkim	strncpy(osbuild, version, 256);
431167159Sjkim	osbuild[255] = '\0';
432167159Sjkim	cp1 = strstr(osbuild, "\n");
433167159Sjkim	cp2 = strstr(osbuild, ":");
434167159Sjkim	if (cp1 && cp2) {
435167159Sjkim		*cp1 = *cp2 = '\0';
436167159Sjkim		cp1 = strstr(osbuild, "#");
437167159Sjkim	} else
438167159Sjkim		cp1 = NULL;
439167159Sjkim	if (cp1)
440167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
441167159Sjkim	else
442167159Sjkim#endif
443167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
444167159Sjkim}
445167159Sjkim
446167159Sjkim/*
447167159Sjkim * Get OS builder
448167159Sjkim */
449167159Sjkimstatic void
450167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
451167159Sjkim{
452167159Sjkim	char builder[256];
453167159Sjkim	char *cp;
454167159Sjkim
455167159Sjkim	cp = strstr(version, "\n    ");
456167159Sjkim	if (cp) {
457167159Sjkim		strncpy(builder, cp + 5, 256);
458167159Sjkim		builder[255] = '\0';
459167159Sjkim		cp = strstr(builder, ":");
460167159Sjkim		if (cp)
461167159Sjkim			*cp = '\0';
462167159Sjkim	}
463167159Sjkim	if (cp)
464167159Sjkim		sbuf_cat(sb, builder);
465167159Sjkim	else
466167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
467167159Sjkim}
468167159Sjkim
469167159Sjkim/*
47078113Sdes * Filler function for proc/version
47178113Sdes */
47278025Sdesstatic int
47378025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
47465633Sdes{
47587275Srwatson	char osname[LINUX_MAX_UTSNAME];
47687275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
47787275Srwatson
478112206Sjhb	linux_get_osname(td, osname);
479112206Sjhb	linux_get_osrelease(td, osrelease);
480167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
481167159Sjkim	linprocfs_osbuilder(td, sb);
482167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
483167159Sjkim	linprocfs_osbuild(td, sb);
484167159Sjkim	sbuf_cat(sb, "\n");
48587275Srwatson
48678025Sdes	return (0);
48765633Sdes}
48865633Sdes
48978113Sdes/*
49078113Sdes * Filler function for proc/loadavg
49178113Sdes */
49278025Sdesstatic int
49378025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
49476839Sjlemon{
49578025Sdes	sbuf_printf(sb,
49676839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
49776839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
49876839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
49976839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
50076839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
50176839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
50276839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
50376839Sjlemon	    1,				/* number of running tasks */
50476839Sjlemon	    nprocs,			/* number of tasks */
50578116Sdes	    lastpid			/* the last pid */
50676839Sjlemon	);
507119068Sdes
50878025Sdes	return (0);
50976839Sjlemon}
51076839Sjlemon
51178113Sdes/*
51278113Sdes * Filler function for proc/pid/stat
51378113Sdes */
51478025Sdesstatic int
51578025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
51667588Sdes{
51769995Sdes	struct kinfo_proc kp;
518166140Snetchild	char state;
519166140Snetchild	static int ratelimit = 0;
52067588Sdes
52194307Sjhb	PROC_LOCK(p);
52269995Sdes	fill_kinfo_proc(p, &kp);
52378025Sdes	sbuf_printf(sb, "%d", p->p_pid);
52478025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
52567588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
526166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
527166140Snetchild		state = 'R';
528166140Snetchild
529166141Snetchild		if (ratelimit == 0) {
530166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
531166162Snetchild			    kp.ki_stat, sizeof(linux_state));
532166141Snetchild			++ratelimit;
533166141Snetchild		}
534166140Snetchild	} else
535166140Snetchild		state = linux_state[kp.ki_stat - 1];
536166140Snetchild	PS_ADD("state",		"%c",	state);
53773923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
53867588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
53967588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
54091140Stanimura	PROC_UNLOCK(p);
54167588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
542159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
54367588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
544159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
545159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
546159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
547159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
548159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
549159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
550159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
551159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
552159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
553159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
554159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
555159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
556159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
557159995Snetchild	   It should be the number of jiffies between system boot and process
558159995Snetchild	   start. */
559159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
560159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
561159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
562159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
56369995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
56467588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
56567588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
566159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
567159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
568159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
569159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
570159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
571159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
57267588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
573159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
574159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
57569799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
576159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
577159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
578159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
57967588Sdes#undef PS_ADD
58078025Sdes	sbuf_putc(sb, '\n');
581119068Sdes
58278025Sdes	return (0);
58367588Sdes}
58467588Sdes
58567588Sdes/*
586119911Sdes * Filler function for proc/pid/statm
587119911Sdes */
588119911Sdesstatic int
589119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
590119911Sdes{
591119911Sdes	struct kinfo_proc kp;
592119911Sdes	segsz_t lsize;
593120340Sdes
594119911Sdes	PROC_LOCK(p);
595119911Sdes	fill_kinfo_proc(p, &kp);
596119911Sdes	PROC_UNLOCK(p);
597119911Sdes
598119911Sdes	/*
599119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
600119911Sdes	 * computation of lsize.
601119911Sdes	 */
602119911Sdes	/* size resident share trs drs lrs dt */
603119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
604119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
605119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
606119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
607119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
608119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
609119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
610119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
611119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
612119911Sdes
613119911Sdes	return (0);
614119911Sdes}
615119911Sdes
616119911Sdes/*
61778113Sdes * Filler function for proc/pid/status
61878113Sdes */
61978025Sdesstatic int
62078025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
62167588Sdes{
62269995Sdes	struct kinfo_proc kp;
62367588Sdes	char *state;
62469799Sdes	segsz_t lsize;
62599072Sjulian	struct thread *td2;
626114983Sjhb	struct sigacts *ps;
62774135Sjlemon	int i;
62867588Sdes
629113611Sjhb	PROC_LOCK(p);
63099072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
63199072Sjulian
63299072Sjulian	if (P_SHOULDSTOP(p)) {
63399072Sjulian		state = "T (stopped)";
63499072Sjulian	} else {
635113611Sjhb		mtx_lock_spin(&sched_lock);
63699072Sjulian		switch(p->p_state) {
63799072Sjulian		case PRS_NEW:
63899072Sjulian			state = "I (idle)";
63999072Sjulian			break;
64099072Sjulian		case PRS_NORMAL:
64199072Sjulian			if (p->p_flag & P_WEXIT) {
64299072Sjulian				state = "X (exiting)";
64399072Sjulian				break;
64499072Sjulian			}
64599072Sjulian			switch(td2->td_state) {
646103216Sjulian			case TDS_INHIBITED:
64799072Sjulian				state = "S (sleeping)";
64899072Sjulian				break;
64999072Sjulian			case TDS_RUNQ:
65099072Sjulian			case TDS_RUNNING:
65199072Sjulian				state = "R (running)";
65299072Sjulian				break;
65399072Sjulian			default:
65499072Sjulian				state = "? (unknown)";
65599072Sjulian				break;
65699072Sjulian			}
65799072Sjulian			break;
65899072Sjulian		case PRS_ZOMBIE:
65999072Sjulian			state = "Z (zombie)";
66099072Sjulian			break;
66199072Sjulian		default:
66299072Sjulian			state = "? (unknown)";
66399072Sjulian			break;
66499072Sjulian		}
665113611Sjhb		mtx_unlock_spin(&sched_lock);
66699072Sjulian	}
66767588Sdes
66869995Sdes	fill_kinfo_proc(p, &kp);
66978025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
67078031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
67167588Sdes
67267588Sdes	/*
67367588Sdes	 * Credentials
67467588Sdes	 */
67578025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
67678025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
67773923Sjhb						p->p_pptr->p_pid : 0);
67878031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
67978031Sdes						p->p_ucred->cr_uid,
68078031Sdes						p->p_ucred->cr_svuid,
68178031Sdes						/* FreeBSD doesn't have fsuid */
68278031Sdes						p->p_ucred->cr_uid);
68378031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
68478031Sdes						p->p_ucred->cr_gid,
68578031Sdes						p->p_ucred->cr_svgid,
68678031Sdes						/* FreeBSD doesn't have fsgid */
68778031Sdes						p->p_ucred->cr_gid);
68878025Sdes	sbuf_cat(sb, "Groups:\t");
68967588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
69078031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
69171471Sjhb	PROC_UNLOCK(p);
69278025Sdes	sbuf_putc(sb, '\n');
693119068Sdes
69467588Sdes	/*
69567588Sdes	 * Memory
69669799Sdes	 *
69769799Sdes	 * While our approximation of VmLib may not be accurate (I
69869799Sdes	 * don't know of a simple way to verify it, and I'm not sure
69969799Sdes	 * it has much meaning anyway), I believe it's good enough.
70069799Sdes	 *
70169799Sdes	 * The same code that could (I think) accurately compute VmLib
70269799Sdes	 * could also compute VmLck, but I don't really care enough to
70369799Sdes	 * implement it. Submissions are welcome.
70467588Sdes	 */
705113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
70678025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
707113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
708113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
709113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
710113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
71169995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
71269995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
713113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
71467588Sdes
71567588Sdes	/*
71667588Sdes	 * Signal masks
71767588Sdes	 *
71867588Sdes	 * We support up to 128 signals, while Linux supports 32,
71967588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
72067588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
72167588Sdes	 *
72267588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
72367588Sdes	 * supports 64 signals, but this code is a long way from
72467588Sdes	 * running on anything but i386, so ignore that for now.
72567588Sdes	 */
72671471Sjhb	PROC_LOCK(p);
727104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
72869799Sdes	/*
72969799Sdes	 * I can't seem to find out where the signal mask is in
73069799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
73169799Sdes	 */
73278025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
733114983Sjhb	ps = p->p_sigacts;
734114983Sjhb	mtx_lock(&ps->ps_mtx);
735114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
736114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
737114983Sjhb	mtx_unlock(&ps->ps_mtx);
73871471Sjhb	PROC_UNLOCK(p);
739119068Sdes
74067588Sdes	/*
74167588Sdes	 * Linux also prints the capability masks, but we don't have
74267588Sdes	 * capabilities yet, and when we do get them they're likely to
74367588Sdes	 * be meaningless to Linux programs, so we lie. XXX
74467588Sdes	 */
74578025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
74678025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
74778025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
748119068Sdes
74978025Sdes	return (0);
75067588Sdes}
75174135Sjlemon
752119911Sdes
75378113Sdes/*
754119911Sdes * Filler function for proc/pid/cwd
755119911Sdes */
756119911Sdesstatic int
757119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
758119911Sdes{
759119911Sdes	char *fullpath = "unknown";
760119911Sdes	char *freepath = NULL;
761119911Sdes
762119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
763119911Sdes	sbuf_printf(sb, "%s", fullpath);
764119911Sdes	if (freepath)
765119911Sdes		free(freepath, M_TEMP);
766119911Sdes	return (0);
767119911Sdes}
768119911Sdes
769119911Sdes/*
770119911Sdes * Filler function for proc/pid/root
771119911Sdes */
772119911Sdesstatic int
773119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
774119911Sdes{
775119911Sdes	struct vnode *rvp;
776119911Sdes	char *fullpath = "unknown";
777119911Sdes	char *freepath = NULL;
778119911Sdes
779119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
780119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
781119911Sdes	sbuf_printf(sb, "%s", fullpath);
782119911Sdes	if (freepath)
783119911Sdes		free(freepath, M_TEMP);
784119911Sdes	return (0);
785119911Sdes}
786119911Sdes
787119911Sdes/*
78878113Sdes * Filler function for proc/pid/cmdline
78978113Sdes */
79078025Sdesstatic int
79178113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
79278113Sdes{
79378113Sdes	struct ps_strings pstr;
794138281Scperciva	char **ps_argvstr;
79578113Sdes	int error, i;
79678113Sdes
79778113Sdes	/*
79878113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
79978113Sdes	 * revert back to the old way which only implements full cmdline
80078113Sdes	 * for the currept process and just p->p_comm for all other
80178113Sdes	 * processes.
80278113Sdes	 * Note that if the argv is no longer available, we deliberately
80378113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
80478113Sdes	 * Linux behaviour is to return zero-length in this case.
80578113Sdes	 */
80678113Sdes
80794620Sjhb	PROC_LOCK(p);
808127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
80994620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
81094620Sjhb		PROC_UNLOCK(p);
81194620Sjhb	} else if (p != td->td_proc) {
81294620Sjhb		PROC_UNLOCK(p);
81394620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
81494620Sjhb	} else {
81594620Sjhb		PROC_UNLOCK(p);
816103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
817103767Sjake		    sizeof(pstr));
81894620Sjhb		if (error)
81994620Sjhb			return (error);
820138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
821138281Scperciva			return (E2BIG);
822138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
823138281Scperciva		    M_TEMP, M_WAITOK);
824138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
825138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
826138281Scperciva		if (error) {
827138281Scperciva			free(ps_argvstr, M_TEMP);
828138281Scperciva			return (error);
829138281Scperciva		}
83094620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
831138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
83294620Sjhb			sbuf_printf(sb, "%c", '\0');
83378113Sdes		}
834138281Scperciva		free(ps_argvstr, M_TEMP);
83578113Sdes	}
83678113Sdes
83778113Sdes	return (0);
83878113Sdes}
83978113Sdes
84078113Sdes/*
841116173Sobrien * Filler function for proc/pid/environ
842116173Sobrien */
843116173Sobrienstatic int
844116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
845116173Sobrien{
846116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
847116173Sobrien
848116173Sobrien	return (0);
849116173Sobrien}
850116173Sobrien
851116173Sobrien/*
852116173Sobrien * Filler function for proc/pid/maps
853116173Sobrien */
854116173Sobrienstatic int
855116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
856116173Sobrien{
857121265Scognet	char mebuffer[512];
858121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
859121246Scognet	vm_map_entry_t entry;
860121265Scognet	vm_object_t obj, tobj, lobj;
861121265Scognet	vm_ooffset_t off = 0;
862121265Scognet	char *name = "", *freename = NULL;
863121265Scognet	size_t len;
864121265Scognet	ino_t ino;
865121265Scognet	int ref_count, shadow_count, flags;
866121265Scognet	int error;
867137507Sphk	struct vnode *vp;
868137507Sphk	struct vattr vat;
869161094Skib	int locked;
870121246Scognet
871121246Scognet	PROC_LOCK(p);
872121246Scognet	error = p_candebug(td, p);
873121246Scognet	PROC_UNLOCK(p);
874121246Scognet	if (error)
875121246Scognet		return (error);
876121246Scognet
877121246Scognet	if (uio->uio_rw != UIO_READ)
878121246Scognet		return (EOPNOTSUPP);
879121246Scognet
880121246Scognet	if (uio->uio_offset != 0)
881121246Scognet		return (0);
882121246Scognet
883121246Scognet	error = 0;
884121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
885121246Scognet		vm_map_lock_read(map);
886121246Scognet        for (entry = map->header.next;
887121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
888121246Scognet	    entry = entry->next) {
889121265Scognet		name = "";
890121265Scognet		freename = NULL;
891121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
892121246Scognet			continue;
893121246Scognet		obj = entry->object.vm_object;
894121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
895121246Scognet			lobj = tobj;
896121246Scognet		ino = 0;
897121246Scognet		if (lobj) {
898121246Scognet			VM_OBJECT_LOCK(lobj);
899121246Scognet			off = IDX_TO_OFF(lobj->size);
900161094Skib			if (lobj->type == OBJT_VNODE) {
901161094Skib				vp = lobj->handle;
902161094Skib				if (vp)
903161094Skib					vref(vp);
904121246Scognet			}
905161094Skib			else
906161094Skib				vp = NULL;
907121246Scognet			flags = obj->flags;
908121246Scognet			ref_count = obj->ref_count;
909121246Scognet			shadow_count = obj->shadow_count;
910121246Scognet			VM_OBJECT_UNLOCK(lobj);
911161094Skib			if (vp) {
912161094Skib				vn_fullpath(td, vp, &name, &freename);
913161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
914161094Skib				vn_lock(vp, LK_SHARED | LK_RETRY, td);
915161094Skib				VOP_GETATTR(vp, &vat, td->td_ucred, td);
916161094Skib				ino = vat.va_fileid;
917161094Skib				vput(vp);
918161094Skib				VFS_UNLOCK_GIANT(locked);
919161094Skib			}
920121246Scognet		} else {
921121246Scognet			flags = 0;
922121246Scognet			ref_count = 0;
923121246Scognet			shadow_count = 0;
924121246Scognet		}
925121246Scognet
926121246Scognet		/*
927121246Scognet	     	 * format:
928121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
929121246Scognet		 */
930121246Scognet		snprintf(mebuffer, sizeof mebuffer,
931121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
932121246Scognet		    (u_long)entry->start, (u_long)entry->end,
933121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
934121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
935121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
936121246Scognet		    "p",
937121265Scognet		    (u_long)off,
938121246Scognet		    0,
939121246Scognet		    0,
940121265Scognet		    (u_long)ino,
941121246Scognet		    *name ? "     " : "",
942121246Scognet		    name
943121246Scognet		    );
944121246Scognet		if (freename)
945121246Scognet			free(freename, M_TEMP);
946121246Scognet		len = strlen(mebuffer);
947121246Scognet		if (len > uio->uio_resid)
948121246Scognet			len = uio->uio_resid; /*
949121246Scognet					       * XXX We should probably return
950121246Scognet					       * EFBIG here, as in procfs.
951121246Scognet					       */
952121246Scognet		error = uiomove(mebuffer, len, uio);
953121246Scognet		if (error)
954121246Scognet			break;
955121246Scognet	}
956121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
957121246Scognet		vm_map_unlock_read(map);
958121246Scognet
959121246Scognet	return (error);
960121246Scognet}
961121246Scognet
962116173Sobrien/*
96378113Sdes * Filler function for proc/net/dev
96478113Sdes */
96578025Sdesstatic int
96678025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
96774135Sjlemon{
96885129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
96974135Sjlemon	struct ifnet *ifp;
97074135Sjlemon
97185129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
97283926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
97385129Sdes	    "bytes    packets errs drop fifo frame compressed",
97483926Sdes	    "bytes    packets errs drop fifo frame compressed");
97574135Sjlemon
976108172Shsu	IFNET_RLOCK();
97774135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
97885129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
97985129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
98083926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
98183926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
98283926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
98383926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
98474135Sjlemon	}
985108172Shsu	IFNET_RUNLOCK();
986119068Sdes
98778025Sdes	return (0);
98874135Sjlemon}
98974135Sjlemon
990158311Sambrisko/*
991167159Sjkim * Filler function for proc/sys/kernel/osrelease
992167159Sjkim */
993167159Sjkimstatic int
994167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
995167159Sjkim{
996167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
997167159Sjkim
998167159Sjkim	linux_get_osrelease(td, osrelease);
999167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1000167159Sjkim
1001167159Sjkim	return (0);
1002167159Sjkim}
1003167159Sjkim
1004167159Sjkim/*
1005167159Sjkim * Filler function for proc/sys/kernel/ostype
1006167159Sjkim */
1007167159Sjkimstatic int
1008167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1009167159Sjkim{
1010167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1011167159Sjkim
1012167159Sjkim	linux_get_osname(td, osname);
1013167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1014167159Sjkim
1015167159Sjkim	return (0);
1016167159Sjkim}
1017167159Sjkim
1018167159Sjkim/*
1019167159Sjkim * Filler function for proc/sys/kernel/version
1020167159Sjkim */
1021167159Sjkimstatic int
1022167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1023167159Sjkim{
1024167159Sjkim	linprocfs_osbuild(td, sb);
1025167159Sjkim	sbuf_cat(sb, "\n");
1026167159Sjkim
1027167159Sjkim	return (0);
1028167159Sjkim}
1029167159Sjkim
1030167159Sjkim/*
1031164692Sjkim * Filler function for proc/sys/kernel/msgmni
1032164692Sjkim */
1033164692Sjkimstatic int
1034164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1035164692Sjkim{
1036164692Sjkim
1037168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1038164692Sjkim
1039164692Sjkim	return (0);
1040164692Sjkim}
1041164692Sjkim
1042164692Sjkim/*
1043163251Skeramida * Filler function for proc/sys/kernel/pid_max
1044163129Snetchild */
1045163129Snetchildstatic int
1046163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1047163129Snetchild{
1048163757Snetchild
1049163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1050163129Snetchild
1051163129Snetchild	return (0);
1052163129Snetchild}
1053163129Snetchild
1054163129Snetchild/*
1055164692Sjkim * Filler function for proc/sys/kernel/sem
1056164692Sjkim */
1057164692Sjkimstatic int
1058164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1059164692Sjkim{
1060164692Sjkim
1061168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1062168067Sjkim	    seminfo.semopm, seminfo.semmni);
1063164692Sjkim
1064164692Sjkim	return (0);
1065164692Sjkim}
1066164692Sjkim
1067164692Sjkim/*
1068158311Sambrisko * Filler function for proc/scsi/device_info
1069158311Sambrisko */
1070158311Sambriskostatic int
1071158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1072158311Sambrisko{
1073158311Sambrisko	return (0);
1074158311Sambrisko}
1075158311Sambrisko
1076158311Sambrisko/*
1077158311Sambrisko * Filler function for proc/scsi/scsi
1078158311Sambrisko */
1079158311Sambriskostatic int
1080158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1081158311Sambrisko{
1082158311Sambrisko	return (0);
1083158311Sambrisko}
1084158311Sambrisko
108585538Sphkextern struct cdevsw *cdevsw[];
108685538Sphk
108778113Sdes/*
108878113Sdes * Filler function for proc/devices
108978113Sdes */
109078025Sdesstatic int
109178025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
109274135Sjlemon{
1093158311Sambrisko	char *char_devices;
109478025Sdes	sbuf_printf(sb, "Character devices:\n");
109574135Sjlemon
1096158311Sambrisko	char_devices = linux_get_char_devices();
1097158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1098158311Sambrisko	linux_free_get_char_devices(char_devices);
109974135Sjlemon
110078025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1101119068Sdes
110278025Sdes	return (0);
110374135Sjlemon}
110474135Sjlemon
110578113Sdes/*
110678113Sdes * Filler function for proc/cmdline
110778113Sdes */
110878025Sdesstatic int
110978025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
111074135Sjlemon{
111178025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
111278025Sdes	sbuf_printf(sb, " ro root=302\n");
111378025Sdes	return (0);
111478025Sdes}
111574135Sjlemon
111683926Sdes#if 0
111778025Sdes/*
111883926Sdes * Filler function for proc/modules
111983926Sdes */
112083926Sdesstatic int
112183926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
112283926Sdes{
112383926Sdes	struct linker_file *lf;
1124119068Sdes
112583926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
112683926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
112783926Sdes		    (unsigned long)lf->size, lf->refs);
112883926Sdes	}
112983926Sdes	return (0);
113083926Sdes}
113183926Sdes#endif
113283926Sdes
113383926Sdes/*
113485129Sdes * Constructor
113578025Sdes */
113685129Sdesstatic int
113785129Sdeslinprocfs_init(PFS_INIT_ARGS)
113885129Sdes{
113985129Sdes	struct pfs_node *root;
114085129Sdes	struct pfs_node *dir;
114174135Sjlemon
114285129Sdes	root = pi->pi_root;
114378025Sdes
1144119923Sdes	/* /proc/... */
1145119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1146167482Sdes	    NULL, NULL, NULL, PFS_RD);
1147119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1148167482Sdes	    NULL, NULL, NULL, PFS_RD);
1149119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1150167482Sdes	    NULL, NULL, NULL, PFS_RD);
1151119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1152167482Sdes	    NULL, NULL, NULL, PFS_RD);
1153119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1154167482Sdes	    NULL, NULL, NULL, PFS_RD);
115583926Sdes#if 0
1156119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1157167482Sdes	    NULL, NULL, NULL, PFS_RD);
115883926Sdes#endif
1159158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1160167482Sdes	    NULL, NULL, NULL, PFS_RD);
1161119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1162167482Sdes	    NULL, NULL, NULL, PFS_RD);
116387543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1164167482Sdes	    NULL, NULL, NULL, 0);
1165119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1166167482Sdes	    NULL, NULL, NULL, PFS_RD);
1167119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1168167482Sdes	    NULL, NULL, NULL, PFS_RD);
1169119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1170167482Sdes	    NULL, NULL, NULL, PFS_RD);
117178025Sdes
1172119923Sdes	/* /proc/net/... */
1173167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
117485129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1175167482Sdes	    NULL, NULL, NULL, PFS_RD);
117678025Sdes
1177119923Sdes	/* /proc/<pid>/... */
1178167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
117985129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1180167482Sdes	    NULL, NULL, NULL, PFS_RD);
1181119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1182167482Sdes	    NULL, NULL, NULL, 0);
1183116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1184167482Sdes	    NULL, NULL, NULL, PFS_RD);
118587543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1186167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1187116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1188167482Sdes	    NULL, NULL, NULL, PFS_RD);
118985129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1190167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1191119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1192167482Sdes	    NULL, NULL, NULL, 0);
119385129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1194167482Sdes	    NULL, NULL, NULL, PFS_RD);
1195119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1196167482Sdes	    NULL, NULL, NULL, PFS_RD);
119785129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1198167482Sdes	    NULL, NULL, NULL, PFS_RD);
119985129Sdes
1200158311Sambrisko	/* /proc/scsi/... */
1201167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1202158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1203167482Sdes	    NULL, NULL, NULL, PFS_RD);
1204158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1205167482Sdes	    NULL, NULL, NULL, PFS_RD);
1206163129Snetchild
1207163129Snetchild	/* /proc/sys/... */
1208167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1209163129Snetchild	/* /proc/sys/kernel/... */
1210167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1211167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1212167482Sdes	    NULL, NULL, NULL, PFS_RD);
1213167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1214167482Sdes	    NULL, NULL, NULL, PFS_RD);
1215167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1216167482Sdes	    NULL, NULL, NULL, PFS_RD);
1217164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1218167482Sdes	    NULL, NULL, NULL, PFS_RD);
1219163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1220167482Sdes	    NULL, NULL, NULL, PFS_RD);
1221164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1222167482Sdes	    NULL, NULL, NULL, PFS_RD);
1223163129Snetchild
122485129Sdes	return (0);
122585129Sdes}
122685129Sdes
122785129Sdes/*
122885129Sdes * Destructor
122985129Sdes */
123085129Sdesstatic int
123185129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
123285129Sdes{
123385129Sdes
123485129Sdes	/* nothing to do, pseudofs will GC */
123585129Sdes	return (0);
123685129Sdes}
123785129Sdes
123885129SdesPSEUDOFS(linprocfs, 1);
123978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
124078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1241