linprocfs.c revision 185765
1139743Simp/*-
2184691Sdes * 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 185765 2008-12-08 12:34:52Z kib $");
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>
79185571Sbz#include <net/vnet.h>
8083926Sdes
8159412Smsmith#include <vm/vm.h>
8259412Smsmith#include <vm/pmap.h>
8367588Sdes#include <vm/vm_map.h>
8459412Smsmith#include <vm/vm_param.h>
8560860Sdes#include <vm/vm_object.h>
8659412Smsmith#include <vm/swap_pager.h>
8769799Sdes
8867589Sdes#include <machine/clock.h>
8978113Sdes
90133822Stjr#if defined(__i386__) || defined(__amd64__)
9167589Sdes#include <machine/cputypes.h>
9259412Smsmith#include <machine/md_var.h>
93133822Stjr#endif /* __i386__ || __amd64__ */
9459412Smsmith
95140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
96140214Sobrien#include <machine/../linux32/linux.h>
97140214Sobrien#else
9887275Srwatson#include <machine/../linux/linux.h>
99133822Stjr#endif
10085129Sdes#include <compat/linux/linux_ioctl.h>
10169995Sdes#include <compat/linux/linux_mib.h>
10285289Sdes#include <compat/linux/linux_util.h>
10378025Sdes#include <fs/pseudofs/pseudofs.h>
10484248Sdes#include <fs/procfs/procfs.h>
10559412Smsmith
10667588Sdes/*
10767588Sdes * Various conversion macros
10867588Sdes */
10976405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
11067588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11167588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11269799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11367588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11467588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11574135Sjlemon
116159995Snetchild/**
117159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
118159995Snetchild *
119159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
120159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
121172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
122159995Snetchild * or stopped, or process is paging respectively.
123159995Snetchild *
124159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
125159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
126159995Snetchild *
127159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
128159995Snetchild * map our states to suitable linux states.
129159995Snetchild */
130166140Snetchildstatic char linux_state[] = "RRSTZDD";
131159995Snetchild
13278113Sdes/*
13378113Sdes * Filler function for proc/meminfo
13478113Sdes */
13578025Sdesstatic int
13678025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13759412Smsmith{
13859412Smsmith	unsigned long memtotal;		/* total memory in bytes */
13959412Smsmith	unsigned long memused;		/* used memory in bytes */
14059412Smsmith	unsigned long memfree;		/* free memory in bytes */
14159412Smsmith	unsigned long memshared;	/* shared memory ??? */
14259412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
143113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
144113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
145113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14660860Sdes	vm_object_t object;
147117723Sphk	int i, j;
14859412Smsmith
14959412Smsmith	memtotal = physmem * PAGE_SIZE;
15059412Smsmith	/*
15159412Smsmith	 * The correct thing here would be:
15259412Smsmith	 *
153170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
15459412Smsmith	memused = memtotal - memfree;
15559412Smsmith	 *
15659412Smsmith	 * but it might mislead linux binaries into thinking there
15759412Smsmith	 * is very little memory left, so we cheat and tell them that
15859412Smsmith	 * all memory that isn't wired down is free.
15959412Smsmith	 */
160170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
16159412Smsmith	memfree = memtotal - memused;
162117723Sphk	swap_pager_status(&i, &j);
163153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
164153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
165117723Sphk	swapfree = swaptotal - swapused;
16660860Sdes	memshared = 0;
167124082Salc	mtx_lock(&vm_object_list_mtx);
16871471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
16960860Sdes		if (object->shadow_count > 1)
17060860Sdes			memshared += object->resident_page_count;
171124082Salc	mtx_unlock(&vm_object_list_mtx);
17260860Sdes	memshared *= PAGE_SIZE;
17359412Smsmith	/*
17459412Smsmith	 * We'd love to be able to write:
17559412Smsmith	 *
17659412Smsmith	buffers = bufspace;
17759412Smsmith	 *
17859412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
17959412Smsmith	 * like unstaticizing it just for linprocfs's sake.
18059412Smsmith	 */
18159412Smsmith	buffers = 0;
182170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18359412Smsmith
18478025Sdes	sbuf_printf(sb,
18578031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18669799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18776839Sjlemon	    "Swap: %llu %llu %llu\n"
18869799Sdes	    "MemTotal: %9lu kB\n"
18969799Sdes	    "MemFree:  %9lu kB\n"
19069799Sdes	    "MemShared:%9lu kB\n"
19169799Sdes	    "Buffers:  %9lu kB\n"
19269799Sdes	    "Cached:   %9lu kB\n"
19376839Sjlemon	    "SwapTotal:%9llu kB\n"
19476839Sjlemon	    "SwapFree: %9llu kB\n",
19569799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19669799Sdes	    swaptotal, swapused, swapfree,
19769799Sdes	    B2K(memtotal), B2K(memfree),
19869799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
19969799Sdes	    B2K(swaptotal), B2K(swapfree));
20059412Smsmith
20178025Sdes	return (0);
20259412Smsmith}
20359412Smsmith
204133822Stjr#if defined(__i386__) || defined(__amd64__)
20578113Sdes/*
206133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20778113Sdes */
20878113Sdesstatic int
20978113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
21078113Sdes{
211159544Sdes	int hw_model[2];
212159544Sdes	char model[128];
213159544Sdes	size_t size;
214123246Sdes	int class, fqmhz, fqkhz;
215118421Sdes	int i;
21659412Smsmith
21769799Sdes	/*
21878031Sdes	 * We default the flags to include all non-conflicting flags,
21978031Sdes	 * and the Intel versions of conflicting flags.
22069799Sdes	 */
22178031Sdes	static char *flags[] = {
22278031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22378031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22478031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22578031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22678031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
227183385Scognet		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
22867589Sdes		"3dnowext", "3dnow"
22967589Sdes	};
23067589Sdes
23159412Smsmith	switch (cpu_class) {
232133822Stjr#ifdef __i386__
23359412Smsmith	case CPUCLASS_286:
23467589Sdes		class = 2;
23559412Smsmith		break;
23659412Smsmith	case CPUCLASS_386:
23767589Sdes		class = 3;
23859412Smsmith		break;
23959412Smsmith	case CPUCLASS_486:
24067589Sdes		class = 4;
24159412Smsmith		break;
24259412Smsmith	case CPUCLASS_586:
24367589Sdes		class = 5;
24459412Smsmith		break;
24559412Smsmith	case CPUCLASS_686:
24667589Sdes		class = 6;
24759412Smsmith		break;
24859412Smsmith	default:
24978031Sdes		class = 0;
25059412Smsmith		break;
251159170Sdes#else /* __amd64__ */
252133822Stjr	default:
253159170Sdes		class = 15;
254133822Stjr		break;
255133822Stjr#endif
25659412Smsmith	}
25759412Smsmith
258159544Sdes	hw_model[0] = CTL_HW;
259159544Sdes	hw_model[1] = HW_MODEL;
260159544Sdes	model[0] = '\0';
261159544Sdes	size = sizeof(model);
262159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
263159544Sdes		strcpy(model, "unknown");
264123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
265118421Sdes		sbuf_printf(sb,
266118421Sdes		    "processor\t: %d\n"
267118421Sdes		    "vendor_id\t: %.20s\n"
268118421Sdes		    "cpu family\t: %d\n"
269118421Sdes		    "model\t\t: %d\n"
270159544Sdes		    "model name\t: %s\n"
271118421Sdes		    "stepping\t: %d\n",
272159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
273159544Sdes		/* XXX per-cpu vendor / class / model / id? */
274118421Sdes	}
27559412Smsmith
27678031Sdes	sbuf_cat(sb,
27778031Sdes	    "flags\t\t:");
27867589Sdes
27978031Sdes	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
28067589Sdes		flags[16] = "fcmov";
28178031Sdes	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
28267589Sdes		flags[24] = "cxmmx";
28378031Sdes	}
284119068Sdes
28578031Sdes	for (i = 0; i < 32; i++)
28667589Sdes		if (cpu_feature & (1 << i))
28778025Sdes			sbuf_printf(sb, " %s", flags[i]);
28878025Sdes	sbuf_cat(sb, "\n");
28978031Sdes	if (class >= 5) {
29069799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
29169799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
29278025Sdes		sbuf_printf(sb,
29369799Sdes		    "cpu MHz\t\t: %d.%02d\n"
29469799Sdes		    "bogomips\t: %d.%02d\n",
29569799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
29678031Sdes	}
29769995Sdes
29878025Sdes	return (0);
29959412Smsmith}
300133822Stjr#endif /* __i386__ || __amd64__ */
30165633Sdes
30278113Sdes/*
30385289Sdes * Filler function for proc/mtab
30485289Sdes *
30585289Sdes * This file doesn't exist in Linux' procfs, but is included here so
30685289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
30785289Sdes */
30885289Sdesstatic int
30985289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
31085289Sdes{
31185289Sdes	struct nameidata nd;
31285289Sdes	struct mount *mp;
31391334Sjulian	const char *lep;
31491334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
31585289Sdes	size_t lep_len;
31685289Sdes	int error;
31785289Sdes
31885289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
319168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
32085289Sdes	flep = NULL;
321168942Sdes	error = namei(&nd);
322184649Sjhb	lep = linux_emul_path;
323184649Sjhb	if (error == 0) {
324184649Sjhb		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
325184649Sjhb			lep = dlep;
326184649Sjhb		vrele(nd.ni_vp);
327184649Sjhb		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
328184649Sjhb	}
32985289Sdes	lep_len = strlen(lep);
330119068Sdes
33185289Sdes	mtx_lock(&mountlist_mtx);
33285289Sdes	error = 0;
33385289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
33485289Sdes		/* determine device name */
33585289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
336119068Sdes
33785289Sdes		/* determine mount point */
33885289Sdes		mntto = mp->mnt_stat.f_mntonname;
33985289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
34085289Sdes		    mntto[lep_len] == '/')
34185289Sdes			mntto += lep_len;
34285289Sdes
34385289Sdes		/* determine fs type */
34485289Sdes		fstype = mp->mnt_stat.f_fstypename;
34585289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
34685289Sdes			mntfrom = fstype = "proc";
34785289Sdes		else if (strcmp(fstype, "procfs") == 0)
34885289Sdes			continue;
349119068Sdes
350158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
351158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
352158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
353158311Sambrisko		} else {
354158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
355158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
356158311Sambrisko		}
35785289Sdes#define ADD_OPTION(opt, name) \
35885289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
35985289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
36085289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
36185289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
36285289Sdes		ADD_OPTION(MNT_UNION,		"union");
36385289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
36485289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
36585289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
36685289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
36785289Sdes#undef ADD_OPTION
36885289Sdes		/* a real Linux mtab will also show NFS options */
36985289Sdes		sbuf_printf(sb, " 0 0\n");
37085289Sdes	}
37185289Sdes	mtx_unlock(&mountlist_mtx);
37285289Sdes	if (flep != NULL)
37385289Sdes		free(flep, M_TEMP);
37485289Sdes	return (error);
37585289Sdes}
37685289Sdes
37785289Sdes/*
37878113Sdes * Filler function for proc/stat
37978113Sdes */
38078025Sdesstatic int
38178025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
38265633Sdes{
383174070Speter	struct pcpu *pcpu;
384174070Speter	long cp_time[CPUSTATES];
385174070Speter	long *cp;
386123246Sdes	int i;
387120339Sdes
388174070Speter	read_cpu_time(cp_time);
389120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
390120339Sdes	    T2J(cp_time[CP_USER]),
391120339Sdes	    T2J(cp_time[CP_NICE]),
392120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
393120339Sdes	    T2J(cp_time[CP_IDLE]));
394174070Speter	for (i = 0; i <= mp_maxid; ++i) {
395174070Speter		if (CPU_ABSENT(i))
396174070Speter			continue;
397174070Speter		pcpu = pcpu_find(i);
398174070Speter		cp = pcpu->pc_cp_time;
399143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
400174070Speter		    T2J(cp[CP_USER]),
401174070Speter		    T2J(cp[CP_NICE]),
402174070Speter		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
403174070Speter		    T2J(cp[CP_IDLE]));
404174070Speter	}
40578025Sdes	sbuf_printf(sb,
40669799Sdes	    "disk 0 0 0 0\n"
40769799Sdes	    "page %u %u\n"
40869799Sdes	    "swap %u %u\n"
40969799Sdes	    "intr %u\n"
41069799Sdes	    "ctxt %u\n"
41185657Sdillon	    "btime %lld\n",
412170170Sattilio	    cnt.v_vnodepgsin,
413170170Sattilio	    cnt.v_vnodepgsout,
414170170Sattilio	    cnt.v_swappgsin,
415170170Sattilio	    cnt.v_swappgsout,
416170170Sattilio	    cnt.v_intr,
417170170Sattilio	    cnt.v_swtch,
418113574Sjhb	    (long long)boottime.tv_sec);
41978025Sdes	return (0);
42065633Sdes}
42165633Sdes
42278113Sdes/*
42378113Sdes * Filler function for proc/uptime
42478113Sdes */
42578025Sdesstatic int
42678025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
42765633Sdes{
428174070Speter	long cp_time[CPUSTATES];
42965633Sdes	struct timeval tv;
43065633Sdes
43165633Sdes	getmicrouptime(&tv);
432174070Speter	read_cpu_time(cp_time);
43385657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
434113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
43569799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
43678025Sdes	return (0);
43765633Sdes}
43865633Sdes
43978113Sdes/*
440167159Sjkim * Get OS build date
441167159Sjkim */
442167159Sjkimstatic void
443167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
444167159Sjkim{
445167159Sjkim#if 0
446167159Sjkim	char osbuild[256];
447167159Sjkim	char *cp1, *cp2;
448167159Sjkim
449167159Sjkim	strncpy(osbuild, version, 256);
450167159Sjkim	osbuild[255] = '\0';
451167159Sjkim	cp1 = strstr(osbuild, "\n");
452167159Sjkim	cp2 = strstr(osbuild, ":");
453167159Sjkim	if (cp1 && cp2) {
454167159Sjkim		*cp1 = *cp2 = '\0';
455167159Sjkim		cp1 = strstr(osbuild, "#");
456167159Sjkim	} else
457167159Sjkim		cp1 = NULL;
458167159Sjkim	if (cp1)
459167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
460167159Sjkim	else
461167159Sjkim#endif
462167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
463167159Sjkim}
464167159Sjkim
465167159Sjkim/*
466167159Sjkim * Get OS builder
467167159Sjkim */
468167159Sjkimstatic void
469167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
470167159Sjkim{
471168762Sdes#if 0
472167159Sjkim	char builder[256];
473167159Sjkim	char *cp;
474167159Sjkim
475167159Sjkim	cp = strstr(version, "\n    ");
476167159Sjkim	if (cp) {
477167159Sjkim		strncpy(builder, cp + 5, 256);
478167159Sjkim		builder[255] = '\0';
479167159Sjkim		cp = strstr(builder, ":");
480167159Sjkim		if (cp)
481167159Sjkim			*cp = '\0';
482167159Sjkim	}
483167159Sjkim	if (cp)
484167159Sjkim		sbuf_cat(sb, builder);
485167159Sjkim	else
486168762Sdes#endif
487167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
488167159Sjkim}
489167159Sjkim
490167159Sjkim/*
49178113Sdes * Filler function for proc/version
49278113Sdes */
49378025Sdesstatic int
49478025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
49565633Sdes{
49687275Srwatson	char osname[LINUX_MAX_UTSNAME];
49787275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
49887275Srwatson
499112206Sjhb	linux_get_osname(td, osname);
500112206Sjhb	linux_get_osrelease(td, osrelease);
501167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
502167159Sjkim	linprocfs_osbuilder(td, sb);
503167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
504167159Sjkim	linprocfs_osbuild(td, sb);
505167159Sjkim	sbuf_cat(sb, "\n");
50687275Srwatson
50778025Sdes	return (0);
50865633Sdes}
50965633Sdes
51078113Sdes/*
51178113Sdes * Filler function for proc/loadavg
51278113Sdes */
51378025Sdesstatic int
51478025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
51576839Sjlemon{
516168762Sdes
51778025Sdes	sbuf_printf(sb,
51876839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
51976839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
52076839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
52176839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
52276839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
52376839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
52476839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
52576839Sjlemon	    1,				/* number of running tasks */
52676839Sjlemon	    nprocs,			/* number of tasks */
52778116Sdes	    lastpid			/* the last pid */
52876839Sjlemon	);
52978025Sdes	return (0);
53076839Sjlemon}
53176839Sjlemon
53278113Sdes/*
53378113Sdes * Filler function for proc/pid/stat
53478113Sdes */
53578025Sdesstatic int
53678025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
53767588Sdes{
53869995Sdes	struct kinfo_proc kp;
539166140Snetchild	char state;
540166140Snetchild	static int ratelimit = 0;
54167588Sdes
54294307Sjhb	PROC_LOCK(p);
54369995Sdes	fill_kinfo_proc(p, &kp);
54478025Sdes	sbuf_printf(sb, "%d", p->p_pid);
54578025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
54667588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
547166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
548166140Snetchild		state = 'R';
549166140Snetchild
550166141Snetchild		if (ratelimit == 0) {
551166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
552166162Snetchild			    kp.ki_stat, sizeof(linux_state));
553166141Snetchild			++ratelimit;
554166141Snetchild		}
555166140Snetchild	} else
556166140Snetchild		state = linux_state[kp.ki_stat - 1];
557166140Snetchild	PS_ADD("state",		"%c",	state);
55873923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
55967588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
56067588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
56191140Stanimura	PROC_UNLOCK(p);
56267588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
563159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
56467588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
565159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
566159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
567159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
568159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
569159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
570159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
571159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
572159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
573159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
574159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
575159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
576159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
577159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
578159995Snetchild	   It should be the number of jiffies between system boot and process
579159995Snetchild	   start. */
580159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
581159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
582159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
583159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
58469995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
58567588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
58667588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
587159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
588159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
589159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
590159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
591159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
592159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
59367588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
594159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
595159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
59669799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
597159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
598159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
599159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
60067588Sdes#undef PS_ADD
60178025Sdes	sbuf_putc(sb, '\n');
602119068Sdes
60378025Sdes	return (0);
60467588Sdes}
60567588Sdes
60667588Sdes/*
607119911Sdes * Filler function for proc/pid/statm
608119911Sdes */
609119911Sdesstatic int
610119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
611119911Sdes{
612119911Sdes	struct kinfo_proc kp;
613119911Sdes	segsz_t lsize;
614120340Sdes
615119911Sdes	PROC_LOCK(p);
616119911Sdes	fill_kinfo_proc(p, &kp);
617119911Sdes	PROC_UNLOCK(p);
618119911Sdes
619119911Sdes	/*
620119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
621119911Sdes	 * computation of lsize.
622119911Sdes	 */
623119911Sdes	/* size resident share trs drs lrs dt */
624119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
625119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
626119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
627119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
628119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
629119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
630119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
631119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
632119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
633119911Sdes
634119911Sdes	return (0);
635119911Sdes}
636119911Sdes
637119911Sdes/*
63878113Sdes * Filler function for proc/pid/status
63978113Sdes */
64078025Sdesstatic int
64178025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
64267588Sdes{
64369995Sdes	struct kinfo_proc kp;
64467588Sdes	char *state;
64569799Sdes	segsz_t lsize;
64699072Sjulian	struct thread *td2;
647114983Sjhb	struct sigacts *ps;
64874135Sjlemon	int i;
64967588Sdes
650113611Sjhb	PROC_LOCK(p);
65199072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
65299072Sjulian
65399072Sjulian	if (P_SHOULDSTOP(p)) {
65499072Sjulian		state = "T (stopped)";
65599072Sjulian	} else {
656170307Sjeff		PROC_SLOCK(p);
65799072Sjulian		switch(p->p_state) {
65899072Sjulian		case PRS_NEW:
65999072Sjulian			state = "I (idle)";
66099072Sjulian			break;
66199072Sjulian		case PRS_NORMAL:
66299072Sjulian			if (p->p_flag & P_WEXIT) {
66399072Sjulian				state = "X (exiting)";
66499072Sjulian				break;
66599072Sjulian			}
66699072Sjulian			switch(td2->td_state) {
667103216Sjulian			case TDS_INHIBITED:
66899072Sjulian				state = "S (sleeping)";
66999072Sjulian				break;
67099072Sjulian			case TDS_RUNQ:
67199072Sjulian			case TDS_RUNNING:
67299072Sjulian				state = "R (running)";
67399072Sjulian				break;
67499072Sjulian			default:
67599072Sjulian				state = "? (unknown)";
67699072Sjulian				break;
67799072Sjulian			}
67899072Sjulian			break;
67999072Sjulian		case PRS_ZOMBIE:
68099072Sjulian			state = "Z (zombie)";
68199072Sjulian			break;
68299072Sjulian		default:
68399072Sjulian			state = "? (unknown)";
68499072Sjulian			break;
68599072Sjulian		}
686170307Sjeff		PROC_SUNLOCK(p);
68799072Sjulian	}
68867588Sdes
68969995Sdes	fill_kinfo_proc(p, &kp);
69078025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
69178031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
69267588Sdes
69367588Sdes	/*
69467588Sdes	 * Credentials
69567588Sdes	 */
69678025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
69778025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
69873923Sjhb						p->p_pptr->p_pid : 0);
69978031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
70078031Sdes						p->p_ucred->cr_uid,
70178031Sdes						p->p_ucred->cr_svuid,
70278031Sdes						/* FreeBSD doesn't have fsuid */
70378031Sdes						p->p_ucred->cr_uid);
70478031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
70578031Sdes						p->p_ucred->cr_gid,
70678031Sdes						p->p_ucred->cr_svgid,
70778031Sdes						/* FreeBSD doesn't have fsgid */
70878031Sdes						p->p_ucred->cr_gid);
70978025Sdes	sbuf_cat(sb, "Groups:\t");
71067588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
71178031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
71271471Sjhb	PROC_UNLOCK(p);
71378025Sdes	sbuf_putc(sb, '\n');
714119068Sdes
71567588Sdes	/*
71667588Sdes	 * Memory
71769799Sdes	 *
71869799Sdes	 * While our approximation of VmLib may not be accurate (I
71969799Sdes	 * don't know of a simple way to verify it, and I'm not sure
72069799Sdes	 * it has much meaning anyway), I believe it's good enough.
72169799Sdes	 *
72269799Sdes	 * The same code that could (I think) accurately compute VmLib
72369799Sdes	 * could also compute VmLck, but I don't really care enough to
72469799Sdes	 * implement it. Submissions are welcome.
72567588Sdes	 */
726113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
72778025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
728113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
729113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
730113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
731113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
73269995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
73369995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
734113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
73567588Sdes
73667588Sdes	/*
73767588Sdes	 * Signal masks
73867588Sdes	 *
73967588Sdes	 * We support up to 128 signals, while Linux supports 32,
74067588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
74167588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
74267588Sdes	 *
74367588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
74467588Sdes	 * supports 64 signals, but this code is a long way from
74567588Sdes	 * running on anything but i386, so ignore that for now.
74667588Sdes	 */
74771471Sjhb	PROC_LOCK(p);
748104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
74969799Sdes	/*
75069799Sdes	 * I can't seem to find out where the signal mask is in
75169799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
75269799Sdes	 */
75378025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
754114983Sjhb	ps = p->p_sigacts;
755114983Sjhb	mtx_lock(&ps->ps_mtx);
756114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
757114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
758114983Sjhb	mtx_unlock(&ps->ps_mtx);
75971471Sjhb	PROC_UNLOCK(p);
760119068Sdes
76167588Sdes	/*
76267588Sdes	 * Linux also prints the capability masks, but we don't have
76367588Sdes	 * capabilities yet, and when we do get them they're likely to
76467588Sdes	 * be meaningless to Linux programs, so we lie. XXX
76567588Sdes	 */
76678025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
76778025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
76878025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
769119068Sdes
77078025Sdes	return (0);
77167588Sdes}
77274135Sjlemon
773119911Sdes
77478113Sdes/*
775119911Sdes * Filler function for proc/pid/cwd
776119911Sdes */
777119911Sdesstatic int
778119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
779119911Sdes{
780119911Sdes	char *fullpath = "unknown";
781119911Sdes	char *freepath = NULL;
782119911Sdes
783119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
784119911Sdes	sbuf_printf(sb, "%s", fullpath);
785119911Sdes	if (freepath)
786119911Sdes		free(freepath, M_TEMP);
787119911Sdes	return (0);
788119911Sdes}
789119911Sdes
790119911Sdes/*
791119911Sdes * Filler function for proc/pid/root
792119911Sdes */
793119911Sdesstatic int
794119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
795119911Sdes{
796119911Sdes	struct vnode *rvp;
797119911Sdes	char *fullpath = "unknown";
798119911Sdes	char *freepath = NULL;
799119911Sdes
800119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
801119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
802119911Sdes	sbuf_printf(sb, "%s", fullpath);
803119911Sdes	if (freepath)
804119911Sdes		free(freepath, M_TEMP);
805119911Sdes	return (0);
806119911Sdes}
807119911Sdes
808119911Sdes/*
80978113Sdes * Filler function for proc/pid/cmdline
81078113Sdes */
81178025Sdesstatic int
81278113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
81378113Sdes{
81478113Sdes	struct ps_strings pstr;
815138281Scperciva	char **ps_argvstr;
81678113Sdes	int error, i;
81778113Sdes
81878113Sdes	/*
81978113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
82078113Sdes	 * revert back to the old way which only implements full cmdline
82178113Sdes	 * for the currept process and just p->p_comm for all other
82278113Sdes	 * processes.
82378113Sdes	 * Note that if the argv is no longer available, we deliberately
82478113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
82578113Sdes	 * Linux behaviour is to return zero-length in this case.
82678113Sdes	 */
82778113Sdes
82894620Sjhb	PROC_LOCK(p);
829127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
83094620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
83194620Sjhb		PROC_UNLOCK(p);
83294620Sjhb	} else if (p != td->td_proc) {
83394620Sjhb		PROC_UNLOCK(p);
83494620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
83594620Sjhb	} else {
83694620Sjhb		PROC_UNLOCK(p);
837103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
838103767Sjake		    sizeof(pstr));
83994620Sjhb		if (error)
84094620Sjhb			return (error);
841138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
842138281Scperciva			return (E2BIG);
843138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
844138281Scperciva		    M_TEMP, M_WAITOK);
845138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
846138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
847138281Scperciva		if (error) {
848138281Scperciva			free(ps_argvstr, M_TEMP);
849138281Scperciva			return (error);
850138281Scperciva		}
85194620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
852138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
85394620Sjhb			sbuf_printf(sb, "%c", '\0');
85478113Sdes		}
855138281Scperciva		free(ps_argvstr, M_TEMP);
85678113Sdes	}
85778113Sdes
85878113Sdes	return (0);
85978113Sdes}
86078113Sdes
86178113Sdes/*
862116173Sobrien * Filler function for proc/pid/environ
863116173Sobrien */
864116173Sobrienstatic int
865116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
866116173Sobrien{
867168762Sdes
868116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
869116173Sobrien	return (0);
870116173Sobrien}
871116173Sobrien
872116173Sobrien/*
873116173Sobrien * Filler function for proc/pid/maps
874116173Sobrien */
875116173Sobrienstatic int
876116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
877116173Sobrien{
878121246Scognet	vm_map_t map = &p->p_vmspace->vm_map;
879185765Skib	vm_map_entry_t entry, tmp_entry;
880121265Scognet	vm_object_t obj, tobj, lobj;
881185765Skib	vm_offset_t e_start, e_end;
882121265Scognet	vm_ooffset_t off = 0;
883185765Skib	vm_prot_t e_prot;
884185765Skib	unsigned int last_timestamp;
885121265Scognet	char *name = "", *freename = NULL;
886121265Scognet	ino_t ino;
887121265Scognet	int ref_count, shadow_count, flags;
888121265Scognet	int error;
889137507Sphk	struct vnode *vp;
890137507Sphk	struct vattr vat;
891161094Skib	int locked;
892168762Sdes
893121246Scognet	PROC_LOCK(p);
894121246Scognet	error = p_candebug(td, p);
895121246Scognet	PROC_UNLOCK(p);
896121246Scognet	if (error)
897121246Scognet		return (error);
898168762Sdes
899121246Scognet	if (uio->uio_rw != UIO_READ)
900121246Scognet		return (EOPNOTSUPP);
901168762Sdes
902121246Scognet	error = 0;
903169156Salc	vm_map_lock_read(map);
904183600Skib	for (entry = map->header.next; entry != &map->header;
905121246Scognet	    entry = entry->next) {
906121265Scognet		name = "";
907121265Scognet		freename = NULL;
908121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
909121246Scognet			continue;
910185765Skib		e_prot = entry->protection;
911185765Skib		e_start = entry->start;
912185765Skib		e_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		}
920185765Skib		last_timestamp = map->timestamp;
921185765Skib		vm_map_unlock_read(map);
922121246Scognet		ino = 0;
923121246Scognet		if (lobj) {
924121246Scognet			off = IDX_TO_OFF(lobj->size);
925161094Skib			if (lobj->type == OBJT_VNODE) {
926161094Skib				vp = lobj->handle;
927161094Skib				if (vp)
928161094Skib					vref(vp);
929121246Scognet			}
930161094Skib			else
931161094Skib				vp = NULL;
932169156Salc			if (lobj != obj)
933169156Salc				VM_OBJECT_UNLOCK(lobj);
934121246Scognet			flags = obj->flags;
935121246Scognet			ref_count = obj->ref_count;
936121246Scognet			shadow_count = obj->shadow_count;
937169156Salc			VM_OBJECT_UNLOCK(obj);
938161094Skib			if (vp) {
939161094Skib				vn_fullpath(td, vp, &name, &freename);
940161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
941175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
942182371Sattilio				VOP_GETATTR(vp, &vat, td->td_ucred);
943161094Skib				ino = vat.va_fileid;
944161094Skib				vput(vp);
945161094Skib				VFS_UNLOCK_GIANT(locked);
946161094Skib			}
947121246Scognet		} else {
948121246Scognet			flags = 0;
949121246Scognet			ref_count = 0;
950121246Scognet			shadow_count = 0;
951121246Scognet		}
952168762Sdes
953121246Scognet		/*
954168762Sdes		 * format:
955121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
956121246Scognet		 */
957183600Skib		error = sbuf_printf(sb,
958121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
959185765Skib		    (u_long)e_start, (u_long)e_end,
960185765Skib		    (e_prot & VM_PROT_READ)?"r":"-",
961185765Skib		    (e_prot & VM_PROT_WRITE)?"w":"-",
962185765Skib		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
963121246Scognet		    "p",
964121265Scognet		    (u_long)off,
965121246Scognet		    0,
966121246Scognet		    0,
967121265Scognet		    (u_long)ino,
968121246Scognet		    *name ? "     " : "",
969121246Scognet		    name
970121246Scognet		    );
971121246Scognet		if (freename)
972121246Scognet			free(freename, M_TEMP);
973183600Skib		if (error == -1) {
974183600Skib			error = 0;
975121246Scognet			break;
976169156Salc		}
977185765Skib		vm_map_lock_read(map);
978185765Skib		if (last_timestamp + 1 != map->timestamp) {
979185765Skib			/*
980185765Skib			 * Look again for the entry because the map was
981185765Skib			 * modified while it was unlocked.  Specifically,
982185765Skib			 * the entry may have been clipped, merged, or deleted.
983185765Skib			 */
984185765Skib			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
985185765Skib			entry = tmp_entry;
986185765Skib		}
987121246Scognet	}
988169156Salc	vm_map_unlock_read(map);
989168762Sdes
990121246Scognet	return (error);
991168762Sdes}
992168762Sdes
993116173Sobrien/*
99478113Sdes * Filler function for proc/net/dev
99578113Sdes */
99678025Sdesstatic int
99778025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
99874135Sjlemon{
999183550Szec	INIT_VNET_NET(TD_TO_VNET(curthread));
100085129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
100174135Sjlemon	struct ifnet *ifp;
100274135Sjlemon
100385129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
100483926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
100585129Sdes	    "bytes    packets errs drop fifo frame compressed",
100683926Sdes	    "bytes    packets errs drop fifo frame compressed");
100774135Sjlemon
1008108172Shsu	IFNET_RLOCK();
1009181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
101085129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
101185129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
101283926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
101383926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
101483926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
101583926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
101674135Sjlemon	}
1017108172Shsu	IFNET_RUNLOCK();
1018119068Sdes
101978025Sdes	return (0);
102074135Sjlemon}
102174135Sjlemon
1022158311Sambrisko/*
1023167159Sjkim * Filler function for proc/sys/kernel/osrelease
1024167159Sjkim */
1025167159Sjkimstatic int
1026167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1027167159Sjkim{
1028167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1029167159Sjkim
1030167159Sjkim	linux_get_osrelease(td, osrelease);
1031167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1032167159Sjkim
1033167159Sjkim	return (0);
1034167159Sjkim}
1035167159Sjkim
1036167159Sjkim/*
1037167159Sjkim * Filler function for proc/sys/kernel/ostype
1038167159Sjkim */
1039167159Sjkimstatic int
1040167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1041167159Sjkim{
1042167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1043167159Sjkim
1044167159Sjkim	linux_get_osname(td, osname);
1045167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1046167159Sjkim
1047167159Sjkim	return (0);
1048167159Sjkim}
1049167159Sjkim
1050167159Sjkim/*
1051167159Sjkim * Filler function for proc/sys/kernel/version
1052167159Sjkim */
1053167159Sjkimstatic int
1054167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1055167159Sjkim{
1056168762Sdes
1057167159Sjkim	linprocfs_osbuild(td, sb);
1058167159Sjkim	sbuf_cat(sb, "\n");
1059167159Sjkim	return (0);
1060167159Sjkim}
1061167159Sjkim
1062167159Sjkim/*
1063164692Sjkim * Filler function for proc/sys/kernel/msgmni
1064164692Sjkim */
1065164692Sjkimstatic int
1066164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1067164692Sjkim{
1068164692Sjkim
1069168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1070164692Sjkim	return (0);
1071164692Sjkim}
1072164692Sjkim
1073164692Sjkim/*
1074163251Skeramida * Filler function for proc/sys/kernel/pid_max
1075163129Snetchild */
1076163129Snetchildstatic int
1077163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1078163129Snetchild{
1079163757Snetchild
1080163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1081163129Snetchild	return (0);
1082163129Snetchild}
1083163129Snetchild
1084163129Snetchild/*
1085164692Sjkim * Filler function for proc/sys/kernel/sem
1086164692Sjkim */
1087164692Sjkimstatic int
1088164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1089164692Sjkim{
1090164692Sjkim
1091168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1092168067Sjkim	    seminfo.semopm, seminfo.semmni);
1093164692Sjkim	return (0);
1094164692Sjkim}
1095164692Sjkim
1096164692Sjkim/*
1097158311Sambrisko * Filler function for proc/scsi/device_info
1098158311Sambrisko */
1099158311Sambriskostatic int
1100158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1101158311Sambrisko{
1102168762Sdes
1103158311Sambrisko	return (0);
1104158311Sambrisko}
1105158311Sambrisko
1106158311Sambrisko/*
1107158311Sambrisko * Filler function for proc/scsi/scsi
1108158311Sambrisko */
1109158311Sambriskostatic int
1110158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1111158311Sambrisko{
1112168762Sdes
1113158311Sambrisko	return (0);
1114158311Sambrisko}
1115158311Sambrisko
111685538Sphkextern struct cdevsw *cdevsw[];
111785538Sphk
111878113Sdes/*
111978113Sdes * Filler function for proc/devices
112078113Sdes */
112178025Sdesstatic int
112278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
112374135Sjlemon{
1124158311Sambrisko	char *char_devices;
112578025Sdes	sbuf_printf(sb, "Character devices:\n");
112674135Sjlemon
1127158311Sambrisko	char_devices = linux_get_char_devices();
1128158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1129158311Sambrisko	linux_free_get_char_devices(char_devices);
113074135Sjlemon
113178025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1132119068Sdes
113378025Sdes	return (0);
113474135Sjlemon}
113574135Sjlemon
113678113Sdes/*
113778113Sdes * Filler function for proc/cmdline
113878113Sdes */
113978025Sdesstatic int
114078025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
114174135Sjlemon{
1142168762Sdes
114378025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
114478025Sdes	sbuf_printf(sb, " ro root=302\n");
114578025Sdes	return (0);
114678025Sdes}
114774135Sjlemon
114883926Sdes#if 0
114978025Sdes/*
115083926Sdes * Filler function for proc/modules
115183926Sdes */
115283926Sdesstatic int
115383926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
115483926Sdes{
115583926Sdes	struct linker_file *lf;
1156119068Sdes
115783926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
115883926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
115983926Sdes		    (unsigned long)lf->size, lf->refs);
116083926Sdes	}
116183926Sdes	return (0);
116283926Sdes}
116383926Sdes#endif
116483926Sdes
116583926Sdes/*
116685129Sdes * Constructor
116778025Sdes */
116885129Sdesstatic int
116985129Sdeslinprocfs_init(PFS_INIT_ARGS)
117085129Sdes{
117185129Sdes	struct pfs_node *root;
117285129Sdes	struct pfs_node *dir;
117374135Sjlemon
117485129Sdes	root = pi->pi_root;
117578025Sdes
1176119923Sdes	/* /proc/... */
1177119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1178167482Sdes	    NULL, NULL, NULL, PFS_RD);
1179119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1180167482Sdes	    NULL, NULL, NULL, PFS_RD);
1181119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1182167482Sdes	    NULL, NULL, NULL, PFS_RD);
1183119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1184167482Sdes	    NULL, NULL, NULL, PFS_RD);
1185119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1186167482Sdes	    NULL, NULL, NULL, PFS_RD);
118783926Sdes#if 0
1188119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1189167482Sdes	    NULL, NULL, NULL, PFS_RD);
119083926Sdes#endif
1191158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1192167482Sdes	    NULL, NULL, NULL, PFS_RD);
1193119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1194167482Sdes	    NULL, NULL, NULL, PFS_RD);
119587543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1196167482Sdes	    NULL, NULL, NULL, 0);
1197119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1198167482Sdes	    NULL, NULL, NULL, PFS_RD);
1199119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1200167482Sdes	    NULL, NULL, NULL, PFS_RD);
1201119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1202167482Sdes	    NULL, NULL, NULL, PFS_RD);
120378025Sdes
1204119923Sdes	/* /proc/net/... */
1205167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
120685129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1207167482Sdes	    NULL, NULL, NULL, PFS_RD);
120878025Sdes
1209119923Sdes	/* /proc/<pid>/... */
1210167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
121185129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1212167482Sdes	    NULL, NULL, NULL, PFS_RD);
1213119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1214167482Sdes	    NULL, NULL, NULL, 0);
1215116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1216167482Sdes	    NULL, NULL, NULL, PFS_RD);
121787543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1218167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1219116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1220167482Sdes	    NULL, NULL, NULL, PFS_RD);
122185129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1222167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1223119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1224167482Sdes	    NULL, NULL, NULL, 0);
122585129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1226167482Sdes	    NULL, NULL, NULL, PFS_RD);
1227119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1228167482Sdes	    NULL, NULL, NULL, PFS_RD);
122985129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1230167482Sdes	    NULL, NULL, NULL, PFS_RD);
123185129Sdes
1232158311Sambrisko	/* /proc/scsi/... */
1233167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1234158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1235167482Sdes	    NULL, NULL, NULL, PFS_RD);
1236158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1237167482Sdes	    NULL, NULL, NULL, PFS_RD);
1238163129Snetchild
1239163129Snetchild	/* /proc/sys/... */
1240167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1241163129Snetchild	/* /proc/sys/kernel/... */
1242167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1243167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1244167482Sdes	    NULL, NULL, NULL, PFS_RD);
1245167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1246167482Sdes	    NULL, NULL, NULL, PFS_RD);
1247167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1248167482Sdes	    NULL, NULL, NULL, PFS_RD);
1249164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1250167482Sdes	    NULL, NULL, NULL, PFS_RD);
1251163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1252167482Sdes	    NULL, NULL, NULL, PFS_RD);
1253164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1254167482Sdes	    NULL, NULL, NULL, PFS_RD);
1255163129Snetchild
125685129Sdes	return (0);
125785129Sdes}
125885129Sdes
125985129Sdes/*
126085129Sdes * Destructor
126185129Sdes */
126285129Sdesstatic int
126385129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
126485129Sdes{
126585129Sdes
126685129Sdes	/* nothing to do, pseudofs will GC */
126785129Sdes	return (0);
126885129Sdes}
126985129Sdes
127085129SdesPSEUDOFS(linprocfs, 1);
127178025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
127278025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1273168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1274168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1275