linprocfs.c revision 167159
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 167159 2007-03-02 01:10:26Z 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>
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 */
124166140Snetchildstatic 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/*
419167159Sjkim * Get OS build date
420167159Sjkim */
421167159Sjkimstatic void
422167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
423167159Sjkim{
424167159Sjkim#if 0
425167159Sjkim	char osbuild[256];
426167159Sjkim	char *cp1, *cp2;
427167159Sjkim
428167159Sjkim	strncpy(osbuild, version, 256);
429167159Sjkim	osbuild[255] = '\0';
430167159Sjkim	cp1 = strstr(osbuild, "\n");
431167159Sjkim	cp2 = strstr(osbuild, ":");
432167159Sjkim	if (cp1 && cp2) {
433167159Sjkim		*cp1 = *cp2 = '\0';
434167159Sjkim		cp1 = strstr(osbuild, "#");
435167159Sjkim	} else
436167159Sjkim		cp1 = NULL;
437167159Sjkim	if (cp1)
438167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
439167159Sjkim	else
440167159Sjkim#endif
441167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
442167159Sjkim}
443167159Sjkim
444167159Sjkim/*
445167159Sjkim * Get OS builder
446167159Sjkim */
447167159Sjkimstatic void
448167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
449167159Sjkim{
450167159Sjkim	char builder[256];
451167159Sjkim	char *cp;
452167159Sjkim
453167159Sjkim	cp = strstr(version, "\n    ");
454167159Sjkim	if (cp) {
455167159Sjkim		strncpy(builder, cp + 5, 256);
456167159Sjkim		builder[255] = '\0';
457167159Sjkim		cp = strstr(builder, ":");
458167159Sjkim		if (cp)
459167159Sjkim			*cp = '\0';
460167159Sjkim	}
461167159Sjkim	if (cp)
462167159Sjkim		sbuf_cat(sb, builder);
463167159Sjkim	else
464167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
465167159Sjkim}
466167159Sjkim
467167159Sjkim/*
46878113Sdes * Filler function for proc/version
46978113Sdes */
47078025Sdesstatic int
47178025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
47265633Sdes{
47387275Srwatson	char osname[LINUX_MAX_UTSNAME];
47487275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
47587275Srwatson
476112206Sjhb	linux_get_osname(td, osname);
477112206Sjhb	linux_get_osrelease(td, osrelease);
478167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
479167159Sjkim	linprocfs_osbuilder(td, sb);
480167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
481167159Sjkim	linprocfs_osbuild(td, sb);
482167159Sjkim	sbuf_cat(sb, "\n");
48387275Srwatson
48478025Sdes	return (0);
48565633Sdes}
48665633Sdes
48778113Sdes/*
48878113Sdes * Filler function for proc/loadavg
48978113Sdes */
49078025Sdesstatic int
49178025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
49276839Sjlemon{
49378025Sdes	sbuf_printf(sb,
49476839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
49576839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
49676839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
49776839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
49876839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
49976839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
50076839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
50176839Sjlemon	    1,				/* number of running tasks */
50276839Sjlemon	    nprocs,			/* number of tasks */
50378116Sdes	    lastpid			/* the last pid */
50476839Sjlemon	);
505119068Sdes
50678025Sdes	return (0);
50776839Sjlemon}
50876839Sjlemon
50978113Sdes/*
51078113Sdes * Filler function for proc/pid/stat
51178113Sdes */
51278025Sdesstatic int
51378025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
51467588Sdes{
51569995Sdes	struct kinfo_proc kp;
516166140Snetchild	char state;
517166140Snetchild	static int ratelimit = 0;
51867588Sdes
51994307Sjhb	PROC_LOCK(p);
52069995Sdes	fill_kinfo_proc(p, &kp);
52178025Sdes	sbuf_printf(sb, "%d", p->p_pid);
52278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
52367588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
524166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
525166140Snetchild		state = 'R';
526166140Snetchild
527166141Snetchild		if (ratelimit == 0) {
528166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
529166162Snetchild			    kp.ki_stat, sizeof(linux_state));
530166141Snetchild			++ratelimit;
531166141Snetchild		}
532166140Snetchild	} else
533166140Snetchild		state = linux_state[kp.ki_stat - 1];
534166140Snetchild	PS_ADD("state",		"%c",	state);
53573923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
53667588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
53767588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
53891140Stanimura	PROC_UNLOCK(p);
53967588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
540159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
54167588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
542159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
543159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
544159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
545159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
546159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
547159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
548159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
549159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
550159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
551159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
552159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
553159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
554159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
555159995Snetchild	   It should be the number of jiffies between system boot and process
556159995Snetchild	   start. */
557159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
558159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
559159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
560159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
56169995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
56267588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
56367588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
564159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
565159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
566159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
567159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
568159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
569159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
57067588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
571159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
572159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
57369799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
574159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
575159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
576159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
57767588Sdes#undef PS_ADD
57878025Sdes	sbuf_putc(sb, '\n');
579119068Sdes
58078025Sdes	return (0);
58167588Sdes}
58267588Sdes
58367588Sdes/*
584119911Sdes * Filler function for proc/pid/statm
585119911Sdes */
586119911Sdesstatic int
587119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
588119911Sdes{
589119911Sdes	struct kinfo_proc kp;
590119911Sdes	segsz_t lsize;
591120340Sdes
592119911Sdes	PROC_LOCK(p);
593119911Sdes	fill_kinfo_proc(p, &kp);
594119911Sdes	PROC_UNLOCK(p);
595119911Sdes
596119911Sdes	/*
597119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
598119911Sdes	 * computation of lsize.
599119911Sdes	 */
600119911Sdes	/* size resident share trs drs lrs dt */
601119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
602119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
603119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
604119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
605119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
606119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
607119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
608119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
609119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
610119911Sdes
611119911Sdes	return (0);
612119911Sdes}
613119911Sdes
614119911Sdes/*
61578113Sdes * Filler function for proc/pid/status
61678113Sdes */
61778025Sdesstatic int
61878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
61967588Sdes{
62069995Sdes	struct kinfo_proc kp;
62167588Sdes	char *state;
62269799Sdes	segsz_t lsize;
62399072Sjulian	struct thread *td2;
624114983Sjhb	struct sigacts *ps;
62574135Sjlemon	int i;
62667588Sdes
627113611Sjhb	PROC_LOCK(p);
62899072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
62999072Sjulian
63099072Sjulian	if (P_SHOULDSTOP(p)) {
63199072Sjulian		state = "T (stopped)";
63299072Sjulian	} else {
633113611Sjhb		mtx_lock_spin(&sched_lock);
63499072Sjulian		switch(p->p_state) {
63599072Sjulian		case PRS_NEW:
63699072Sjulian			state = "I (idle)";
63799072Sjulian			break;
63899072Sjulian		case PRS_NORMAL:
63999072Sjulian			if (p->p_flag & P_WEXIT) {
64099072Sjulian				state = "X (exiting)";
64199072Sjulian				break;
64299072Sjulian			}
64399072Sjulian			switch(td2->td_state) {
644103216Sjulian			case TDS_INHIBITED:
64599072Sjulian				state = "S (sleeping)";
64699072Sjulian				break;
64799072Sjulian			case TDS_RUNQ:
64899072Sjulian			case TDS_RUNNING:
64999072Sjulian				state = "R (running)";
65099072Sjulian				break;
65199072Sjulian			default:
65299072Sjulian				state = "? (unknown)";
65399072Sjulian				break;
65499072Sjulian			}
65599072Sjulian			break;
65699072Sjulian		case PRS_ZOMBIE:
65799072Sjulian			state = "Z (zombie)";
65899072Sjulian			break;
65999072Sjulian		default:
66099072Sjulian			state = "? (unknown)";
66199072Sjulian			break;
66299072Sjulian		}
663113611Sjhb		mtx_unlock_spin(&sched_lock);
66499072Sjulian	}
66567588Sdes
66669995Sdes	fill_kinfo_proc(p, &kp);
66778025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
66878031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
66967588Sdes
67067588Sdes	/*
67167588Sdes	 * Credentials
67267588Sdes	 */
67378025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
67478025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
67573923Sjhb						p->p_pptr->p_pid : 0);
67678031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
67778031Sdes						p->p_ucred->cr_uid,
67878031Sdes						p->p_ucred->cr_svuid,
67978031Sdes						/* FreeBSD doesn't have fsuid */
68078031Sdes						p->p_ucred->cr_uid);
68178031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
68278031Sdes						p->p_ucred->cr_gid,
68378031Sdes						p->p_ucred->cr_svgid,
68478031Sdes						/* FreeBSD doesn't have fsgid */
68578031Sdes						p->p_ucred->cr_gid);
68678025Sdes	sbuf_cat(sb, "Groups:\t");
68767588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
68878031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
68971471Sjhb	PROC_UNLOCK(p);
69078025Sdes	sbuf_putc(sb, '\n');
691119068Sdes
69267588Sdes	/*
69367588Sdes	 * Memory
69469799Sdes	 *
69569799Sdes	 * While our approximation of VmLib may not be accurate (I
69669799Sdes	 * don't know of a simple way to verify it, and I'm not sure
69769799Sdes	 * it has much meaning anyway), I believe it's good enough.
69869799Sdes	 *
69969799Sdes	 * The same code that could (I think) accurately compute VmLib
70069799Sdes	 * could also compute VmLck, but I don't really care enough to
70169799Sdes	 * implement it. Submissions are welcome.
70267588Sdes	 */
703113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
70478025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
705113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
706113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
707113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
708113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
70969995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
71069995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
711113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
71267588Sdes
71367588Sdes	/*
71467588Sdes	 * Signal masks
71567588Sdes	 *
71667588Sdes	 * We support up to 128 signals, while Linux supports 32,
71767588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
71867588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
71967588Sdes	 *
72067588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
72167588Sdes	 * supports 64 signals, but this code is a long way from
72267588Sdes	 * running on anything but i386, so ignore that for now.
72367588Sdes	 */
72471471Sjhb	PROC_LOCK(p);
725104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
72669799Sdes	/*
72769799Sdes	 * I can't seem to find out where the signal mask is in
72869799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
72969799Sdes	 */
73078025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
731114983Sjhb	ps = p->p_sigacts;
732114983Sjhb	mtx_lock(&ps->ps_mtx);
733114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
734114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
735114983Sjhb	mtx_unlock(&ps->ps_mtx);
73671471Sjhb	PROC_UNLOCK(p);
737119068Sdes
73867588Sdes	/*
73967588Sdes	 * Linux also prints the capability masks, but we don't have
74067588Sdes	 * capabilities yet, and when we do get them they're likely to
74167588Sdes	 * be meaningless to Linux programs, so we lie. XXX
74267588Sdes	 */
74378025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
74478025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
74578025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
746119068Sdes
74778025Sdes	return (0);
74867588Sdes}
74974135Sjlemon
750119911Sdes
75178113Sdes/*
752119911Sdes * Filler function for proc/pid/cwd
753119911Sdes */
754119911Sdesstatic int
755119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
756119911Sdes{
757119911Sdes	char *fullpath = "unknown";
758119911Sdes	char *freepath = NULL;
759119911Sdes
760119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
761119911Sdes	sbuf_printf(sb, "%s", fullpath);
762119911Sdes	if (freepath)
763119911Sdes		free(freepath, M_TEMP);
764119911Sdes	return (0);
765119911Sdes}
766119911Sdes
767119911Sdes/*
768119911Sdes * Filler function for proc/pid/root
769119911Sdes */
770119911Sdesstatic int
771119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
772119911Sdes{
773119911Sdes	struct vnode *rvp;
774119911Sdes	char *fullpath = "unknown";
775119911Sdes	char *freepath = NULL;
776119911Sdes
777119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
778119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
779119911Sdes	sbuf_printf(sb, "%s", fullpath);
780119911Sdes	if (freepath)
781119911Sdes		free(freepath, M_TEMP);
782119911Sdes	return (0);
783119911Sdes}
784119911Sdes
785119911Sdes/*
78678113Sdes * Filler function for proc/pid/cmdline
78778113Sdes */
78878025Sdesstatic int
78978113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
79078113Sdes{
79178113Sdes	struct ps_strings pstr;
792138281Scperciva	char **ps_argvstr;
79378113Sdes	int error, i;
79478113Sdes
79578113Sdes	/*
79678113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
79778113Sdes	 * revert back to the old way which only implements full cmdline
79878113Sdes	 * for the currept process and just p->p_comm for all other
79978113Sdes	 * processes.
80078113Sdes	 * Note that if the argv is no longer available, we deliberately
80178113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
80278113Sdes	 * Linux behaviour is to return zero-length in this case.
80378113Sdes	 */
80478113Sdes
80594620Sjhb	PROC_LOCK(p);
806127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
80794620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
80894620Sjhb		PROC_UNLOCK(p);
80994620Sjhb	} else if (p != td->td_proc) {
81094620Sjhb		PROC_UNLOCK(p);
81194620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
81294620Sjhb	} else {
81394620Sjhb		PROC_UNLOCK(p);
814103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
815103767Sjake		    sizeof(pstr));
81694620Sjhb		if (error)
81794620Sjhb			return (error);
818138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
819138281Scperciva			return (E2BIG);
820138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
821138281Scperciva		    M_TEMP, M_WAITOK);
822138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
823138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
824138281Scperciva		if (error) {
825138281Scperciva			free(ps_argvstr, M_TEMP);
826138281Scperciva			return (error);
827138281Scperciva		}
82894620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
829138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
83094620Sjhb			sbuf_printf(sb, "%c", '\0');
83178113Sdes		}
832138281Scperciva		free(ps_argvstr, M_TEMP);
83378113Sdes	}
83478113Sdes
83578113Sdes	return (0);
83678113Sdes}
83778113Sdes
83878113Sdes/*
839116173Sobrien * Filler function for proc/pid/environ
840116173Sobrien */
841116173Sobrienstatic int
842116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
843116173Sobrien{
844116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
845116173Sobrien
846116173Sobrien	return (0);
847116173Sobrien}
848116173Sobrien
849116173Sobrien/*
850116173Sobrien * Filler function for proc/pid/maps
851116173Sobrien */
852116173Sobrienstatic int
853116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
854116173Sobrien{
855121265Scognet	char mebuffer[512];
856121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
857121246Scognet	vm_map_entry_t entry;
858121265Scognet	vm_object_t obj, tobj, lobj;
859121265Scognet	vm_ooffset_t off = 0;
860121265Scognet	char *name = "", *freename = NULL;
861121265Scognet	size_t len;
862121265Scognet	ino_t ino;
863121265Scognet	int ref_count, shadow_count, flags;
864121265Scognet	int error;
865137507Sphk	struct vnode *vp;
866137507Sphk	struct vattr vat;
867161094Skib	int locked;
868121246Scognet
869121246Scognet	PROC_LOCK(p);
870121246Scognet	error = p_candebug(td, p);
871121246Scognet	PROC_UNLOCK(p);
872121246Scognet	if (error)
873121246Scognet		return (error);
874121246Scognet
875121246Scognet	if (uio->uio_rw != UIO_READ)
876121246Scognet		return (EOPNOTSUPP);
877121246Scognet
878121246Scognet	if (uio->uio_offset != 0)
879121246Scognet		return (0);
880121246Scognet
881121246Scognet	error = 0;
882121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
883121246Scognet		vm_map_lock_read(map);
884121246Scognet        for (entry = map->header.next;
885121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
886121246Scognet	    entry = entry->next) {
887121265Scognet		name = "";
888121265Scognet		freename = NULL;
889121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
890121246Scognet			continue;
891121246Scognet		obj = entry->object.vm_object;
892121246Scognet		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
893121246Scognet			lobj = tobj;
894121246Scognet		ino = 0;
895121246Scognet		if (lobj) {
896121246Scognet			VM_OBJECT_LOCK(lobj);
897121246Scognet			off = IDX_TO_OFF(lobj->size);
898161094Skib			if (lobj->type == OBJT_VNODE) {
899161094Skib				vp = lobj->handle;
900161094Skib				if (vp)
901161094Skib					vref(vp);
902121246Scognet			}
903161094Skib			else
904161094Skib				vp = NULL;
905121246Scognet			flags = obj->flags;
906121246Scognet			ref_count = obj->ref_count;
907121246Scognet			shadow_count = obj->shadow_count;
908121246Scognet			VM_OBJECT_UNLOCK(lobj);
909161094Skib			if (vp) {
910161094Skib				vn_fullpath(td, vp, &name, &freename);
911161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
912161094Skib				vn_lock(vp, LK_SHARED | LK_RETRY, td);
913161094Skib				VOP_GETATTR(vp, &vat, td->td_ucred, td);
914161094Skib				ino = vat.va_fileid;
915161094Skib				vput(vp);
916161094Skib				VFS_UNLOCK_GIANT(locked);
917161094Skib			}
918121246Scognet		} else {
919121246Scognet			flags = 0;
920121246Scognet			ref_count = 0;
921121246Scognet			shadow_count = 0;
922121246Scognet		}
923121246Scognet
924121246Scognet		/*
925121246Scognet	     	 * format:
926121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
927121246Scognet		 */
928121246Scognet		snprintf(mebuffer, sizeof mebuffer,
929121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
930121246Scognet		    (u_long)entry->start, (u_long)entry->end,
931121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
932121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
933121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
934121246Scognet		    "p",
935121265Scognet		    (u_long)off,
936121246Scognet		    0,
937121246Scognet		    0,
938121265Scognet		    (u_long)ino,
939121246Scognet		    *name ? "     " : "",
940121246Scognet		    name
941121246Scognet		    );
942121246Scognet		if (freename)
943121246Scognet			free(freename, M_TEMP);
944121246Scognet		len = strlen(mebuffer);
945121246Scognet		if (len > uio->uio_resid)
946121246Scognet			len = uio->uio_resid; /*
947121246Scognet					       * XXX We should probably return
948121246Scognet					       * EFBIG here, as in procfs.
949121246Scognet					       */
950121246Scognet		error = uiomove(mebuffer, len, uio);
951121246Scognet		if (error)
952121246Scognet			break;
953121246Scognet	}
954121246Scognet	if (map != &curthread->td_proc->p_vmspace->vm_map)
955121246Scognet		vm_map_unlock_read(map);
956121246Scognet
957121246Scognet	return (error);
958121246Scognet}
959121246Scognet
960116173Sobrien/*
96178113Sdes * Filler function for proc/net/dev
96278113Sdes */
96378025Sdesstatic int
96478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
96574135Sjlemon{
96685129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
96774135Sjlemon	struct ifnet *ifp;
96874135Sjlemon
96985129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
97083926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
97185129Sdes	    "bytes    packets errs drop fifo frame compressed",
97283926Sdes	    "bytes    packets errs drop fifo frame compressed");
97374135Sjlemon
974108172Shsu	IFNET_RLOCK();
97574135Sjlemon	TAILQ_FOREACH(ifp, &ifnet, if_link) {
97685129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
97785129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
97883926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
97983926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
98083926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
98183926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
98274135Sjlemon	}
983108172Shsu	IFNET_RUNLOCK();
984119068Sdes
98578025Sdes	return (0);
98674135Sjlemon}
98774135Sjlemon
988158311Sambrisko/*
989167159Sjkim * Filler function for proc/sys/kernel/osrelease
990167159Sjkim */
991167159Sjkimstatic int
992167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
993167159Sjkim{
994167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
995167159Sjkim
996167159Sjkim	linux_get_osrelease(td, osrelease);
997167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
998167159Sjkim
999167159Sjkim	return (0);
1000167159Sjkim}
1001167159Sjkim
1002167159Sjkim/*
1003167159Sjkim * Filler function for proc/sys/kernel/ostype
1004167159Sjkim */
1005167159Sjkimstatic int
1006167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1007167159Sjkim{
1008167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1009167159Sjkim
1010167159Sjkim	linux_get_osname(td, osname);
1011167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1012167159Sjkim
1013167159Sjkim	return (0);
1014167159Sjkim}
1015167159Sjkim
1016167159Sjkim/*
1017167159Sjkim * Filler function for proc/sys/kernel/version
1018167159Sjkim */
1019167159Sjkimstatic int
1020167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1021167159Sjkim{
1022167159Sjkim	linprocfs_osbuild(td, sb);
1023167159Sjkim	sbuf_cat(sb, "\n");
1024167159Sjkim
1025167159Sjkim	return (0);
1026167159Sjkim}
1027167159Sjkim
1028167159Sjkim/*
1029164692Sjkim * Filler function for proc/sys/kernel/msgmni
1030164692Sjkim */
1031164692Sjkimstatic int
1032164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1033164692Sjkim{
1034164692Sjkim	int msgmni;
1035164692Sjkim	size_t size;
1036164692Sjkim
1037164692Sjkim	size = sizeof(msgmni);
1038164692Sjkim	if (kernel_sysctlbyname(td, "kern.ipc.msgmni", &msgmni, &size,
1039164692Sjkim	    0, 0, 0, 0) != 0)
1040164692Sjkim		msgmni = 0;
1041164692Sjkim	sbuf_printf(sb, "%i\n", msgmni);
1042164692Sjkim
1043164692Sjkim	return (0);
1044164692Sjkim}
1045164692Sjkim
1046164692Sjkim/*
1047163251Skeramida * Filler function for proc/sys/kernel/pid_max
1048163129Snetchild */
1049163129Snetchildstatic int
1050163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1051163129Snetchild{
1052163757Snetchild
1053163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1054163129Snetchild
1055163129Snetchild	return (0);
1056163129Snetchild}
1057163129Snetchild
1058163129Snetchild/*
1059164692Sjkim * Filler function for proc/sys/kernel/sem
1060164692Sjkim */
1061164692Sjkimstatic int
1062164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1063164692Sjkim{
1064164692Sjkim	int semmsl, semmns, semopm, semmni;
1065164692Sjkim	size_t size;
1066164692Sjkim
1067164692Sjkim	/* Field 1: SEMMSL */
1068164692Sjkim	size = sizeof(semmsl);
1069164692Sjkim	if (kernel_sysctlbyname(td, "kern.ipc.semmsl", &semmsl, &size,
1070164692Sjkim	    0, 0, 0, 0) != 0)
1071164692Sjkim		semmsl = 0;
1072164692Sjkim
1073164692Sjkim	/* Field 2: SEMMNS */
1074164692Sjkim	size = sizeof(semmns);
1075164692Sjkim	if (kernel_sysctlbyname(td, "kern.ipc.semmns", &semmns, &size,
1076164692Sjkim	    0, 0, 0, 0) != 0)
1077164692Sjkim		semmns = 0;
1078164692Sjkim
1079164692Sjkim	/* Field 3: SEMOPM */
1080164692Sjkim	size = sizeof(semopm);
1081164692Sjkim	if (kernel_sysctlbyname(td, "kern.ipc.semopm", &semopm, &size,
1082164692Sjkim	    0, 0, 0, 0) != 0)
1083164692Sjkim		semopm = 0;
1084164692Sjkim
1085164692Sjkim	/* Field 4: SEMMNI */
1086164692Sjkim	size = sizeof(semmni);
1087164692Sjkim	if (kernel_sysctlbyname(td, "kern.ipc.semmni", &semmni, &size,
1088164692Sjkim	    0, 0, 0, 0) != 0)
1089164692Sjkim		semmni = 0;
1090164692Sjkim
1091164692Sjkim	sbuf_printf(sb, "%i %i %i %i\n", semmsl, semmns, semopm, semmni);
1092164692Sjkim
1093164692Sjkim	return (0);
1094164692Sjkim}
1095164692Sjkim
1096164692Sjkim/*
1097158311Sambrisko * Filler function for proc/scsi/device_info
1098158311Sambrisko */
1099158311Sambriskostatic int
1100158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1101158311Sambrisko{
1102158311Sambrisko	return (0);
1103158311Sambrisko}
1104158311Sambrisko
1105158311Sambrisko/*
1106158311Sambrisko * Filler function for proc/scsi/scsi
1107158311Sambrisko */
1108158311Sambriskostatic int
1109158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1110158311Sambrisko{
1111158311Sambrisko	return (0);
1112158311Sambrisko}
1113158311Sambrisko
111485538Sphkextern struct cdevsw *cdevsw[];
111585538Sphk
111678113Sdes/*
111778113Sdes * Filler function for proc/devices
111878113Sdes */
111978025Sdesstatic int
112078025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
112174135Sjlemon{
1122158311Sambrisko	char *char_devices;
112378025Sdes	sbuf_printf(sb, "Character devices:\n");
112474135Sjlemon
1125158311Sambrisko	char_devices = linux_get_char_devices();
1126158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1127158311Sambrisko	linux_free_get_char_devices(char_devices);
112874135Sjlemon
112978025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1130119068Sdes
113178025Sdes	return (0);
113274135Sjlemon}
113374135Sjlemon
113478113Sdes/*
113578113Sdes * Filler function for proc/cmdline
113678113Sdes */
113778025Sdesstatic int
113878025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
113974135Sjlemon{
114078025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
114178025Sdes	sbuf_printf(sb, " ro root=302\n");
114278025Sdes	return (0);
114378025Sdes}
114474135Sjlemon
114583926Sdes#if 0
114678025Sdes/*
114783926Sdes * Filler function for proc/modules
114883926Sdes */
114983926Sdesstatic int
115083926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
115183926Sdes{
115283926Sdes	struct linker_file *lf;
1153119068Sdes
115483926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
115583926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
115683926Sdes		    (unsigned long)lf->size, lf->refs);
115783926Sdes	}
115883926Sdes	return (0);
115983926Sdes}
116083926Sdes#endif
116183926Sdes
116283926Sdes/*
116385129Sdes * Constructor
116478025Sdes */
116585129Sdesstatic int
116685129Sdeslinprocfs_init(PFS_INIT_ARGS)
116785129Sdes{
116885129Sdes	struct pfs_node *root;
116985129Sdes	struct pfs_node *dir;
117074135Sjlemon
117185129Sdes	root = pi->pi_root;
117278025Sdes
1173119923Sdes	/* /proc/... */
1174119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1175119911Sdes	    NULL, NULL, PFS_RD);
1176119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1177119911Sdes	    NULL, NULL, PFS_RD);
1178119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1179119911Sdes	    NULL, NULL, PFS_RD);
1180119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1181119911Sdes	    NULL, NULL, PFS_RD);
1182119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1183119911Sdes	    NULL, NULL, PFS_RD);
118483926Sdes#if 0
1185119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1186119911Sdes	    NULL, NULL, PFS_RD);
118783926Sdes#endif
1188158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1189158311Sambrisko	    NULL, NULL, PFS_RD);
1190119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1191119911Sdes	    NULL, NULL, PFS_RD);
119287543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
119385129Sdes	    NULL, NULL, 0);
1194119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1195119911Sdes	    NULL, NULL, PFS_RD);
1196119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1197119911Sdes	    NULL, NULL, PFS_RD);
1198119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1199119911Sdes	    NULL, NULL, PFS_RD);
120078025Sdes
1201119923Sdes	/* /proc/net/... */
120285129Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
120385129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
120485129Sdes	    NULL, NULL, PFS_RD);
120578025Sdes
1206119923Sdes	/* /proc/<pid>/... */
120785129Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
120885129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
120985129Sdes	    NULL, NULL, PFS_RD);
1210119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1211119911Sdes	    NULL, NULL, 0);
1212116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1213116173Sobrien	    NULL, NULL, PFS_RD);
121487543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
121587543Sdes	    NULL, &procfs_notsystem, 0);
1216116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1217116173Sobrien	    NULL, NULL, PFS_RD);
121885129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
121985129Sdes	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1220119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1221119911Sdes	    NULL, NULL, 0);
122285129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
122385129Sdes	    NULL, NULL, PFS_RD);
1224119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1225119911Sdes	    NULL, NULL, PFS_RD);
122685129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
122785129Sdes	    NULL, NULL, PFS_RD);
122885129Sdes
1229158311Sambrisko	/* /proc/scsi/... */
1230158311Sambrisko	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1231158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1232158311Sambrisko	    NULL, NULL, PFS_RD);
1233158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1234158311Sambrisko	    NULL, NULL, PFS_RD);
1235163129Snetchild
1236163129Snetchild	/* /proc/sys/... */
1237163129Snetchild	dir = pfs_create_dir(root, "sys", NULL, NULL, 0);
1238163129Snetchild	/* /proc/sys/kernel/... */
1239163129Snetchild	dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0);
1240167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1241167159Sjkim	    NULL, NULL, PFS_RD);
1242167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1243167159Sjkim	    NULL, NULL, PFS_RD);
1244167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1245167159Sjkim	    NULL, NULL, PFS_RD);
1246164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1247164692Sjkim	    NULL, NULL, PFS_RD);
1248163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1249163129Snetchild	    NULL, NULL, PFS_RD);
1250164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1251164692Sjkim	    NULL, NULL, PFS_RD);
1252163129Snetchild
125385129Sdes	return (0);
125485129Sdes}
125585129Sdes
125685129Sdes/*
125785129Sdes * Destructor
125885129Sdes */
125985129Sdesstatic int
126085129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
126185129Sdes{
126285129Sdes
126385129Sdes	/* nothing to do, pseudofs will GC */
126485129Sdes	return (0);
126585129Sdes}
126685129Sdes
126785129SdesPSEUDOFS(linprocfs, 1);
126878025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
126978025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1270