linprocfs.c revision 181803
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 181803 2008-08-17 23:27:27Z bz $");
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>
50177785Skib#include <sys/fcntl.h>
51119911Sdes#include <sys/filedesc.h>
5276166Smarkm#include <sys/jail.h>
5365633Sdes#include <sys/kernel.h>
5483926Sdes#include <sys/linker.h>
5576166Smarkm#include <sys/lock.h>
5674135Sjlemon#include <sys/malloc.h>
5778025Sdes#include <sys/mount.h>
58168067Sjkim#include <sys/msg.h>
5976827Salfred#include <sys/mutex.h>
6085289Sdes#include <sys/namei.h>
6165633Sdes#include <sys/proc.h>
6265633Sdes#include <sys/resourcevar.h>
6369995Sdes#include <sys/sbuf.h>
64168067Sjkim#include <sys/sem.h>
65123246Sdes#include <sys/smp.h>
6683926Sdes#include <sys/socket.h>
6776839Sjlemon#include <sys/sysctl.h>
6883926Sdes#include <sys/systm.h>
69159995Snetchild#include <sys/time.h>
7065633Sdes#include <sys/tty.h>
7183926Sdes#include <sys/user.h>
7283926Sdes#include <sys/vmmeter.h>
7359412Smsmith#include <sys/vnode.h>
74181803Sbz#include <sys/vimage.h>
7559412Smsmith
7683926Sdes#include <net/if.h>
7783926Sdes
7859412Smsmith#include <vm/vm.h>
7959412Smsmith#include <vm/pmap.h>
8067588Sdes#include <vm/vm_map.h>
8159412Smsmith#include <vm/vm_param.h>
8260860Sdes#include <vm/vm_object.h>
8359412Smsmith#include <vm/swap_pager.h>
8469799Sdes
8567589Sdes#include <machine/clock.h>
8678113Sdes
87133822Stjr#if defined(__i386__) || defined(__amd64__)
8867589Sdes#include <machine/cputypes.h>
8959412Smsmith#include <machine/md_var.h>
90133822Stjr#endif /* __i386__ || __amd64__ */
9159412Smsmith
92133822Stjr#include "opt_compat.h"
93140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
94140214Sobrien#include <machine/../linux32/linux.h>
95140214Sobrien#else
9687275Srwatson#include <machine/../linux/linux.h>
97133822Stjr#endif
9885129Sdes#include <compat/linux/linux_ioctl.h>
9969995Sdes#include <compat/linux/linux_mib.h>
10085289Sdes#include <compat/linux/linux_util.h>
10178025Sdes#include <fs/pseudofs/pseudofs.h>
10284248Sdes#include <fs/procfs/procfs.h>
10359412Smsmith
10467588Sdes/*
10567588Sdes * Various conversion macros
10667588Sdes */
10776405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10867588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10967588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11069799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11167588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11267588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11374135Sjlemon
114159995Snetchild/**
115159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
116159995Snetchild *
117159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
118159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
119172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
120159995Snetchild * or stopped, or process is paging respectively.
121159995Snetchild *
122159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
123159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
124159995Snetchild *
125159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
126159995Snetchild * map our states to suitable linux states.
127159995Snetchild */
128166140Snetchildstatic char linux_state[] = "RRSTZDD";
129159995Snetchild
13078113Sdes/*
13178113Sdes * Filler function for proc/meminfo
13278113Sdes */
13378025Sdesstatic int
13478025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13559412Smsmith{
13659412Smsmith	unsigned long memtotal;		/* total memory in bytes */
13759412Smsmith	unsigned long memused;		/* used memory in bytes */
13859412Smsmith	unsigned long memfree;		/* free memory in bytes */
13959412Smsmith	unsigned long memshared;	/* shared memory ??? */
14059412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
141113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
142113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
143113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14460860Sdes	vm_object_t object;
145117723Sphk	int i, j;
14659412Smsmith
14759412Smsmith	memtotal = physmem * PAGE_SIZE;
14859412Smsmith	/*
14959412Smsmith	 * The correct thing here would be:
15059412Smsmith	 *
151170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
15259412Smsmith	memused = memtotal - memfree;
15359412Smsmith	 *
15459412Smsmith	 * but it might mislead linux binaries into thinking there
15559412Smsmith	 * is very little memory left, so we cheat and tell them that
15659412Smsmith	 * all memory that isn't wired down is free.
15759412Smsmith	 */
158170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
15959412Smsmith	memfree = memtotal - memused;
160117723Sphk	swap_pager_status(&i, &j);
161153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
162153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
163117723Sphk	swapfree = swaptotal - swapused;
16460860Sdes	memshared = 0;
165124082Salc	mtx_lock(&vm_object_list_mtx);
16671471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
16760860Sdes		if (object->shadow_count > 1)
16860860Sdes			memshared += object->resident_page_count;
169124082Salc	mtx_unlock(&vm_object_list_mtx);
17060860Sdes	memshared *= PAGE_SIZE;
17159412Smsmith	/*
17259412Smsmith	 * We'd love to be able to write:
17359412Smsmith	 *
17459412Smsmith	buffers = bufspace;
17559412Smsmith	 *
17659412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
17759412Smsmith	 * like unstaticizing it just for linprocfs's sake.
17859412Smsmith	 */
17959412Smsmith	buffers = 0;
180170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18159412Smsmith
18278025Sdes	sbuf_printf(sb,
18378031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18469799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18576839Sjlemon	    "Swap: %llu %llu %llu\n"
18669799Sdes	    "MemTotal: %9lu kB\n"
18769799Sdes	    "MemFree:  %9lu kB\n"
18869799Sdes	    "MemShared:%9lu kB\n"
18969799Sdes	    "Buffers:  %9lu kB\n"
19069799Sdes	    "Cached:   %9lu kB\n"
19176839Sjlemon	    "SwapTotal:%9llu kB\n"
19276839Sjlemon	    "SwapFree: %9llu kB\n",
19369799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19469799Sdes	    swaptotal, swapused, swapfree,
19569799Sdes	    B2K(memtotal), B2K(memfree),
19669799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
19769799Sdes	    B2K(swaptotal), B2K(swapfree));
19859412Smsmith
19978025Sdes	return (0);
20059412Smsmith}
20159412Smsmith
202133822Stjr#if defined(__i386__) || defined(__amd64__)
20378113Sdes/*
204133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20578113Sdes */
20678113Sdesstatic int
20778113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
20878113Sdes{
209159544Sdes	int hw_model[2];
210159544Sdes	char model[128];
211159544Sdes	size_t size;
212123246Sdes	int class, fqmhz, fqkhz;
213118421Sdes	int i;
21459412Smsmith
21569799Sdes	/*
21678031Sdes	 * We default the flags to include all non-conflicting flags,
21778031Sdes	 * and the Intel versions of conflicting flags.
21869799Sdes	 */
21978031Sdes	static char *flags[] = {
22078031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22178031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22278031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22378031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22478031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22578031Sdes		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22667589Sdes		"3dnowext", "3dnow"
22767589Sdes	};
22867589Sdes
22959412Smsmith	switch (cpu_class) {
230133822Stjr#ifdef __i386__
23159412Smsmith	case CPUCLASS_286:
23267589Sdes		class = 2;
23359412Smsmith		break;
23459412Smsmith	case CPUCLASS_386:
23567589Sdes		class = 3;
23659412Smsmith		break;
23759412Smsmith	case CPUCLASS_486:
23867589Sdes		class = 4;
23959412Smsmith		break;
24059412Smsmith	case CPUCLASS_586:
24167589Sdes		class = 5;
24259412Smsmith		break;
24359412Smsmith	case CPUCLASS_686:
24467589Sdes		class = 6;
24559412Smsmith		break;
24659412Smsmith	default:
24778031Sdes		class = 0;
24859412Smsmith		break;
249159170Sdes#else /* __amd64__ */
250133822Stjr	default:
251159170Sdes		class = 15;
252133822Stjr		break;
253133822Stjr#endif
25459412Smsmith	}
25559412Smsmith
256159544Sdes	hw_model[0] = CTL_HW;
257159544Sdes	hw_model[1] = HW_MODEL;
258159544Sdes	model[0] = '\0';
259159544Sdes	size = sizeof(model);
260159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
261159544Sdes		strcpy(model, "unknown");
262123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
263118421Sdes		sbuf_printf(sb,
264118421Sdes		    "processor\t: %d\n"
265118421Sdes		    "vendor_id\t: %.20s\n"
266118421Sdes		    "cpu family\t: %d\n"
267118421Sdes		    "model\t\t: %d\n"
268159544Sdes		    "model name\t: %s\n"
269118421Sdes		    "stepping\t: %d\n",
270159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
271159544Sdes		/* XXX per-cpu vendor / class / model / id? */
272118421Sdes	}
27359412Smsmith
27478031Sdes	sbuf_cat(sb,
27578031Sdes	    "flags\t\t:");
27667589Sdes
27778031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
27867589Sdes		flags[16] = "fcmov";
27978031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
28067589Sdes		flags[24] = "cxmmx";
28178031Sdes	}
282119068Sdes
28378031Sdes	for (i = 0; i < 32; i++)
28467589Sdes		if (cpu_feature & (1 << i))
28578025Sdes			sbuf_printf(sb, " %s", flags[i]);
28678025Sdes	sbuf_cat(sb, "\n");
28778031Sdes	if (class >= 5) {
28869799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
28969799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
29078025Sdes		sbuf_printf(sb,
29169799Sdes		    "cpu MHz\t\t: %d.%02d\n"
29269799Sdes		    "bogomips\t: %d.%02d\n",
29369799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
29478031Sdes	}
29569995Sdes
29678025Sdes	return (0);
29759412Smsmith}
298133822Stjr#endif /* __i386__ || __amd64__ */
29965633Sdes
30078113Sdes/*
30185289Sdes * Filler function for proc/mtab
30285289Sdes *
30385289Sdes * This file doesn't exist in Linux' procfs, but is included here so
30485289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
30585289Sdes */
30685289Sdesstatic int
30785289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
30885289Sdes{
30985289Sdes	struct nameidata nd;
31085289Sdes	struct mount *mp;
31191334Sjulian	const char *lep;
31291334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
31385289Sdes	size_t lep_len;
31485289Sdes	int error;
31585289Sdes
31685289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
317168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
31885289Sdes	flep = NULL;
319168942Sdes	error = namei(&nd);
320168942Sdes	VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
321168942Sdes	if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
32285289Sdes		lep = linux_emul_path;
32391334Sjulian	else
32491334Sjulian		lep = dlep;
32585289Sdes	lep_len = strlen(lep);
326119068Sdes
32785289Sdes	mtx_lock(&mountlist_mtx);
32885289Sdes	error = 0;
32985289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
33085289Sdes		/* determine device name */
33185289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
332119068Sdes
33385289Sdes		/* determine mount point */
33485289Sdes		mntto = mp->mnt_stat.f_mntonname;
33585289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
33685289Sdes		    mntto[lep_len] == '/')
33785289Sdes			mntto += lep_len;
33885289Sdes
33985289Sdes		/* determine fs type */
34085289Sdes		fstype = mp->mnt_stat.f_fstypename;
34185289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
34285289Sdes			mntfrom = fstype = "proc";
34385289Sdes		else if (strcmp(fstype, "procfs") == 0)
34485289Sdes			continue;
345119068Sdes
346158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
347158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
348158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
349158311Sambrisko		} else {
350158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
351158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
352158311Sambrisko		}
35385289Sdes#define ADD_OPTION(opt, name) \
35485289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
35585289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
35685289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
35785289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
35885289Sdes		ADD_OPTION(MNT_UNION,		"union");
35985289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
36085289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
36185289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
36285289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
36385289Sdes#undef ADD_OPTION
36485289Sdes		/* a real Linux mtab will also show NFS options */
36585289Sdes		sbuf_printf(sb, " 0 0\n");
36685289Sdes	}
36785289Sdes	mtx_unlock(&mountlist_mtx);
36885289Sdes	if (flep != NULL)
36985289Sdes		free(flep, M_TEMP);
37085289Sdes	return (error);
37185289Sdes}
37285289Sdes
37385289Sdes/*
37478113Sdes * Filler function for proc/stat
37578113Sdes */
37678025Sdesstatic int
37778025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
37865633Sdes{
379174070Speter	struct pcpu *pcpu;
380174070Speter	long cp_time[CPUSTATES];
381174070Speter	long *cp;
382123246Sdes	int i;
383120339Sdes
384174070Speter	read_cpu_time(cp_time);
385120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
386120339Sdes	    T2J(cp_time[CP_USER]),
387120339Sdes	    T2J(cp_time[CP_NICE]),
388120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
389120339Sdes	    T2J(cp_time[CP_IDLE]));
390174070Speter	for (i = 0; i <= mp_maxid; ++i) {
391174070Speter		if (CPU_ABSENT(i))
392174070Speter			continue;
393174070Speter		pcpu = pcpu_find(i);
394174070Speter		cp = pcpu->pc_cp_time;
395143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
396174070Speter		    T2J(cp[CP_USER]),
397174070Speter		    T2J(cp[CP_NICE]),
398174070Speter		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
399174070Speter		    T2J(cp[CP_IDLE]));
400174070Speter	}
40178025Sdes	sbuf_printf(sb,
40269799Sdes	    "disk 0 0 0 0\n"
40369799Sdes	    "page %u %u\n"
40469799Sdes	    "swap %u %u\n"
40569799Sdes	    "intr %u\n"
40669799Sdes	    "ctxt %u\n"
40785657Sdillon	    "btime %lld\n",
408170170Sattilio	    cnt.v_vnodepgsin,
409170170Sattilio	    cnt.v_vnodepgsout,
410170170Sattilio	    cnt.v_swappgsin,
411170170Sattilio	    cnt.v_swappgsout,
412170170Sattilio	    cnt.v_intr,
413170170Sattilio	    cnt.v_swtch,
414113574Sjhb	    (long long)boottime.tv_sec);
41578025Sdes	return (0);
41665633Sdes}
41765633Sdes
41878113Sdes/*
41978113Sdes * Filler function for proc/uptime
42078113Sdes */
42178025Sdesstatic int
42278025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
42365633Sdes{
424174070Speter	long cp_time[CPUSTATES];
42565633Sdes	struct timeval tv;
42665633Sdes
42765633Sdes	getmicrouptime(&tv);
428174070Speter	read_cpu_time(cp_time);
42985657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
430113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
43169799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
43278025Sdes	return (0);
43365633Sdes}
43465633Sdes
43578113Sdes/*
436167159Sjkim * Get OS build date
437167159Sjkim */
438167159Sjkimstatic void
439167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
440167159Sjkim{
441167159Sjkim#if 0
442167159Sjkim	char osbuild[256];
443167159Sjkim	char *cp1, *cp2;
444167159Sjkim
445167159Sjkim	strncpy(osbuild, version, 256);
446167159Sjkim	osbuild[255] = '\0';
447167159Sjkim	cp1 = strstr(osbuild, "\n");
448167159Sjkim	cp2 = strstr(osbuild, ":");
449167159Sjkim	if (cp1 && cp2) {
450167159Sjkim		*cp1 = *cp2 = '\0';
451167159Sjkim		cp1 = strstr(osbuild, "#");
452167159Sjkim	} else
453167159Sjkim		cp1 = NULL;
454167159Sjkim	if (cp1)
455167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
456167159Sjkim	else
457167159Sjkim#endif
458167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
459167159Sjkim}
460167159Sjkim
461167159Sjkim/*
462167159Sjkim * Get OS builder
463167159Sjkim */
464167159Sjkimstatic void
465167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
466167159Sjkim{
467168762Sdes#if 0
468167159Sjkim	char builder[256];
469167159Sjkim	char *cp;
470167159Sjkim
471167159Sjkim	cp = strstr(version, "\n    ");
472167159Sjkim	if (cp) {
473167159Sjkim		strncpy(builder, cp + 5, 256);
474167159Sjkim		builder[255] = '\0';
475167159Sjkim		cp = strstr(builder, ":");
476167159Sjkim		if (cp)
477167159Sjkim			*cp = '\0';
478167159Sjkim	}
479167159Sjkim	if (cp)
480167159Sjkim		sbuf_cat(sb, builder);
481167159Sjkim	else
482168762Sdes#endif
483167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
484167159Sjkim}
485167159Sjkim
486167159Sjkim/*
48778113Sdes * Filler function for proc/version
48878113Sdes */
48978025Sdesstatic int
49078025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
49165633Sdes{
49287275Srwatson	char osname[LINUX_MAX_UTSNAME];
49387275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
49487275Srwatson
495112206Sjhb	linux_get_osname(td, osname);
496112206Sjhb	linux_get_osrelease(td, osrelease);
497167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
498167159Sjkim	linprocfs_osbuilder(td, sb);
499167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
500167159Sjkim	linprocfs_osbuild(td, sb);
501167159Sjkim	sbuf_cat(sb, "\n");
50287275Srwatson
50378025Sdes	return (0);
50465633Sdes}
50565633Sdes
50678113Sdes/*
50778113Sdes * Filler function for proc/loadavg
50878113Sdes */
50978025Sdesstatic int
51078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
51176839Sjlemon{
512168762Sdes
51378025Sdes	sbuf_printf(sb,
51476839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
51576839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
51676839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
51776839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
51876839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
51976839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
52076839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
52176839Sjlemon	    1,				/* number of running tasks */
52276839Sjlemon	    nprocs,			/* number of tasks */
52378116Sdes	    lastpid			/* the last pid */
52476839Sjlemon	);
52578025Sdes	return (0);
52676839Sjlemon}
52776839Sjlemon
52878113Sdes/*
52978113Sdes * Filler function for proc/pid/stat
53078113Sdes */
53178025Sdesstatic int
53278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
53367588Sdes{
53469995Sdes	struct kinfo_proc kp;
535166140Snetchild	char state;
536166140Snetchild	static int ratelimit = 0;
53767588Sdes
53894307Sjhb	PROC_LOCK(p);
53969995Sdes	fill_kinfo_proc(p, &kp);
54078025Sdes	sbuf_printf(sb, "%d", p->p_pid);
54178025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
54267588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
543166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
544166140Snetchild		state = 'R';
545166140Snetchild
546166141Snetchild		if (ratelimit == 0) {
547166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
548166162Snetchild			    kp.ki_stat, sizeof(linux_state));
549166141Snetchild			++ratelimit;
550166141Snetchild		}
551166140Snetchild	} else
552166140Snetchild		state = linux_state[kp.ki_stat - 1];
553166140Snetchild	PS_ADD("state",		"%c",	state);
55473923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
55567588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
55667588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
55791140Stanimura	PROC_UNLOCK(p);
55867588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
559159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
56067588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
561159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
562159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
563159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
564159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
565159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
566159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
567159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
568159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
569159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
570159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
571159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
572159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
573159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
574159995Snetchild	   It should be the number of jiffies between system boot and process
575159995Snetchild	   start. */
576159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
577159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
578159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
579159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
58069995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
58167588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
58267588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
583159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
584159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
585159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
586159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
587159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
588159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
58967588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
590159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
591159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
59269799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
593159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
594159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
595159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
59667588Sdes#undef PS_ADD
59778025Sdes	sbuf_putc(sb, '\n');
598119068Sdes
59978025Sdes	return (0);
60067588Sdes}
60167588Sdes
60267588Sdes/*
603119911Sdes * Filler function for proc/pid/statm
604119911Sdes */
605119911Sdesstatic int
606119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
607119911Sdes{
608119911Sdes	struct kinfo_proc kp;
609119911Sdes	segsz_t lsize;
610120340Sdes
611119911Sdes	PROC_LOCK(p);
612119911Sdes	fill_kinfo_proc(p, &kp);
613119911Sdes	PROC_UNLOCK(p);
614119911Sdes
615119911Sdes	/*
616119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
617119911Sdes	 * computation of lsize.
618119911Sdes	 */
619119911Sdes	/* size resident share trs drs lrs dt */
620119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
621119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
622119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
623119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
624119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
625119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
626119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
627119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
628119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
629119911Sdes
630119911Sdes	return (0);
631119911Sdes}
632119911Sdes
633119911Sdes/*
63478113Sdes * Filler function for proc/pid/status
63578113Sdes */
63678025Sdesstatic int
63778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
63867588Sdes{
63969995Sdes	struct kinfo_proc kp;
64067588Sdes	char *state;
64169799Sdes	segsz_t lsize;
64299072Sjulian	struct thread *td2;
643114983Sjhb	struct sigacts *ps;
64474135Sjlemon	int i;
64567588Sdes
646113611Sjhb	PROC_LOCK(p);
64799072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
64899072Sjulian
64999072Sjulian	if (P_SHOULDSTOP(p)) {
65099072Sjulian		state = "T (stopped)";
65199072Sjulian	} else {
652170307Sjeff		PROC_SLOCK(p);
65399072Sjulian		switch(p->p_state) {
65499072Sjulian		case PRS_NEW:
65599072Sjulian			state = "I (idle)";
65699072Sjulian			break;
65799072Sjulian		case PRS_NORMAL:
65899072Sjulian			if (p->p_flag & P_WEXIT) {
65999072Sjulian				state = "X (exiting)";
66099072Sjulian				break;
66199072Sjulian			}
66299072Sjulian			switch(td2->td_state) {
663103216Sjulian			case TDS_INHIBITED:
66499072Sjulian				state = "S (sleeping)";
66599072Sjulian				break;
66699072Sjulian			case TDS_RUNQ:
66799072Sjulian			case TDS_RUNNING:
66899072Sjulian				state = "R (running)";
66999072Sjulian				break;
67099072Sjulian			default:
67199072Sjulian				state = "? (unknown)";
67299072Sjulian				break;
67399072Sjulian			}
67499072Sjulian			break;
67599072Sjulian		case PRS_ZOMBIE:
67699072Sjulian			state = "Z (zombie)";
67799072Sjulian			break;
67899072Sjulian		default:
67999072Sjulian			state = "? (unknown)";
68099072Sjulian			break;
68199072Sjulian		}
682170307Sjeff		PROC_SUNLOCK(p);
68399072Sjulian	}
68467588Sdes
68569995Sdes	fill_kinfo_proc(p, &kp);
68678025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
68778031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
68867588Sdes
68967588Sdes	/*
69067588Sdes	 * Credentials
69167588Sdes	 */
69278025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
69378025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
69473923Sjhb						p->p_pptr->p_pid : 0);
69578031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
69678031Sdes						p->p_ucred->cr_uid,
69778031Sdes						p->p_ucred->cr_svuid,
69878031Sdes						/* FreeBSD doesn't have fsuid */
69978031Sdes						p->p_ucred->cr_uid);
70078031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
70178031Sdes						p->p_ucred->cr_gid,
70278031Sdes						p->p_ucred->cr_svgid,
70378031Sdes						/* FreeBSD doesn't have fsgid */
70478031Sdes						p->p_ucred->cr_gid);
70578025Sdes	sbuf_cat(sb, "Groups:\t");
70667588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
70778031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
70871471Sjhb	PROC_UNLOCK(p);
70978025Sdes	sbuf_putc(sb, '\n');
710119068Sdes
71167588Sdes	/*
71267588Sdes	 * Memory
71369799Sdes	 *
71469799Sdes	 * While our approximation of VmLib may not be accurate (I
71569799Sdes	 * don't know of a simple way to verify it, and I'm not sure
71669799Sdes	 * it has much meaning anyway), I believe it's good enough.
71769799Sdes	 *
71869799Sdes	 * The same code that could (I think) accurately compute VmLib
71969799Sdes	 * could also compute VmLck, but I don't really care enough to
72069799Sdes	 * implement it. Submissions are welcome.
72167588Sdes	 */
722113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
72378025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
724113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
725113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
726113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
727113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
72869995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
72969995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
730113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
73167588Sdes
73267588Sdes	/*
73367588Sdes	 * Signal masks
73467588Sdes	 *
73567588Sdes	 * We support up to 128 signals, while Linux supports 32,
73667588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
73767588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
73867588Sdes	 *
73967588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
74067588Sdes	 * supports 64 signals, but this code is a long way from
74167588Sdes	 * running on anything but i386, so ignore that for now.
74267588Sdes	 */
74371471Sjhb	PROC_LOCK(p);
744104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
74569799Sdes	/*
74669799Sdes	 * I can't seem to find out where the signal mask is in
74769799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
74869799Sdes	 */
74978025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
750114983Sjhb	ps = p->p_sigacts;
751114983Sjhb	mtx_lock(&ps->ps_mtx);
752114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
753114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
754114983Sjhb	mtx_unlock(&ps->ps_mtx);
75571471Sjhb	PROC_UNLOCK(p);
756119068Sdes
75767588Sdes	/*
75867588Sdes	 * Linux also prints the capability masks, but we don't have
75967588Sdes	 * capabilities yet, and when we do get them they're likely to
76067588Sdes	 * be meaningless to Linux programs, so we lie. XXX
76167588Sdes	 */
76278025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
76378025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
76478025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
765119068Sdes
76678025Sdes	return (0);
76767588Sdes}
76874135Sjlemon
769119911Sdes
77078113Sdes/*
771119911Sdes * Filler function for proc/pid/cwd
772119911Sdes */
773119911Sdesstatic int
774119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
775119911Sdes{
776119911Sdes	char *fullpath = "unknown";
777119911Sdes	char *freepath = NULL;
778119911Sdes
779119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
780119911Sdes	sbuf_printf(sb, "%s", fullpath);
781119911Sdes	if (freepath)
782119911Sdes		free(freepath, M_TEMP);
783119911Sdes	return (0);
784119911Sdes}
785119911Sdes
786119911Sdes/*
787119911Sdes * Filler function for proc/pid/root
788119911Sdes */
789119911Sdesstatic int
790119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
791119911Sdes{
792119911Sdes	struct vnode *rvp;
793119911Sdes	char *fullpath = "unknown";
794119911Sdes	char *freepath = NULL;
795119911Sdes
796119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
797119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
798119911Sdes	sbuf_printf(sb, "%s", fullpath);
799119911Sdes	if (freepath)
800119911Sdes		free(freepath, M_TEMP);
801119911Sdes	return (0);
802119911Sdes}
803119911Sdes
804119911Sdes/*
80578113Sdes * Filler function for proc/pid/cmdline
80678113Sdes */
80778025Sdesstatic int
80878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
80978113Sdes{
81078113Sdes	struct ps_strings pstr;
811138281Scperciva	char **ps_argvstr;
81278113Sdes	int error, i;
81378113Sdes
81478113Sdes	/*
81578113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
81678113Sdes	 * revert back to the old way which only implements full cmdline
81778113Sdes	 * for the currept process and just p->p_comm for all other
81878113Sdes	 * processes.
81978113Sdes	 * Note that if the argv is no longer available, we deliberately
82078113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
82178113Sdes	 * Linux behaviour is to return zero-length in this case.
82278113Sdes	 */
82378113Sdes
82494620Sjhb	PROC_LOCK(p);
825127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
82694620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
82794620Sjhb		PROC_UNLOCK(p);
82894620Sjhb	} else if (p != td->td_proc) {
82994620Sjhb		PROC_UNLOCK(p);
83094620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
83194620Sjhb	} else {
83294620Sjhb		PROC_UNLOCK(p);
833103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
834103767Sjake		    sizeof(pstr));
83594620Sjhb		if (error)
83694620Sjhb			return (error);
837138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
838138281Scperciva			return (E2BIG);
839138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
840138281Scperciva		    M_TEMP, M_WAITOK);
841138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
842138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
843138281Scperciva		if (error) {
844138281Scperciva			free(ps_argvstr, M_TEMP);
845138281Scperciva			return (error);
846138281Scperciva		}
84794620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
848138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
84994620Sjhb			sbuf_printf(sb, "%c", '\0');
85078113Sdes		}
851138281Scperciva		free(ps_argvstr, M_TEMP);
85278113Sdes	}
85378113Sdes
85478113Sdes	return (0);
85578113Sdes}
85678113Sdes
85778113Sdes/*
858116173Sobrien * Filler function for proc/pid/environ
859116173Sobrien */
860116173Sobrienstatic int
861116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
862116173Sobrien{
863168762Sdes
864116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
865116173Sobrien	return (0);
866116173Sobrien}
867116173Sobrien
868116173Sobrien/*
869116173Sobrien * Filler function for proc/pid/maps
870116173Sobrien */
871116173Sobrienstatic int
872116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
873116173Sobrien{
874121265Scognet	char mebuffer[512];
875121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
876169156Salc	vm_map_entry_t entry, tmp_entry;
877121265Scognet	vm_object_t obj, tobj, lobj;
878169156Salc	vm_offset_t saved_end;
879121265Scognet	vm_ooffset_t off = 0;
880121265Scognet	char *name = "", *freename = NULL;
881121265Scognet	size_t len;
882121265Scognet	ino_t ino;
883169156Salc	unsigned int last_timestamp;
884121265Scognet	int ref_count, shadow_count, flags;
885121265Scognet	int error;
886137507Sphk	struct vnode *vp;
887137507Sphk	struct vattr vat;
888161094Skib	int locked;
889168762Sdes
890121246Scognet	PROC_LOCK(p);
891121246Scognet	error = p_candebug(td, p);
892121246Scognet	PROC_UNLOCK(p);
893121246Scognet	if (error)
894121246Scognet		return (error);
895168762Sdes
896121246Scognet	if (uio->uio_rw != UIO_READ)
897121246Scognet		return (EOPNOTSUPP);
898168762Sdes
899121246Scognet	if (uio->uio_offset != 0)
900121246Scognet		return (0);
901168762Sdes
902121246Scognet	error = 0;
903169156Salc	vm_map_lock_read(map);
904168762Sdes	for (entry = map->header.next;
905121246Scognet	    ((uio->uio_resid > 0) && (entry != &map->header));
906121246Scognet	    entry = entry->next) {
907121265Scognet		name = "";
908121265Scognet		freename = NULL;
909121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
910121246Scognet			continue;
911169156Salc		saved_end = entry->end;
912121246Scognet		obj = entry->object.vm_object;
913169156Salc		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
914169156Salc			VM_OBJECT_LOCK(tobj);
915169156Salc			if (lobj != obj)
916169156Salc				VM_OBJECT_UNLOCK(lobj);
917121246Scognet			lobj = tobj;
918169156Salc		}
919121246Scognet		ino = 0;
920121246Scognet		if (lobj) {
921121246Scognet			off = IDX_TO_OFF(lobj->size);
922161094Skib			if (lobj->type == OBJT_VNODE) {
923161094Skib				vp = lobj->handle;
924161094Skib				if (vp)
925161094Skib					vref(vp);
926121246Scognet			}
927161094Skib			else
928161094Skib				vp = NULL;
929169156Salc			if (lobj != obj)
930169156Salc				VM_OBJECT_UNLOCK(lobj);
931121246Scognet			flags = obj->flags;
932121246Scognet			ref_count = obj->ref_count;
933121246Scognet			shadow_count = obj->shadow_count;
934169156Salc			VM_OBJECT_UNLOCK(obj);
935161094Skib			if (vp) {
936161094Skib				vn_fullpath(td, vp, &name, &freename);
937161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
938175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
939161094Skib				VOP_GETATTR(vp, &vat, td->td_ucred, td);
940161094Skib				ino = vat.va_fileid;
941161094Skib				vput(vp);
942161094Skib				VFS_UNLOCK_GIANT(locked);
943161094Skib			}
944121246Scognet		} else {
945121246Scognet			flags = 0;
946121246Scognet			ref_count = 0;
947121246Scognet			shadow_count = 0;
948121246Scognet		}
949168762Sdes
950121246Scognet		/*
951168762Sdes		 * format:
952121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
953121246Scognet		 */
954121246Scognet		snprintf(mebuffer, sizeof mebuffer,
955121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
956121246Scognet		    (u_long)entry->start, (u_long)entry->end,
957121246Scognet		    (entry->protection & VM_PROT_READ)?"r":"-",
958121246Scognet		    (entry->protection & VM_PROT_WRITE)?"w":"-",
959121246Scognet		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
960121246Scognet		    "p",
961121265Scognet		    (u_long)off,
962121246Scognet		    0,
963121246Scognet		    0,
964121265Scognet		    (u_long)ino,
965121246Scognet		    *name ? "     " : "",
966121246Scognet		    name
967121246Scognet		    );
968121246Scognet		if (freename)
969121246Scognet			free(freename, M_TEMP);
970121246Scognet		len = strlen(mebuffer);
971121246Scognet		if (len > uio->uio_resid)
972121246Scognet			len = uio->uio_resid; /*
973121246Scognet					       * XXX We should probably return
974121246Scognet					       * EFBIG here, as in procfs.
975121246Scognet					       */
976169156Salc		last_timestamp = map->timestamp;
977169156Salc		vm_map_unlock_read(map);
978121246Scognet		error = uiomove(mebuffer, len, uio);
979169156Salc		vm_map_lock_read(map);
980121246Scognet		if (error)
981121246Scognet			break;
982169156Salc		if (last_timestamp + 1 != map->timestamp) {
983169156Salc			/*
984169156Salc			 * Look again for the entry because the map was
985169156Salc			 * modified while it was unlocked.  Specifically,
986169156Salc			 * the entry may have been clipped, merged, or deleted.
987169156Salc			 */
988169156Salc			vm_map_lookup_entry(map, saved_end - 1, &tmp_entry);
989169156Salc			entry = tmp_entry;
990169156Salc		}
991121246Scognet	}
992169156Salc	vm_map_unlock_read(map);
993168762Sdes
994121246Scognet	return (error);
995168762Sdes}
996168762Sdes
997116173Sobrien/*
99878113Sdes * Filler function for proc/net/dev
99978113Sdes */
100078025Sdesstatic int
100178025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
100274135Sjlemon{
100385129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
100474135Sjlemon	struct ifnet *ifp;
100574135Sjlemon
100685129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
100783926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
100885129Sdes	    "bytes    packets errs drop fifo frame compressed",
100983926Sdes	    "bytes    packets errs drop fifo frame compressed");
101074135Sjlemon
1011108172Shsu	IFNET_RLOCK();
1012181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
101385129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
101485129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
101583926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
101683926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
101783926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
101883926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
101974135Sjlemon	}
1020108172Shsu	IFNET_RUNLOCK();
1021119068Sdes
102278025Sdes	return (0);
102374135Sjlemon}
102474135Sjlemon
1025158311Sambrisko/*
1026167159Sjkim * Filler function for proc/sys/kernel/osrelease
1027167159Sjkim */
1028167159Sjkimstatic int
1029167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1030167159Sjkim{
1031167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1032167159Sjkim
1033167159Sjkim	linux_get_osrelease(td, osrelease);
1034167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1035167159Sjkim
1036167159Sjkim	return (0);
1037167159Sjkim}
1038167159Sjkim
1039167159Sjkim/*
1040167159Sjkim * Filler function for proc/sys/kernel/ostype
1041167159Sjkim */
1042167159Sjkimstatic int
1043167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1044167159Sjkim{
1045167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1046167159Sjkim
1047167159Sjkim	linux_get_osname(td, osname);
1048167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1049167159Sjkim
1050167159Sjkim	return (0);
1051167159Sjkim}
1052167159Sjkim
1053167159Sjkim/*
1054167159Sjkim * Filler function for proc/sys/kernel/version
1055167159Sjkim */
1056167159Sjkimstatic int
1057167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1058167159Sjkim{
1059168762Sdes
1060167159Sjkim	linprocfs_osbuild(td, sb);
1061167159Sjkim	sbuf_cat(sb, "\n");
1062167159Sjkim	return (0);
1063167159Sjkim}
1064167159Sjkim
1065167159Sjkim/*
1066164692Sjkim * Filler function for proc/sys/kernel/msgmni
1067164692Sjkim */
1068164692Sjkimstatic int
1069164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1070164692Sjkim{
1071164692Sjkim
1072168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1073164692Sjkim	return (0);
1074164692Sjkim}
1075164692Sjkim
1076164692Sjkim/*
1077163251Skeramida * Filler function for proc/sys/kernel/pid_max
1078163129Snetchild */
1079163129Snetchildstatic int
1080163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1081163129Snetchild{
1082163757Snetchild
1083163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1084163129Snetchild	return (0);
1085163129Snetchild}
1086163129Snetchild
1087163129Snetchild/*
1088164692Sjkim * Filler function for proc/sys/kernel/sem
1089164692Sjkim */
1090164692Sjkimstatic int
1091164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1092164692Sjkim{
1093164692Sjkim
1094168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1095168067Sjkim	    seminfo.semopm, seminfo.semmni);
1096164692Sjkim	return (0);
1097164692Sjkim}
1098164692Sjkim
1099164692Sjkim/*
1100158311Sambrisko * Filler function for proc/scsi/device_info
1101158311Sambrisko */
1102158311Sambriskostatic int
1103158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1104158311Sambrisko{
1105168762Sdes
1106158311Sambrisko	return (0);
1107158311Sambrisko}
1108158311Sambrisko
1109158311Sambrisko/*
1110158311Sambrisko * Filler function for proc/scsi/scsi
1111158311Sambrisko */
1112158311Sambriskostatic int
1113158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1114158311Sambrisko{
1115168762Sdes
1116158311Sambrisko	return (0);
1117158311Sambrisko}
1118158311Sambrisko
111985538Sphkextern struct cdevsw *cdevsw[];
112085538Sphk
112178113Sdes/*
112278113Sdes * Filler function for proc/devices
112378113Sdes */
112478025Sdesstatic int
112578025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
112674135Sjlemon{
1127158311Sambrisko	char *char_devices;
112878025Sdes	sbuf_printf(sb, "Character devices:\n");
112974135Sjlemon
1130158311Sambrisko	char_devices = linux_get_char_devices();
1131158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1132158311Sambrisko	linux_free_get_char_devices(char_devices);
113374135Sjlemon
113478025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1135119068Sdes
113678025Sdes	return (0);
113774135Sjlemon}
113874135Sjlemon
113978113Sdes/*
114078113Sdes * Filler function for proc/cmdline
114178113Sdes */
114278025Sdesstatic int
114378025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
114474135Sjlemon{
1145168762Sdes
114678025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
114778025Sdes	sbuf_printf(sb, " ro root=302\n");
114878025Sdes	return (0);
114978025Sdes}
115074135Sjlemon
115183926Sdes#if 0
115278025Sdes/*
115383926Sdes * Filler function for proc/modules
115483926Sdes */
115583926Sdesstatic int
115683926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
115783926Sdes{
115883926Sdes	struct linker_file *lf;
1159119068Sdes
116083926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
116183926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
116283926Sdes		    (unsigned long)lf->size, lf->refs);
116383926Sdes	}
116483926Sdes	return (0);
116583926Sdes}
116683926Sdes#endif
116783926Sdes
116883926Sdes/*
116985129Sdes * Constructor
117078025Sdes */
117185129Sdesstatic int
117285129Sdeslinprocfs_init(PFS_INIT_ARGS)
117385129Sdes{
117485129Sdes	struct pfs_node *root;
117585129Sdes	struct pfs_node *dir;
117674135Sjlemon
117785129Sdes	root = pi->pi_root;
117878025Sdes
1179119923Sdes	/* /proc/... */
1180119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1181167482Sdes	    NULL, NULL, NULL, PFS_RD);
1182119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1183167482Sdes	    NULL, NULL, NULL, PFS_RD);
1184119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1185167482Sdes	    NULL, NULL, NULL, PFS_RD);
1186119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1187167482Sdes	    NULL, NULL, NULL, PFS_RD);
1188119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1189167482Sdes	    NULL, NULL, NULL, PFS_RD);
119083926Sdes#if 0
1191119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1192167482Sdes	    NULL, NULL, NULL, PFS_RD);
119383926Sdes#endif
1194158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1195167482Sdes	    NULL, NULL, NULL, PFS_RD);
1196119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1197167482Sdes	    NULL, NULL, NULL, PFS_RD);
119887543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1199167482Sdes	    NULL, NULL, NULL, 0);
1200119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1201167482Sdes	    NULL, NULL, NULL, PFS_RD);
1202119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1203167482Sdes	    NULL, NULL, NULL, PFS_RD);
1204119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1205167482Sdes	    NULL, NULL, NULL, PFS_RD);
120678025Sdes
1207119923Sdes	/* /proc/net/... */
1208167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
120985129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1210167482Sdes	    NULL, NULL, NULL, PFS_RD);
121178025Sdes
1212119923Sdes	/* /proc/<pid>/... */
1213167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
121485129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1215167482Sdes	    NULL, NULL, NULL, PFS_RD);
1216119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1217167482Sdes	    NULL, NULL, NULL, 0);
1218116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1219167482Sdes	    NULL, NULL, NULL, PFS_RD);
122087543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1221167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1222116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1223167482Sdes	    NULL, NULL, NULL, PFS_RD);
122485129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1225167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1226119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1227167482Sdes	    NULL, NULL, NULL, 0);
122885129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1229167482Sdes	    NULL, NULL, NULL, PFS_RD);
1230119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1231167482Sdes	    NULL, NULL, NULL, PFS_RD);
123285129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1233167482Sdes	    NULL, NULL, NULL, PFS_RD);
123485129Sdes
1235158311Sambrisko	/* /proc/scsi/... */
1236167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1237158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1238167482Sdes	    NULL, NULL, NULL, PFS_RD);
1239158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1240167482Sdes	    NULL, NULL, NULL, PFS_RD);
1241163129Snetchild
1242163129Snetchild	/* /proc/sys/... */
1243167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1244163129Snetchild	/* /proc/sys/kernel/... */
1245167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1246167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1247167482Sdes	    NULL, NULL, NULL, PFS_RD);
1248167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1249167482Sdes	    NULL, NULL, NULL, PFS_RD);
1250167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1251167482Sdes	    NULL, NULL, NULL, PFS_RD);
1252164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1253167482Sdes	    NULL, NULL, NULL, PFS_RD);
1254163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1255167482Sdes	    NULL, NULL, NULL, PFS_RD);
1256164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1257167482Sdes	    NULL, NULL, NULL, PFS_RD);
1258163129Snetchild
125985129Sdes	return (0);
126085129Sdes}
126185129Sdes
126285129Sdes/*
126385129Sdes * Destructor
126485129Sdes */
126585129Sdesstatic int
126685129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
126785129Sdes{
126885129Sdes
126985129Sdes	/* nothing to do, pseudofs will GC */
127085129Sdes	return (0);
127185129Sdes}
127285129Sdes
127385129SdesPSEUDOFS(linprocfs, 1);
127478025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
127578025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1276168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1277168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1278