linprocfs.c revision 182141
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
42182141Sjulian#include "opt_compat.h"
43182141Sjulian
44116173Sobrien#include <sys/cdefs.h>
45116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 182141 2008-08-25 04:55:29Z julian $");
46116173Sobrien
4759412Smsmith#include <sys/param.h>
4883926Sdes#include <sys/queue.h>
4976166Smarkm#include <sys/blist.h>
5074135Sjlemon#include <sys/conf.h>
5183926Sdes#include <sys/exec.h>
52177785Skib#include <sys/fcntl.h>
53119911Sdes#include <sys/filedesc.h>
5476166Smarkm#include <sys/jail.h>
5565633Sdes#include <sys/kernel.h>
5683926Sdes#include <sys/linker.h>
5776166Smarkm#include <sys/lock.h>
5874135Sjlemon#include <sys/malloc.h>
5978025Sdes#include <sys/mount.h>
60168067Sjkim#include <sys/msg.h>
6176827Salfred#include <sys/mutex.h>
6285289Sdes#include <sys/namei.h>
6365633Sdes#include <sys/proc.h>
6465633Sdes#include <sys/resourcevar.h>
6569995Sdes#include <sys/sbuf.h>
66168067Sjkim#include <sys/sem.h>
67123246Sdes#include <sys/smp.h>
6883926Sdes#include <sys/socket.h>
6976839Sjlemon#include <sys/sysctl.h>
7083926Sdes#include <sys/systm.h>
71159995Snetchild#include <sys/time.h>
7265633Sdes#include <sys/tty.h>
7383926Sdes#include <sys/user.h>
7483926Sdes#include <sys/vmmeter.h>
7559412Smsmith#include <sys/vnode.h>
76181803Sbz#include <sys/vimage.h>
7759412Smsmith
7883926Sdes#include <net/if.h>
7983926Sdes
8059412Smsmith#include <vm/vm.h>
8159412Smsmith#include <vm/pmap.h>
8267588Sdes#include <vm/vm_map.h>
8359412Smsmith#include <vm/vm_param.h>
8460860Sdes#include <vm/vm_object.h>
8559412Smsmith#include <vm/swap_pager.h>
8669799Sdes
8767589Sdes#include <machine/clock.h>
8878113Sdes
89133822Stjr#if defined(__i386__) || defined(__amd64__)
9067589Sdes#include <machine/cputypes.h>
9159412Smsmith#include <machine/md_var.h>
92133822Stjr#endif /* __i386__ || __amd64__ */
9359412Smsmith
94140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
95140214Sobrien#include <machine/../linux32/linux.h>
96140214Sobrien#else
9787275Srwatson#include <machine/../linux/linux.h>
98133822Stjr#endif
9985129Sdes#include <compat/linux/linux_ioctl.h>
10069995Sdes#include <compat/linux/linux_mib.h>
10185289Sdes#include <compat/linux/linux_util.h>
10278025Sdes#include <fs/pseudofs/pseudofs.h>
10384248Sdes#include <fs/procfs/procfs.h>
10459412Smsmith
10567588Sdes/*
10667588Sdes * Various conversion macros
10767588Sdes */
10876405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10967588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11067588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11169799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11267588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11367588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11474135Sjlemon
115159995Snetchild/**
116159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
117159995Snetchild *
118159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
119159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
120172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
121159995Snetchild * or stopped, or process is paging respectively.
122159995Snetchild *
123159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
124159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
125159995Snetchild *
126159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
127159995Snetchild * map our states to suitable linux states.
128159995Snetchild */
129166140Snetchildstatic char linux_state[] = "RRSTZDD";
130159995Snetchild
13178113Sdes/*
13278113Sdes * Filler function for proc/meminfo
13378113Sdes */
13478025Sdesstatic int
13578025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13659412Smsmith{
13759412Smsmith	unsigned long memtotal;		/* total memory in bytes */
13859412Smsmith	unsigned long memused;		/* used memory in bytes */
13959412Smsmith	unsigned long memfree;		/* free memory in bytes */
14059412Smsmith	unsigned long memshared;	/* shared memory ??? */
14159412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
142113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
143113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
144113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14560860Sdes	vm_object_t object;
146117723Sphk	int i, j;
14759412Smsmith
14859412Smsmith	memtotal = physmem * PAGE_SIZE;
14959412Smsmith	/*
15059412Smsmith	 * The correct thing here would be:
15159412Smsmith	 *
152170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
15359412Smsmith	memused = memtotal - memfree;
15459412Smsmith	 *
15559412Smsmith	 * but it might mislead linux binaries into thinking there
15659412Smsmith	 * is very little memory left, so we cheat and tell them that
15759412Smsmith	 * all memory that isn't wired down is free.
15859412Smsmith	 */
159170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
16059412Smsmith	memfree = memtotal - memused;
161117723Sphk	swap_pager_status(&i, &j);
162153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
163153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
164117723Sphk	swapfree = swaptotal - swapused;
16560860Sdes	memshared = 0;
166124082Salc	mtx_lock(&vm_object_list_mtx);
16771471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
16860860Sdes		if (object->shadow_count > 1)
16960860Sdes			memshared += object->resident_page_count;
170124082Salc	mtx_unlock(&vm_object_list_mtx);
17160860Sdes	memshared *= PAGE_SIZE;
17259412Smsmith	/*
17359412Smsmith	 * We'd love to be able to write:
17459412Smsmith	 *
17559412Smsmith	buffers = bufspace;
17659412Smsmith	 *
17759412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
17859412Smsmith	 * like unstaticizing it just for linprocfs's sake.
17959412Smsmith	 */
18059412Smsmith	buffers = 0;
181170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18259412Smsmith
18378025Sdes	sbuf_printf(sb,
18478031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18569799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18676839Sjlemon	    "Swap: %llu %llu %llu\n"
18769799Sdes	    "MemTotal: %9lu kB\n"
18869799Sdes	    "MemFree:  %9lu kB\n"
18969799Sdes	    "MemShared:%9lu kB\n"
19069799Sdes	    "Buffers:  %9lu kB\n"
19169799Sdes	    "Cached:   %9lu kB\n"
19276839Sjlemon	    "SwapTotal:%9llu kB\n"
19376839Sjlemon	    "SwapFree: %9llu kB\n",
19469799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19569799Sdes	    swaptotal, swapused, swapfree,
19669799Sdes	    B2K(memtotal), B2K(memfree),
19769799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
19869799Sdes	    B2K(swaptotal), B2K(swapfree));
19959412Smsmith
20078025Sdes	return (0);
20159412Smsmith}
20259412Smsmith
203133822Stjr#if defined(__i386__) || defined(__amd64__)
20478113Sdes/*
205133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20678113Sdes */
20778113Sdesstatic int
20878113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
20978113Sdes{
210159544Sdes	int hw_model[2];
211159544Sdes	char model[128];
212159544Sdes	size_t size;
213123246Sdes	int class, fqmhz, fqkhz;
214118421Sdes	int i;
21559412Smsmith
21669799Sdes	/*
21778031Sdes	 * We default the flags to include all non-conflicting flags,
21878031Sdes	 * and the Intel versions of conflicting flags.
21969799Sdes	 */
22078031Sdes	static char *flags[] = {
22178031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22278031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22378031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22478031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22578031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22678031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22767589Sdes		"3dnowext", "3dnow"
22867589Sdes	};
22967589Sdes
23059412Smsmith	switch (cpu_class) {
231133822Stjr#ifdef __i386__
23259412Smsmith	case CPUCLASS_286:
23367589Sdes		class = 2;
23459412Smsmith		break;
23559412Smsmith	case CPUCLASS_386:
23667589Sdes		class = 3;
23759412Smsmith		break;
23859412Smsmith	case CPUCLASS_486:
23967589Sdes		class = 4;
24059412Smsmith		break;
24159412Smsmith	case CPUCLASS_586:
24267589Sdes		class = 5;
24359412Smsmith		break;
24459412Smsmith	case CPUCLASS_686:
24567589Sdes		class = 6;
24659412Smsmith		break;
24759412Smsmith	default:
24878031Sdes		class = 0;
24959412Smsmith		break;
250159170Sdes#else /* __amd64__ */
251133822Stjr	default:
252159170Sdes		class = 15;
253133822Stjr		break;
254133822Stjr#endif
25559412Smsmith	}
25659412Smsmith
257159544Sdes	hw_model[0] = CTL_HW;
258159544Sdes	hw_model[1] = HW_MODEL;
259159544Sdes	model[0] = '\0';
260159544Sdes	size = sizeof(model);
261159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
262159544Sdes		strcpy(model, "unknown");
263123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
264118421Sdes		sbuf_printf(sb,
265118421Sdes		    "processor\t: %d\n"
266118421Sdes		    "vendor_id\t: %.20s\n"
267118421Sdes		    "cpu family\t: %d\n"
268118421Sdes		    "model\t\t: %d\n"
269159544Sdes		    "model name\t: %s\n"
270118421Sdes		    "stepping\t: %d\n",
271159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
272159544Sdes		/* XXX per-cpu vendor / class / model / id? */
273118421Sdes	}
27459412Smsmith
27578031Sdes	sbuf_cat(sb,
27678031Sdes	    "flags\t\t:");
27767589Sdes
27878031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
27967589Sdes		flags[16] = "fcmov";
28078031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
28167589Sdes		flags[24] = "cxmmx";
28278031Sdes	}
283119068Sdes
28478031Sdes	for (i = 0; i < 32; i++)
28567589Sdes		if (cpu_feature & (1 << i))
28678025Sdes			sbuf_printf(sb, " %s", flags[i]);
28778025Sdes	sbuf_cat(sb, "\n");
28878031Sdes	if (class >= 5) {
28969799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
29069799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
29178025Sdes		sbuf_printf(sb,
29269799Sdes		    "cpu MHz\t\t: %d.%02d\n"
29369799Sdes		    "bogomips\t: %d.%02d\n",
29469799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
29578031Sdes	}
29669995Sdes
29778025Sdes	return (0);
29859412Smsmith}
299133822Stjr#endif /* __i386__ || __amd64__ */
30065633Sdes
30178113Sdes/*
30285289Sdes * Filler function for proc/mtab
30385289Sdes *
30485289Sdes * This file doesn't exist in Linux' procfs, but is included here so
30585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
30685289Sdes */
30785289Sdesstatic int
30885289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
30985289Sdes{
31085289Sdes	struct nameidata nd;
31185289Sdes	struct mount *mp;
31291334Sjulian	const char *lep;
31391334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
31485289Sdes	size_t lep_len;
31585289Sdes	int error;
31685289Sdes
31785289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
318168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
31985289Sdes	flep = NULL;
320168942Sdes	error = namei(&nd);
321168942Sdes	VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
322168942Sdes	if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
32385289Sdes		lep = linux_emul_path;
32491334Sjulian	else
32591334Sjulian		lep = dlep;
32685289Sdes	lep_len = strlen(lep);
327119068Sdes
32885289Sdes	mtx_lock(&mountlist_mtx);
32985289Sdes	error = 0;
33085289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
33185289Sdes		/* determine device name */
33285289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
333119068Sdes
33485289Sdes		/* determine mount point */
33585289Sdes		mntto = mp->mnt_stat.f_mntonname;
33685289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
33785289Sdes		    mntto[lep_len] == '/')
33885289Sdes			mntto += lep_len;
33985289Sdes
34085289Sdes		/* determine fs type */
34185289Sdes		fstype = mp->mnt_stat.f_fstypename;
34285289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
34385289Sdes			mntfrom = fstype = "proc";
34485289Sdes		else if (strcmp(fstype, "procfs") == 0)
34585289Sdes			continue;
346119068Sdes
347158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
348158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
349158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
350158311Sambrisko		} else {
351158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
352158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
353158311Sambrisko		}
35485289Sdes#define ADD_OPTION(opt, name) \
35585289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
35685289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
35785289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
35885289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
35985289Sdes		ADD_OPTION(MNT_UNION,		"union");
36085289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
36185289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
36285289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
36385289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
36485289Sdes#undef ADD_OPTION
36585289Sdes		/* a real Linux mtab will also show NFS options */
36685289Sdes		sbuf_printf(sb, " 0 0\n");
36785289Sdes	}
36885289Sdes	mtx_unlock(&mountlist_mtx);
36985289Sdes	if (flep != NULL)
37085289Sdes		free(flep, M_TEMP);
37185289Sdes	return (error);
37285289Sdes}
37385289Sdes
37485289Sdes/*
37578113Sdes * Filler function for proc/stat
37678113Sdes */
37778025Sdesstatic int
37878025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
37965633Sdes{
380174070Speter	struct pcpu *pcpu;
381174070Speter	long cp_time[CPUSTATES];
382174070Speter	long *cp;
383123246Sdes	int i;
384120339Sdes
385174070Speter	read_cpu_time(cp_time);
386120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
387120339Sdes	    T2J(cp_time[CP_USER]),
388120339Sdes	    T2J(cp_time[CP_NICE]),
389120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
390120339Sdes	    T2J(cp_time[CP_IDLE]));
391174070Speter	for (i = 0; i <= mp_maxid; ++i) {
392174070Speter		if (CPU_ABSENT(i))
393174070Speter			continue;
394174070Speter		pcpu = pcpu_find(i);
395174070Speter		cp = pcpu->pc_cp_time;
396143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
397174070Speter		    T2J(cp[CP_USER]),
398174070Speter		    T2J(cp[CP_NICE]),
399174070Speter		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
400174070Speter		    T2J(cp[CP_IDLE]));
401174070Speter	}
40278025Sdes	sbuf_printf(sb,
40369799Sdes	    "disk 0 0 0 0\n"
40469799Sdes	    "page %u %u\n"
40569799Sdes	    "swap %u %u\n"
40669799Sdes	    "intr %u\n"
40769799Sdes	    "ctxt %u\n"
40885657Sdillon	    "btime %lld\n",
409170170Sattilio	    cnt.v_vnodepgsin,
410170170Sattilio	    cnt.v_vnodepgsout,
411170170Sattilio	    cnt.v_swappgsin,
412170170Sattilio	    cnt.v_swappgsout,
413170170Sattilio	    cnt.v_intr,
414170170Sattilio	    cnt.v_swtch,
415113574Sjhb	    (long long)boottime.tv_sec);
41678025Sdes	return (0);
41765633Sdes}
41865633Sdes
41978113Sdes/*
42078113Sdes * Filler function for proc/uptime
42178113Sdes */
42278025Sdesstatic int
42378025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
42465633Sdes{
425174070Speter	long cp_time[CPUSTATES];
42665633Sdes	struct timeval tv;
42765633Sdes
42865633Sdes	getmicrouptime(&tv);
429174070Speter	read_cpu_time(cp_time);
43085657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
431113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
43269799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
43378025Sdes	return (0);
43465633Sdes}
43565633Sdes
43678113Sdes/*
437167159Sjkim * Get OS build date
438167159Sjkim */
439167159Sjkimstatic void
440167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
441167159Sjkim{
442167159Sjkim#if 0
443167159Sjkim	char osbuild[256];
444167159Sjkim	char *cp1, *cp2;
445167159Sjkim
446167159Sjkim	strncpy(osbuild, version, 256);
447167159Sjkim	osbuild[255] = '\0';
448167159Sjkim	cp1 = strstr(osbuild, "\n");
449167159Sjkim	cp2 = strstr(osbuild, ":");
450167159Sjkim	if (cp1 && cp2) {
451167159Sjkim		*cp1 = *cp2 = '\0';
452167159Sjkim		cp1 = strstr(osbuild, "#");
453167159Sjkim	} else
454167159Sjkim		cp1 = NULL;
455167159Sjkim	if (cp1)
456167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
457167159Sjkim	else
458167159Sjkim#endif
459167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
460167159Sjkim}
461167159Sjkim
462167159Sjkim/*
463167159Sjkim * Get OS builder
464167159Sjkim */
465167159Sjkimstatic void
466167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
467167159Sjkim{
468168762Sdes#if 0
469167159Sjkim	char builder[256];
470167159Sjkim	char *cp;
471167159Sjkim
472167159Sjkim	cp = strstr(version, "\n    ");
473167159Sjkim	if (cp) {
474167159Sjkim		strncpy(builder, cp + 5, 256);
475167159Sjkim		builder[255] = '\0';
476167159Sjkim		cp = strstr(builder, ":");
477167159Sjkim		if (cp)
478167159Sjkim			*cp = '\0';
479167159Sjkim	}
480167159Sjkim	if (cp)
481167159Sjkim		sbuf_cat(sb, builder);
482167159Sjkim	else
483168762Sdes#endif
484167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
485167159Sjkim}
486167159Sjkim
487167159Sjkim/*
48878113Sdes * Filler function for proc/version
48978113Sdes */
49078025Sdesstatic int
49178025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
49265633Sdes{
49387275Srwatson	char osname[LINUX_MAX_UTSNAME];
49487275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
49587275Srwatson
496112206Sjhb	linux_get_osname(td, osname);
497112206Sjhb	linux_get_osrelease(td, osrelease);
498167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
499167159Sjkim	linprocfs_osbuilder(td, sb);
500167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
501167159Sjkim	linprocfs_osbuild(td, sb);
502167159Sjkim	sbuf_cat(sb, "\n");
50387275Srwatson
50478025Sdes	return (0);
50565633Sdes}
50665633Sdes
50778113Sdes/*
50878113Sdes * Filler function for proc/loadavg
50978113Sdes */
51078025Sdesstatic int
51178025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
51276839Sjlemon{
513168762Sdes
51478025Sdes	sbuf_printf(sb,
51576839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
51676839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
51776839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
51876839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
51976839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
52076839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
52176839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
52276839Sjlemon	    1,				/* number of running tasks */
52376839Sjlemon	    nprocs,			/* number of tasks */
52478116Sdes	    lastpid			/* the last pid */
52576839Sjlemon	);
52678025Sdes	return (0);
52776839Sjlemon}
52876839Sjlemon
52978113Sdes/*
53078113Sdes * Filler function for proc/pid/stat
53178113Sdes */
53278025Sdesstatic int
53378025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
53467588Sdes{
53569995Sdes	struct kinfo_proc kp;
536166140Snetchild	char state;
537166140Snetchild	static int ratelimit = 0;
53867588Sdes
53994307Sjhb	PROC_LOCK(p);
54069995Sdes	fill_kinfo_proc(p, &kp);
54178025Sdes	sbuf_printf(sb, "%d", p->p_pid);
54278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
54367588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
544166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
545166140Snetchild		state = 'R';
546166140Snetchild
547166141Snetchild		if (ratelimit == 0) {
548166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
549166162Snetchild			    kp.ki_stat, sizeof(linux_state));
550166141Snetchild			++ratelimit;
551166141Snetchild		}
552166140Snetchild	} else
553166140Snetchild		state = linux_state[kp.ki_stat - 1];
554166140Snetchild	PS_ADD("state",		"%c",	state);
55573923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
55667588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
55767588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
55891140Stanimura	PROC_UNLOCK(p);
55967588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
560159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
56167588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
562159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
563159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
564159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
565159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
566159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
567159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
568159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
569159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
570159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
571159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
572159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
573159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
574159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
575159995Snetchild	   It should be the number of jiffies between system boot and process
576159995Snetchild	   start. */
577159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
578159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
579159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
580159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
58169995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
58267588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
58367588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
584159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
585159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
586159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
587159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
588159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
589159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
59067588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
591159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
592159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
59369799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
594159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
595159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
596159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
59767588Sdes#undef PS_ADD
59878025Sdes	sbuf_putc(sb, '\n');
599119068Sdes
60078025Sdes	return (0);
60167588Sdes}
60267588Sdes
60367588Sdes/*
604119911Sdes * Filler function for proc/pid/statm
605119911Sdes */
606119911Sdesstatic int
607119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
608119911Sdes{
609119911Sdes	struct kinfo_proc kp;
610119911Sdes	segsz_t lsize;
611120340Sdes
612119911Sdes	PROC_LOCK(p);
613119911Sdes	fill_kinfo_proc(p, &kp);
614119911Sdes	PROC_UNLOCK(p);
615119911Sdes
616119911Sdes	/*
617119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
618119911Sdes	 * computation of lsize.
619119911Sdes	 */
620119911Sdes	/* size resident share trs drs lrs dt */
621119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
622119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
623119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
624119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
625119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
626119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
627119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
628119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
629119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
630119911Sdes
631119911Sdes	return (0);
632119911Sdes}
633119911Sdes
634119911Sdes/*
63578113Sdes * Filler function for proc/pid/status
63678113Sdes */
63778025Sdesstatic int
63878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
63967588Sdes{
64069995Sdes	struct kinfo_proc kp;
64167588Sdes	char *state;
64269799Sdes	segsz_t lsize;
64399072Sjulian	struct thread *td2;
644114983Sjhb	struct sigacts *ps;
64574135Sjlemon	int i;
64667588Sdes
647113611Sjhb	PROC_LOCK(p);
64899072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
64999072Sjulian
65099072Sjulian	if (P_SHOULDSTOP(p)) {
65199072Sjulian		state = "T (stopped)";
65299072Sjulian	} else {
653170307Sjeff		PROC_SLOCK(p);
65499072Sjulian		switch(p->p_state) {
65599072Sjulian		case PRS_NEW:
65699072Sjulian			state = "I (idle)";
65799072Sjulian			break;
65899072Sjulian		case PRS_NORMAL:
65999072Sjulian			if (p->p_flag & P_WEXIT) {
66099072Sjulian				state = "X (exiting)";
66199072Sjulian				break;
66299072Sjulian			}
66399072Sjulian			switch(td2->td_state) {
664103216Sjulian			case TDS_INHIBITED:
66599072Sjulian				state = "S (sleeping)";
66699072Sjulian				break;
66799072Sjulian			case TDS_RUNQ:
66899072Sjulian			case TDS_RUNNING:
66999072Sjulian				state = "R (running)";
67099072Sjulian				break;
67199072Sjulian			default:
67299072Sjulian				state = "? (unknown)";
67399072Sjulian				break;
67499072Sjulian			}
67599072Sjulian			break;
67699072Sjulian		case PRS_ZOMBIE:
67799072Sjulian			state = "Z (zombie)";
67899072Sjulian			break;
67999072Sjulian		default:
68099072Sjulian			state = "? (unknown)";
68199072Sjulian			break;
68299072Sjulian		}
683170307Sjeff		PROC_SUNLOCK(p);
68499072Sjulian	}
68567588Sdes
68669995Sdes	fill_kinfo_proc(p, &kp);
68778025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
68878031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
68967588Sdes
69067588Sdes	/*
69167588Sdes	 * Credentials
69267588Sdes	 */
69378025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
69478025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
69573923Sjhb						p->p_pptr->p_pid : 0);
69678031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
69778031Sdes						p->p_ucred->cr_uid,
69878031Sdes						p->p_ucred->cr_svuid,
69978031Sdes						/* FreeBSD doesn't have fsuid */
70078031Sdes						p->p_ucred->cr_uid);
70178031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
70278031Sdes						p->p_ucred->cr_gid,
70378031Sdes						p->p_ucred->cr_svgid,
70478031Sdes						/* FreeBSD doesn't have fsgid */
70578031Sdes						p->p_ucred->cr_gid);
70678025Sdes	sbuf_cat(sb, "Groups:\t");
70767588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
70878031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
70971471Sjhb	PROC_UNLOCK(p);
71078025Sdes	sbuf_putc(sb, '\n');
711119068Sdes
71267588Sdes	/*
71367588Sdes	 * Memory
71469799Sdes	 *
71569799Sdes	 * While our approximation of VmLib may not be accurate (I
71669799Sdes	 * don't know of a simple way to verify it, and I'm not sure
71769799Sdes	 * it has much meaning anyway), I believe it's good enough.
71869799Sdes	 *
71969799Sdes	 * The same code that could (I think) accurately compute VmLib
72069799Sdes	 * could also compute VmLck, but I don't really care enough to
72169799Sdes	 * implement it. Submissions are welcome.
72267588Sdes	 */
723113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
72478025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
725113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
726113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
727113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
728113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
72969995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
73069995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
731113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
73267588Sdes
73367588Sdes	/*
73467588Sdes	 * Signal masks
73567588Sdes	 *
73667588Sdes	 * We support up to 128 signals, while Linux supports 32,
73767588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
73867588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
73967588Sdes	 *
74067588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
74167588Sdes	 * supports 64 signals, but this code is a long way from
74267588Sdes	 * running on anything but i386, so ignore that for now.
74367588Sdes	 */
74471471Sjhb	PROC_LOCK(p);
745104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
74669799Sdes	/*
74769799Sdes	 * I can't seem to find out where the signal mask is in
74869799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
74969799Sdes	 */
75078025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
751114983Sjhb	ps = p->p_sigacts;
752114983Sjhb	mtx_lock(&ps->ps_mtx);
753114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
754114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
755114983Sjhb	mtx_unlock(&ps->ps_mtx);
75671471Sjhb	PROC_UNLOCK(p);
757119068Sdes
75867588Sdes	/*
75967588Sdes	 * Linux also prints the capability masks, but we don't have
76067588Sdes	 * capabilities yet, and when we do get them they're likely to
76167588Sdes	 * be meaningless to Linux programs, so we lie. XXX
76267588Sdes	 */
76378025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
76478025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
76578025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
766119068Sdes
76778025Sdes	return (0);
76867588Sdes}
76974135Sjlemon
770119911Sdes
77178113Sdes/*
772119911Sdes * Filler function for proc/pid/cwd
773119911Sdes */
774119911Sdesstatic int
775119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
776119911Sdes{
777119911Sdes	char *fullpath = "unknown";
778119911Sdes	char *freepath = NULL;
779119911Sdes
780119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
781119911Sdes	sbuf_printf(sb, "%s", fullpath);
782119911Sdes	if (freepath)
783119911Sdes		free(freepath, M_TEMP);
784119911Sdes	return (0);
785119911Sdes}
786119911Sdes
787119911Sdes/*
788119911Sdes * Filler function for proc/pid/root
789119911Sdes */
790119911Sdesstatic int
791119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
792119911Sdes{
793119911Sdes	struct vnode *rvp;
794119911Sdes	char *fullpath = "unknown";
795119911Sdes	char *freepath = NULL;
796119911Sdes
797119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
798119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
799119911Sdes	sbuf_printf(sb, "%s", fullpath);
800119911Sdes	if (freepath)
801119911Sdes		free(freepath, M_TEMP);
802119911Sdes	return (0);
803119911Sdes}
804119911Sdes
805119911Sdes/*
80678113Sdes * Filler function for proc/pid/cmdline
80778113Sdes */
80878025Sdesstatic int
80978113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
81078113Sdes{
81178113Sdes	struct ps_strings pstr;
812138281Scperciva	char **ps_argvstr;
81378113Sdes	int error, i;
81478113Sdes
81578113Sdes	/*
81678113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
81778113Sdes	 * revert back to the old way which only implements full cmdline
81878113Sdes	 * for the currept process and just p->p_comm for all other
81978113Sdes	 * processes.
82078113Sdes	 * Note that if the argv is no longer available, we deliberately
82178113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
82278113Sdes	 * Linux behaviour is to return zero-length in this case.
82378113Sdes	 */
82478113Sdes
82594620Sjhb	PROC_LOCK(p);
826127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
82794620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
82894620Sjhb		PROC_UNLOCK(p);
82994620Sjhb	} else if (p != td->td_proc) {
83094620Sjhb		PROC_UNLOCK(p);
83194620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
83294620Sjhb	} else {
83394620Sjhb		PROC_UNLOCK(p);
834103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
835103767Sjake		    sizeof(pstr));
83694620Sjhb		if (error)
83794620Sjhb			return (error);
838138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
839138281Scperciva			return (E2BIG);
840138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
841138281Scperciva		    M_TEMP, M_WAITOK);
842138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
843138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
844138281Scperciva		if (error) {
845138281Scperciva			free(ps_argvstr, M_TEMP);
846138281Scperciva			return (error);
847138281Scperciva		}
84894620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
849138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
85094620Sjhb			sbuf_printf(sb, "%c", '\0');
85178113Sdes		}
852138281Scperciva		free(ps_argvstr, M_TEMP);
85378113Sdes	}
85478113Sdes
85578113Sdes	return (0);
85678113Sdes}
85778113Sdes
85878113Sdes/*
859116173Sobrien * Filler function for proc/pid/environ
860116173Sobrien */
861116173Sobrienstatic int
862116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
863116173Sobrien{
864168762Sdes
865116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
866116173Sobrien	return (0);
867116173Sobrien}
868116173Sobrien
869116173Sobrien/*
870116173Sobrien * Filler function for proc/pid/maps
871116173Sobrien */
872116173Sobrienstatic int
873116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
874116173Sobrien{
875121265Scognet	char mebuffer[512];
876121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
877169156Salc	vm_map_entry_t entry, tmp_entry;
878121265Scognet	vm_object_t obj, tobj, lobj;
879169156Salc	vm_offset_t saved_end;
880121265Scognet	vm_ooffset_t off = 0;
881121265Scognet	char *name = "", *freename = NULL;
882121265Scognet	size_t len;
883121265Scognet	ino_t ino;
884169156Salc	unsigned int last_timestamp;
885121265Scognet	int ref_count, shadow_count, flags;
886121265Scognet	int error;
887137507Sphk	struct vnode *vp;
888137507Sphk	struct vattr vat;
889161094Skib	int locked;
890168762Sdes
891121246Scognet	PROC_LOCK(p);
892121246Scognet	error = p_candebug(td, p);
893121246Scognet	PROC_UNLOCK(p);
894121246Scognet	if (error)
895121246Scognet		return (error);
896168762Sdes
897121246Scognet	if (uio->uio_rw != UIO_READ)
898121246Scognet		return (EOPNOTSUPP);
899168762Sdes
900121246Scognet	if (uio->uio_offset != 0)
901121246Scognet		return (0);
902168762Sdes
903121246Scognet	error = 0;
904169156Salc	vm_map_lock_read(map);
905168762Sdes	for (entry = map->header.next;
906121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
907121246Scognet	    entry = entry->next) {
908121265Scognet		name = "";
909121265Scognet		freename = NULL;
910121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
911121246Scognet			continue;
912169156Salc		saved_end = entry->end;
913121246Scognet		obj = entry->object.vm_object;
914169156Salc		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
915169156Salc			VM_OBJECT_LOCK(tobj);
916169156Salc			if (lobj != obj)
917169156Salc				VM_OBJECT_UNLOCK(lobj);
918121246Scognet			lobj = tobj;
919169156Salc		}
920121246Scognet		ino = 0;
921121246Scognet		if (lobj) {
922121246Scognet			off = IDX_TO_OFF(lobj->size);
923161094Skib			if (lobj->type == OBJT_VNODE) {
924161094Skib				vp = lobj->handle;
925161094Skib				if (vp)
926161094Skib					vref(vp);
927121246Scognet			}
928161094Skib			else
929161094Skib				vp = NULL;
930169156Salc			if (lobj != obj)
931169156Salc				VM_OBJECT_UNLOCK(lobj);
932121246Scognet			flags = obj->flags;
933121246Scognet			ref_count = obj->ref_count;
934121246Scognet			shadow_count = obj->shadow_count;
935169156Salc			VM_OBJECT_UNLOCK(obj);
936161094Skib			if (vp) {
937161094Skib				vn_fullpath(td, vp, &name, &freename);
938161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
939175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
940161094Skib				VOP_GETATTR(vp, &vat, td->td_ucred, td);
941161094Skib				ino = vat.va_fileid;
942161094Skib				vput(vp);
943161094Skib				VFS_UNLOCK_GIANT(locked);
944161094Skib			}
945121246Scognet		} else {
946121246Scognet			flags = 0;
947121246Scognet			ref_count = 0;
948121246Scognet			shadow_count = 0;
949121246Scognet		}
950168762Sdes
951121246Scognet		/*
952168762Sdes		 * format:
953121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
954121246Scognet		 */
955121246Scognet		snprintf(mebuffer, sizeof mebuffer,
956121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
957121246Scognet		    (u_long)entry->start, (u_long)entry->end,
958121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
959121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
960121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
961121246Scognet		    "p",
962121265Scognet		    (u_long)off,
963121246Scognet		    0,
964121246Scognet		    0,
965121265Scognet		    (u_long)ino,
966121246Scognet		    *name ? "     " : "",
967121246Scognet		    name
968121246Scognet		    );
969121246Scognet		if (freename)
970121246Scognet			free(freename, M_TEMP);
971121246Scognet		len = strlen(mebuffer);
972121246Scognet		if (len > uio->uio_resid)
973121246Scognet			len = uio->uio_resid; /*
974121246Scognet					       * XXX We should probably return
975121246Scognet					       * EFBIG here, as in procfs.
976121246Scognet					       */
977169156Salc		last_timestamp = map->timestamp;
978169156Salc		vm_map_unlock_read(map);
979121246Scognet		error = uiomove(mebuffer, len, uio);
980169156Salc		vm_map_lock_read(map);
981121246Scognet		if (error)
982121246Scognet			break;
983169156Salc		if (last_timestamp + 1 != map->timestamp) {
984169156Salc			/*
985169156Salc			 * Look again for the entry because the map was
986169156Salc			 * modified while it was unlocked.  Specifically,
987169156Salc			 * the entry may have been clipped, merged, or deleted.
988169156Salc			 */
989169156Salc			vm_map_lookup_entry(map, saved_end - 1, &tmp_entry);
990169156Salc			entry = tmp_entry;
991169156Salc		}
992121246Scognet	}
993169156Salc	vm_map_unlock_read(map);
994168762Sdes
995121246Scognet	return (error);
996168762Sdes}
997168762Sdes
998116173Sobrien/*
99978113Sdes * Filler function for proc/net/dev
100078113Sdes */
100178025Sdesstatic int
100278025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
100374135Sjlemon{
100485129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
100574135Sjlemon	struct ifnet *ifp;
100674135Sjlemon
100785129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
100883926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
100985129Sdes	    "bytes    packets errs drop fifo frame compressed",
101083926Sdes	    "bytes    packets errs drop fifo frame compressed");
101174135Sjlemon
1012108172Shsu	IFNET_RLOCK();
1013181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
101485129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
101585129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
101683926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
101783926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
101883926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
101983926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
102074135Sjlemon	}
1021108172Shsu	IFNET_RUNLOCK();
1022119068Sdes
102378025Sdes	return (0);
102474135Sjlemon}
102574135Sjlemon
1026158311Sambrisko/*
1027167159Sjkim * Filler function for proc/sys/kernel/osrelease
1028167159Sjkim */
1029167159Sjkimstatic int
1030167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1031167159Sjkim{
1032167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1033167159Sjkim
1034167159Sjkim	linux_get_osrelease(td, osrelease);
1035167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1036167159Sjkim
1037167159Sjkim	return (0);
1038167159Sjkim}
1039167159Sjkim
1040167159Sjkim/*
1041167159Sjkim * Filler function for proc/sys/kernel/ostype
1042167159Sjkim */
1043167159Sjkimstatic int
1044167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1045167159Sjkim{
1046167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1047167159Sjkim
1048167159Sjkim	linux_get_osname(td, osname);
1049167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1050167159Sjkim
1051167159Sjkim	return (0);
1052167159Sjkim}
1053167159Sjkim
1054167159Sjkim/*
1055167159Sjkim * Filler function for proc/sys/kernel/version
1056167159Sjkim */
1057167159Sjkimstatic int
1058167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1059167159Sjkim{
1060168762Sdes
1061167159Sjkim	linprocfs_osbuild(td, sb);
1062167159Sjkim	sbuf_cat(sb, "\n");
1063167159Sjkim	return (0);
1064167159Sjkim}
1065167159Sjkim
1066167159Sjkim/*
1067164692Sjkim * Filler function for proc/sys/kernel/msgmni
1068164692Sjkim */
1069164692Sjkimstatic int
1070164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1071164692Sjkim{
1072164692Sjkim
1073168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1074164692Sjkim	return (0);
1075164692Sjkim}
1076164692Sjkim
1077164692Sjkim/*
1078163251Skeramida * Filler function for proc/sys/kernel/pid_max
1079163129Snetchild */
1080163129Snetchildstatic int
1081163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1082163129Snetchild{
1083163757Snetchild
1084163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1085163129Snetchild	return (0);
1086163129Snetchild}
1087163129Snetchild
1088163129Snetchild/*
1089164692Sjkim * Filler function for proc/sys/kernel/sem
1090164692Sjkim */
1091164692Sjkimstatic int
1092164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1093164692Sjkim{
1094164692Sjkim
1095168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1096168067Sjkim	    seminfo.semopm, seminfo.semmni);
1097164692Sjkim	return (0);
1098164692Sjkim}
1099164692Sjkim
1100164692Sjkim/*
1101158311Sambrisko * Filler function for proc/scsi/device_info
1102158311Sambrisko */
1103158311Sambriskostatic int
1104158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1105158311Sambrisko{
1106168762Sdes
1107158311Sambrisko	return (0);
1108158311Sambrisko}
1109158311Sambrisko
1110158311Sambrisko/*
1111158311Sambrisko * Filler function for proc/scsi/scsi
1112158311Sambrisko */
1113158311Sambriskostatic int
1114158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1115158311Sambrisko{
1116168762Sdes
1117158311Sambrisko	return (0);
1118158311Sambrisko}
1119158311Sambrisko
112085538Sphkextern struct cdevsw *cdevsw[];
112185538Sphk
112278113Sdes/*
112378113Sdes * Filler function for proc/devices
112478113Sdes */
112578025Sdesstatic int
112678025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
112774135Sjlemon{
1128158311Sambrisko	char *char_devices;
112978025Sdes	sbuf_printf(sb, "Character devices:\n");
113074135Sjlemon
1131158311Sambrisko	char_devices = linux_get_char_devices();
1132158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1133158311Sambrisko	linux_free_get_char_devices(char_devices);
113474135Sjlemon
113578025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1136119068Sdes
113778025Sdes	return (0);
113874135Sjlemon}
113974135Sjlemon
114078113Sdes/*
114178113Sdes * Filler function for proc/cmdline
114278113Sdes */
114378025Sdesstatic int
114478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
114574135Sjlemon{
1146168762Sdes
114778025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
114878025Sdes	sbuf_printf(sb, " ro root=302\n");
114978025Sdes	return (0);
115078025Sdes}
115174135Sjlemon
115283926Sdes#if 0
115378025Sdes/*
115483926Sdes * Filler function for proc/modules
115583926Sdes */
115683926Sdesstatic int
115783926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
115883926Sdes{
115983926Sdes	struct linker_file *lf;
1160119068Sdes
116183926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
116283926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
116383926Sdes		    (unsigned long)lf->size, lf->refs);
116483926Sdes	}
116583926Sdes	return (0);
116683926Sdes}
116783926Sdes#endif
116883926Sdes
116983926Sdes/*
117085129Sdes * Constructor
117178025Sdes */
117285129Sdesstatic int
117385129Sdeslinprocfs_init(PFS_INIT_ARGS)
117485129Sdes{
117585129Sdes	struct pfs_node *root;
117685129Sdes	struct pfs_node *dir;
117774135Sjlemon
117885129Sdes	root = pi->pi_root;
117978025Sdes
1180119923Sdes	/* /proc/... */
1181119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1182167482Sdes	    NULL, NULL, NULL, PFS_RD);
1183119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1184167482Sdes	    NULL, NULL, NULL, PFS_RD);
1185119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1186167482Sdes	    NULL, NULL, NULL, PFS_RD);
1187119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1188167482Sdes	    NULL, NULL, NULL, PFS_RD);
1189119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1190167482Sdes	    NULL, NULL, NULL, PFS_RD);
119183926Sdes#if 0
1192119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1193167482Sdes	    NULL, NULL, NULL, PFS_RD);
119483926Sdes#endif
1195158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1196167482Sdes	    NULL, NULL, NULL, PFS_RD);
1197119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1198167482Sdes	    NULL, NULL, NULL, PFS_RD);
119987543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1200167482Sdes	    NULL, NULL, NULL, 0);
1201119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1202167482Sdes	    NULL, NULL, NULL, PFS_RD);
1203119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1204167482Sdes	    NULL, NULL, NULL, PFS_RD);
1205119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1206167482Sdes	    NULL, NULL, NULL, PFS_RD);
120778025Sdes
1208119923Sdes	/* /proc/net/... */
1209167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
121085129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1211167482Sdes	    NULL, NULL, NULL, PFS_RD);
121278025Sdes
1213119923Sdes	/* /proc/<pid>/... */
1214167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
121585129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1216167482Sdes	    NULL, NULL, NULL, PFS_RD);
1217119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1218167482Sdes	    NULL, NULL, NULL, 0);
1219116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1220167482Sdes	    NULL, NULL, NULL, PFS_RD);
122187543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1222167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1223116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1224167482Sdes	    NULL, NULL, NULL, PFS_RD);
122585129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1226167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1227119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1228167482Sdes	    NULL, NULL, NULL, 0);
122985129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1230167482Sdes	    NULL, NULL, NULL, PFS_RD);
1231119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1232167482Sdes	    NULL, NULL, NULL, PFS_RD);
123385129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1234167482Sdes	    NULL, NULL, NULL, PFS_RD);
123585129Sdes
1236158311Sambrisko	/* /proc/scsi/... */
1237167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1238158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1239167482Sdes	    NULL, NULL, NULL, PFS_RD);
1240158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1241167482Sdes	    NULL, NULL, NULL, PFS_RD);
1242163129Snetchild
1243163129Snetchild	/* /proc/sys/... */
1244167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1245163129Snetchild	/* /proc/sys/kernel/... */
1246167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1247167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1248167482Sdes	    NULL, NULL, NULL, PFS_RD);
1249167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1250167482Sdes	    NULL, NULL, NULL, PFS_RD);
1251167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1252167482Sdes	    NULL, NULL, NULL, PFS_RD);
1253164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1254167482Sdes	    NULL, NULL, NULL, PFS_RD);
1255163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1256167482Sdes	    NULL, NULL, NULL, PFS_RD);
1257164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1258167482Sdes	    NULL, NULL, NULL, PFS_RD);
1259163129Snetchild
126085129Sdes	return (0);
126185129Sdes}
126285129Sdes
126385129Sdes/*
126485129Sdes * Destructor
126585129Sdes */
126685129Sdesstatic int
126785129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
126885129Sdes{
126985129Sdes
127085129Sdes	/* nothing to do, pseudofs will GC */
127185129Sdes	return (0);
127285129Sdes}
127385129Sdes
127485129SdesPSEUDOFS(linprocfs, 1);
127578025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
127678025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1277168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1278168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1279