linprocfs.c revision 188579
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 188579 2009-02-13 15:32:03Z jhb $");
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>
82185984Skib#include <vm/vm_extern.h>
8359412Smsmith#include <vm/pmap.h>
8467588Sdes#include <vm/vm_map.h>
8559412Smsmith#include <vm/vm_param.h>
8660860Sdes#include <vm/vm_object.h>
8759412Smsmith#include <vm/swap_pager.h>
8869799Sdes
8967589Sdes#include <machine/clock.h>
9078113Sdes
91133822Stjr#if defined(__i386__) || defined(__amd64__)
9267589Sdes#include <machine/cputypes.h>
9359412Smsmith#include <machine/md_var.h>
94133822Stjr#endif /* __i386__ || __amd64__ */
9559412Smsmith
96140214Sobrien#ifdef COMPAT_LINUX32				/* XXX */
97140214Sobrien#include <machine/../linux32/linux.h>
98140214Sobrien#else
9987275Srwatson#include <machine/../linux/linux.h>
100133822Stjr#endif
10185129Sdes#include <compat/linux/linux_ioctl.h>
10269995Sdes#include <compat/linux/linux_mib.h>
10385289Sdes#include <compat/linux/linux_util.h>
10478025Sdes#include <fs/pseudofs/pseudofs.h>
10584248Sdes#include <fs/procfs/procfs.h>
10659412Smsmith
10767588Sdes/*
10867588Sdes * Various conversion macros
10967588Sdes */
11076405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
11167588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
11267588Sdes#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
11369799Sdes#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
11467588Sdes#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
11567588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
11674135Sjlemon
117159995Snetchild/**
118159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
119159995Snetchild *
120159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to
121159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an
122172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced
123159995Snetchild * or stopped, or process is paging respectively.
124159995Snetchild *
125159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a
126159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
127159995Snetchild *
128159995Snetchild * This character array is used with ki_stati-1 as an index and tries to
129159995Snetchild * map our states to suitable linux states.
130159995Snetchild */
131166140Snetchildstatic char linux_state[] = "RRSTZDD";
132159995Snetchild
13378113Sdes/*
13478113Sdes * Filler function for proc/meminfo
13578113Sdes */
13678025Sdesstatic int
13778025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS)
13859412Smsmith{
13959412Smsmith	unsigned long memtotal;		/* total memory in bytes */
14059412Smsmith	unsigned long memused;		/* used memory in bytes */
14159412Smsmith	unsigned long memfree;		/* free memory in bytes */
14259412Smsmith	unsigned long memshared;	/* shared memory ??? */
14359412Smsmith	unsigned long buffers, cached;	/* buffer / cache memory ??? */
144113574Sjhb	unsigned long long swaptotal;	/* total swap space in bytes */
145113574Sjhb	unsigned long long swapused;	/* used swap space in bytes */
146113574Sjhb	unsigned long long swapfree;	/* free swap space in bytes */
14760860Sdes	vm_object_t object;
148117723Sphk	int i, j;
14959412Smsmith
15059412Smsmith	memtotal = physmem * PAGE_SIZE;
15159412Smsmith	/*
15259412Smsmith	 * The correct thing here would be:
15359412Smsmith	 *
154170170Sattilio	memfree = cnt.v_free_count * PAGE_SIZE;
15559412Smsmith	memused = memtotal - memfree;
15659412Smsmith	 *
15759412Smsmith	 * but it might mislead linux binaries into thinking there
15859412Smsmith	 * is very little memory left, so we cheat and tell them that
15959412Smsmith	 * all memory that isn't wired down is free.
16059412Smsmith	 */
161170170Sattilio	memused = cnt.v_wire_count * PAGE_SIZE;
16259412Smsmith	memfree = memtotal - memused;
163117723Sphk	swap_pager_status(&i, &j);
164153310Smlaier	swaptotal = (unsigned long long)i * PAGE_SIZE;
165153310Smlaier	swapused = (unsigned long long)j * PAGE_SIZE;
166117723Sphk	swapfree = swaptotal - swapused;
16760860Sdes	memshared = 0;
168124082Salc	mtx_lock(&vm_object_list_mtx);
16971471Sjhb	TAILQ_FOREACH(object, &vm_object_list, object_list)
17060860Sdes		if (object->shadow_count > 1)
17160860Sdes			memshared += object->resident_page_count;
172124082Salc	mtx_unlock(&vm_object_list_mtx);
17360860Sdes	memshared *= PAGE_SIZE;
17459412Smsmith	/*
17559412Smsmith	 * We'd love to be able to write:
17659412Smsmith	 *
17759412Smsmith	buffers = bufspace;
17859412Smsmith	 *
17959412Smsmith	 * but bufspace is internal to vfs_bio.c and we don't feel
18059412Smsmith	 * like unstaticizing it just for linprocfs's sake.
18159412Smsmith	 */
18259412Smsmith	buffers = 0;
183170170Sattilio	cached = cnt.v_cache_count * PAGE_SIZE;
18459412Smsmith
18578025Sdes	sbuf_printf(sb,
18678031Sdes	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18769799Sdes	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18876839Sjlemon	    "Swap: %llu %llu %llu\n"
18969799Sdes	    "MemTotal: %9lu kB\n"
19069799Sdes	    "MemFree:  %9lu kB\n"
19169799Sdes	    "MemShared:%9lu kB\n"
19269799Sdes	    "Buffers:  %9lu kB\n"
19369799Sdes	    "Cached:   %9lu kB\n"
19476839Sjlemon	    "SwapTotal:%9llu kB\n"
19576839Sjlemon	    "SwapFree: %9llu kB\n",
19669799Sdes	    memtotal, memused, memfree, memshared, buffers, cached,
19769799Sdes	    swaptotal, swapused, swapfree,
19869799Sdes	    B2K(memtotal), B2K(memfree),
19969799Sdes	    B2K(memshared), B2K(buffers), B2K(cached),
20069799Sdes	    B2K(swaptotal), B2K(swapfree));
20159412Smsmith
20278025Sdes	return (0);
20359412Smsmith}
20459412Smsmith
205133822Stjr#if defined(__i386__) || defined(__amd64__)
20678113Sdes/*
207133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version)
20878113Sdes */
20978113Sdesstatic int
21078113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS)
21178113Sdes{
212159544Sdes	int hw_model[2];
213159544Sdes	char model[128];
214159544Sdes	size_t size;
215123246Sdes	int class, fqmhz, fqkhz;
216118421Sdes	int i;
21759412Smsmith
21869799Sdes	/*
21978031Sdes	 * We default the flags to include all non-conflicting flags,
22078031Sdes	 * and the Intel versions of conflicting flags.
22169799Sdes	 */
22278031Sdes	static char *flags[] = {
22378031Sdes		"fpu",	    "vme",     "de",	   "pse",      "tsc",
22478031Sdes		"msr",	    "pae",     "mce",	   "cx8",      "apic",
22578031Sdes		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
22678031Sdes		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22778031Sdes		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
228183385Scognet		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
22967589Sdes		"3dnowext", "3dnow"
23067589Sdes	};
23167589Sdes
23259412Smsmith	switch (cpu_class) {
233133822Stjr#ifdef __i386__
23459412Smsmith	case CPUCLASS_286:
23567589Sdes		class = 2;
23659412Smsmith		break;
23759412Smsmith	case CPUCLASS_386:
23867589Sdes		class = 3;
23959412Smsmith		break;
24059412Smsmith	case CPUCLASS_486:
24167589Sdes		class = 4;
24259412Smsmith		break;
24359412Smsmith	case CPUCLASS_586:
24467589Sdes		class = 5;
24559412Smsmith		break;
24659412Smsmith	case CPUCLASS_686:
24767589Sdes		class = 6;
24859412Smsmith		break;
24959412Smsmith	default:
25078031Sdes		class = 0;
25159412Smsmith		break;
252159170Sdes#else /* __amd64__ */
253133822Stjr	default:
254159170Sdes		class = 15;
255133822Stjr		break;
256133822Stjr#endif
25759412Smsmith	}
25859412Smsmith
259159544Sdes	hw_model[0] = CTL_HW;
260159544Sdes	hw_model[1] = HW_MODEL;
261159544Sdes	model[0] = '\0';
262159544Sdes	size = sizeof(model);
263159544Sdes	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
264159544Sdes		strcpy(model, "unknown");
265123246Sdes	for (i = 0; i < mp_ncpus; ++i) {
266118421Sdes		sbuf_printf(sb,
267118421Sdes		    "processor\t: %d\n"
268118421Sdes		    "vendor_id\t: %.20s\n"
269118421Sdes		    "cpu family\t: %d\n"
270118421Sdes		    "model\t\t: %d\n"
271159544Sdes		    "model name\t: %s\n"
272118421Sdes		    "stepping\t: %d\n",
273159544Sdes		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
274159544Sdes		/* XXX per-cpu vendor / class / model / id? */
275118421Sdes	}
27659412Smsmith
277185766Skib	sbuf_cat(sb, "flags\t\t:");
27867589Sdes
279187594Sjkim#ifdef __i386__
280187594Sjkim	switch (cpu_vendor_id) {
281187594Sjkim	case CPU_VENDOR_AMD:
282187594Sjkim		if (class < 6)
283187594Sjkim			flags[16] = "fcmov";
284187594Sjkim		break;
285187594Sjkim	case CPU_VENDOR_CYRIX:
28667589Sdes		flags[24] = "cxmmx";
287187594Sjkim		break;
28878031Sdes	}
289187594Sjkim#endif
290119068Sdes
29178031Sdes	for (i = 0; i < 32; i++)
29267589Sdes		if (cpu_feature & (1 << i))
29378025Sdes			sbuf_printf(sb, " %s", flags[i]);
29478025Sdes	sbuf_cat(sb, "\n");
29578031Sdes	if (class >= 5) {
29669799Sdes		fqmhz = (tsc_freq + 4999) / 1000000;
29769799Sdes		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
29878025Sdes		sbuf_printf(sb,
29969799Sdes		    "cpu MHz\t\t: %d.%02d\n"
30069799Sdes		    "bogomips\t: %d.%02d\n",
30169799Sdes		    fqmhz, fqkhz, fqmhz, fqkhz);
30278031Sdes	}
30369995Sdes
30478025Sdes	return (0);
30559412Smsmith}
306133822Stjr#endif /* __i386__ || __amd64__ */
30765633Sdes
30878113Sdes/*
30985289Sdes * Filler function for proc/mtab
31085289Sdes *
31185289Sdes * This file doesn't exist in Linux' procfs, but is included here so
31285289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab
31385289Sdes */
31485289Sdesstatic int
31585289Sdeslinprocfs_domtab(PFS_FILL_ARGS)
31685289Sdes{
31785289Sdes	struct nameidata nd;
31885289Sdes	struct mount *mp;
31991334Sjulian	const char *lep;
32091334Sjulian	char *dlep, *flep, *mntto, *mntfrom, *fstype;
32185289Sdes	size_t lep_len;
32285289Sdes	int error;
32385289Sdes
32485289Sdes	/* resolve symlinks etc. in the emulation tree prefix */
325168942Sdes	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
32685289Sdes	flep = NULL;
327168942Sdes	error = namei(&nd);
328184649Sjhb	lep = linux_emul_path;
329184649Sjhb	if (error == 0) {
330188579Sjhb		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
331184649Sjhb			lep = dlep;
332184649Sjhb		vrele(nd.ni_vp);
333184649Sjhb		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
334184649Sjhb	}
33585289Sdes	lep_len = strlen(lep);
336119068Sdes
33785289Sdes	mtx_lock(&mountlist_mtx);
33885289Sdes	error = 0;
33985289Sdes	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
34085289Sdes		/* determine device name */
34185289Sdes		mntfrom = mp->mnt_stat.f_mntfromname;
342119068Sdes
34385289Sdes		/* determine mount point */
34485289Sdes		mntto = mp->mnt_stat.f_mntonname;
34585289Sdes		if (strncmp(mntto, lep, lep_len) == 0 &&
34685289Sdes		    mntto[lep_len] == '/')
34785289Sdes			mntto += lep_len;
34885289Sdes
34985289Sdes		/* determine fs type */
35085289Sdes		fstype = mp->mnt_stat.f_fstypename;
35185289Sdes		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
35285289Sdes			mntfrom = fstype = "proc";
35385289Sdes		else if (strcmp(fstype, "procfs") == 0)
35485289Sdes			continue;
355119068Sdes
356158311Sambrisko		if (strcmp(fstype, "linsysfs") == 0) {
357158311Sambrisko			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
358158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
359158311Sambrisko		} else {
360158311Sambrisko			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
361158311Sambrisko			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
362158311Sambrisko		}
36385289Sdes#define ADD_OPTION(opt, name) \
36485289Sdes	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
36585289Sdes		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
36685289Sdes		ADD_OPTION(MNT_NOEXEC,		"noexec");
36785289Sdes		ADD_OPTION(MNT_NOSUID,		"nosuid");
36885289Sdes		ADD_OPTION(MNT_UNION,		"union");
36985289Sdes		ADD_OPTION(MNT_ASYNC,		"async");
37085289Sdes		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
37185289Sdes		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
37285289Sdes		ADD_OPTION(MNT_NOATIME,		"noatime");
37385289Sdes#undef ADD_OPTION
37485289Sdes		/* a real Linux mtab will also show NFS options */
37585289Sdes		sbuf_printf(sb, " 0 0\n");
37685289Sdes	}
37785289Sdes	mtx_unlock(&mountlist_mtx);
37885289Sdes	if (flep != NULL)
37985289Sdes		free(flep, M_TEMP);
38085289Sdes	return (error);
38185289Sdes}
38285289Sdes
38385289Sdes/*
38478113Sdes * Filler function for proc/stat
38578113Sdes */
38678025Sdesstatic int
38778025Sdeslinprocfs_dostat(PFS_FILL_ARGS)
38865633Sdes{
389174070Speter	struct pcpu *pcpu;
390174070Speter	long cp_time[CPUSTATES];
391174070Speter	long *cp;
392123246Sdes	int i;
393120339Sdes
394174070Speter	read_cpu_time(cp_time);
395120339Sdes	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
396120339Sdes	    T2J(cp_time[CP_USER]),
397120339Sdes	    T2J(cp_time[CP_NICE]),
398120339Sdes	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
399120339Sdes	    T2J(cp_time[CP_IDLE]));
400174070Speter	for (i = 0; i <= mp_maxid; ++i) {
401174070Speter		if (CPU_ABSENT(i))
402174070Speter			continue;
403174070Speter		pcpu = pcpu_find(i);
404174070Speter		cp = pcpu->pc_cp_time;
405143194Ssobomax		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
406174070Speter		    T2J(cp[CP_USER]),
407174070Speter		    T2J(cp[CP_NICE]),
408174070Speter		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
409174070Speter		    T2J(cp[CP_IDLE]));
410174070Speter	}
41178025Sdes	sbuf_printf(sb,
41269799Sdes	    "disk 0 0 0 0\n"
41369799Sdes	    "page %u %u\n"
41469799Sdes	    "swap %u %u\n"
41569799Sdes	    "intr %u\n"
41669799Sdes	    "ctxt %u\n"
41785657Sdillon	    "btime %lld\n",
418170170Sattilio	    cnt.v_vnodepgsin,
419170170Sattilio	    cnt.v_vnodepgsout,
420170170Sattilio	    cnt.v_swappgsin,
421170170Sattilio	    cnt.v_swappgsout,
422170170Sattilio	    cnt.v_intr,
423170170Sattilio	    cnt.v_swtch,
424113574Sjhb	    (long long)boottime.tv_sec);
42578025Sdes	return (0);
42665633Sdes}
42765633Sdes
42878113Sdes/*
42978113Sdes * Filler function for proc/uptime
43078113Sdes */
43178025Sdesstatic int
43278025Sdeslinprocfs_douptime(PFS_FILL_ARGS)
43365633Sdes{
434174070Speter	long cp_time[CPUSTATES];
43565633Sdes	struct timeval tv;
43665633Sdes
43765633Sdes	getmicrouptime(&tv);
438174070Speter	read_cpu_time(cp_time);
43985657Sdillon	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
440113574Sjhb	    (long long)tv.tv_sec, tv.tv_usec / 10000,
44169799Sdes	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
44278025Sdes	return (0);
44365633Sdes}
44465633Sdes
44578113Sdes/*
446167159Sjkim * Get OS build date
447167159Sjkim */
448167159Sjkimstatic void
449167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb)
450167159Sjkim{
451167159Sjkim#if 0
452167159Sjkim	char osbuild[256];
453167159Sjkim	char *cp1, *cp2;
454167159Sjkim
455167159Sjkim	strncpy(osbuild, version, 256);
456167159Sjkim	osbuild[255] = '\0';
457167159Sjkim	cp1 = strstr(osbuild, "\n");
458167159Sjkim	cp2 = strstr(osbuild, ":");
459167159Sjkim	if (cp1 && cp2) {
460167159Sjkim		*cp1 = *cp2 = '\0';
461167159Sjkim		cp1 = strstr(osbuild, "#");
462167159Sjkim	} else
463167159Sjkim		cp1 = NULL;
464167159Sjkim	if (cp1)
465167159Sjkim		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
466167159Sjkim	else
467167159Sjkim#endif
468167159Sjkim		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
469167159Sjkim}
470167159Sjkim
471167159Sjkim/*
472167159Sjkim * Get OS builder
473167159Sjkim */
474167159Sjkimstatic void
475167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb)
476167159Sjkim{
477168762Sdes#if 0
478167159Sjkim	char builder[256];
479167159Sjkim	char *cp;
480167159Sjkim
481167159Sjkim	cp = strstr(version, "\n    ");
482167159Sjkim	if (cp) {
483167159Sjkim		strncpy(builder, cp + 5, 256);
484167159Sjkim		builder[255] = '\0';
485167159Sjkim		cp = strstr(builder, ":");
486167159Sjkim		if (cp)
487167159Sjkim			*cp = '\0';
488167159Sjkim	}
489167159Sjkim	if (cp)
490167159Sjkim		sbuf_cat(sb, builder);
491167159Sjkim	else
492168762Sdes#endif
493167159Sjkim		sbuf_cat(sb, "des@freebsd.org");
494167159Sjkim}
495167159Sjkim
496167159Sjkim/*
49778113Sdes * Filler function for proc/version
49878113Sdes */
49978025Sdesstatic int
50078025Sdeslinprocfs_doversion(PFS_FILL_ARGS)
50165633Sdes{
50287275Srwatson	char osname[LINUX_MAX_UTSNAME];
50387275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
50487275Srwatson
505112206Sjhb	linux_get_osname(td, osname);
506112206Sjhb	linux_get_osrelease(td, osrelease);
507167159Sjkim	sbuf_printf(sb, "%s version %s (", osname, osrelease);
508167159Sjkim	linprocfs_osbuilder(td, sb);
509167159Sjkim	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
510167159Sjkim	linprocfs_osbuild(td, sb);
511167159Sjkim	sbuf_cat(sb, "\n");
51287275Srwatson
51378025Sdes	return (0);
51465633Sdes}
51565633Sdes
51678113Sdes/*
51778113Sdes * Filler function for proc/loadavg
51878113Sdes */
51978025Sdesstatic int
52078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS)
52176839Sjlemon{
522168762Sdes
52378025Sdes	sbuf_printf(sb,
52476839Sjlemon	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
52576839Sjlemon	    (int)(averunnable.ldavg[0] / averunnable.fscale),
52676839Sjlemon	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
52776839Sjlemon	    (int)(averunnable.ldavg[1] / averunnable.fscale),
52876839Sjlemon	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
52976839Sjlemon	    (int)(averunnable.ldavg[2] / averunnable.fscale),
53076839Sjlemon	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
53176839Sjlemon	    1,				/* number of running tasks */
53276839Sjlemon	    nprocs,			/* number of tasks */
53378116Sdes	    lastpid			/* the last pid */
53476839Sjlemon	);
53578025Sdes	return (0);
53676839Sjlemon}
53776839Sjlemon
53878113Sdes/*
53978113Sdes * Filler function for proc/pid/stat
54078113Sdes */
54178025Sdesstatic int
54278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS)
54367588Sdes{
54469995Sdes	struct kinfo_proc kp;
545166140Snetchild	char state;
546166140Snetchild	static int ratelimit = 0;
54767588Sdes
54894307Sjhb	PROC_LOCK(p);
54969995Sdes	fill_kinfo_proc(p, &kp);
55078025Sdes	sbuf_printf(sb, "%d", p->p_pid);
55178025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
55267588Sdes	PS_ADD("comm",		"(%s)",	p->p_comm);
553166140Snetchild	if (kp.ki_stat > sizeof(linux_state)) {
554166140Snetchild		state = 'R';
555166140Snetchild
556166141Snetchild		if (ratelimit == 0) {
557166162Snetchild			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
558166162Snetchild			    kp.ki_stat, sizeof(linux_state));
559166141Snetchild			++ratelimit;
560166141Snetchild		}
561166140Snetchild	} else
562166140Snetchild		state = linux_state[kp.ki_stat - 1];
563166140Snetchild	PS_ADD("state",		"%c",	state);
56473923Sjhb	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
56567588Sdes	PS_ADD("pgrp",		"%d",	p->p_pgid);
56667588Sdes	PS_ADD("session",	"%d",	p->p_session->s_sid);
56791140Stanimura	PROC_UNLOCK(p);
56867588Sdes	PS_ADD("tty",		"%d",	0); /* XXX */
569159995Snetchild	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
57067588Sdes	PS_ADD("flags",		"%u",	0); /* XXX */
571159995Snetchild	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
572159995Snetchild	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
573159995Snetchild	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
574159995Snetchild	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
575159995Snetchild	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
576159995Snetchild	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
577159995Snetchild	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
578159995Snetchild	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
579159995Snetchild	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
580159995Snetchild	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
581159995Snetchild	PS_ADD("0",		"%d",	0); /* removed field */
582159995Snetchild	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
583159995Snetchild	/* XXX: starttime is not right, it is the _same_ for _every_ process.
584159995Snetchild	   It should be the number of jiffies between system boot and process
585159995Snetchild	   start. */
586159995Snetchild	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
587159995Snetchild	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
588159995Snetchild	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
589159995Snetchild	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
59069995Sdes	PS_ADD("startcode",	"%u",	(unsigned)0);
59167588Sdes	PS_ADD("endcode",	"%u",	0); /* XXX */
59267588Sdes	PS_ADD("startstack",	"%u",	0); /* XXX */
593159995Snetchild	PS_ADD("kstkesp",	"%u",	0); /* XXX */
594159995Snetchild	PS_ADD("kstkeip",	"%u",	0); /* XXX */
595159995Snetchild	PS_ADD("signal",	"%u",	0); /* XXX */
596159995Snetchild	PS_ADD("blocked",	"%u",	0); /* XXX */
597159995Snetchild	PS_ADD("sigignore",	"%u",	0); /* XXX */
598159995Snetchild	PS_ADD("sigcatch",	"%u",	0); /* XXX */
59967588Sdes	PS_ADD("wchan",		"%u",	0); /* XXX */
600159995Snetchild	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
601159995Snetchild	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
60269799Sdes	PS_ADD("exitsignal",	"%d",	0); /* XXX */
603159995Snetchild	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
604159995Snetchild	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
605159995Snetchild	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
60667588Sdes#undef PS_ADD
60778025Sdes	sbuf_putc(sb, '\n');
608119068Sdes
60978025Sdes	return (0);
61067588Sdes}
61167588Sdes
61267588Sdes/*
613119911Sdes * Filler function for proc/pid/statm
614119911Sdes */
615119911Sdesstatic int
616119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS)
617119911Sdes{
618119911Sdes	struct kinfo_proc kp;
619119911Sdes	segsz_t lsize;
620120340Sdes
621119911Sdes	PROC_LOCK(p);
622119911Sdes	fill_kinfo_proc(p, &kp);
623119911Sdes	PROC_UNLOCK(p);
624119911Sdes
625119911Sdes	/*
626119911Sdes	 * See comments in linprocfs_doprocstatus() regarding the
627119911Sdes	 * computation of lsize.
628119911Sdes	 */
629119911Sdes	/* size resident share trs drs lrs dt */
630119911Sdes	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
631119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
632119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
633119911Sdes	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
634119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
635119911Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
636119911Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
637119911Sdes	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
638119911Sdes	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
639119911Sdes
640119911Sdes	return (0);
641119911Sdes}
642119911Sdes
643119911Sdes/*
64478113Sdes * Filler function for proc/pid/status
64578113Sdes */
64678025Sdesstatic int
64778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS)
64867588Sdes{
64969995Sdes	struct kinfo_proc kp;
65067588Sdes	char *state;
65169799Sdes	segsz_t lsize;
65299072Sjulian	struct thread *td2;
653114983Sjhb	struct sigacts *ps;
65474135Sjlemon	int i;
65567588Sdes
656113611Sjhb	PROC_LOCK(p);
65799072Sjulian	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
65899072Sjulian
65999072Sjulian	if (P_SHOULDSTOP(p)) {
66099072Sjulian		state = "T (stopped)";
66199072Sjulian	} else {
662170307Sjeff		PROC_SLOCK(p);
66399072Sjulian		switch(p->p_state) {
66499072Sjulian		case PRS_NEW:
66599072Sjulian			state = "I (idle)";
66699072Sjulian			break;
66799072Sjulian		case PRS_NORMAL:
66899072Sjulian			if (p->p_flag & P_WEXIT) {
66999072Sjulian				state = "X (exiting)";
67099072Sjulian				break;
67199072Sjulian			}
67299072Sjulian			switch(td2->td_state) {
673103216Sjulian			case TDS_INHIBITED:
67499072Sjulian				state = "S (sleeping)";
67599072Sjulian				break;
67699072Sjulian			case TDS_RUNQ:
67799072Sjulian			case TDS_RUNNING:
67899072Sjulian				state = "R (running)";
67999072Sjulian				break;
68099072Sjulian			default:
68199072Sjulian				state = "? (unknown)";
68299072Sjulian				break;
68399072Sjulian			}
68499072Sjulian			break;
68599072Sjulian		case PRS_ZOMBIE:
68699072Sjulian			state = "Z (zombie)";
68799072Sjulian			break;
68899072Sjulian		default:
68999072Sjulian			state = "? (unknown)";
69099072Sjulian			break;
69199072Sjulian		}
692170307Sjeff		PROC_SUNLOCK(p);
69399072Sjulian	}
69467588Sdes
69569995Sdes	fill_kinfo_proc(p, &kp);
69678025Sdes	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
69778031Sdes	sbuf_printf(sb, "State:\t%s\n",		state);
69867588Sdes
69967588Sdes	/*
70067588Sdes	 * Credentials
70167588Sdes	 */
70278025Sdes	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
70378025Sdes	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
70473923Sjhb						p->p_pptr->p_pid : 0);
70578031Sdes	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
70678031Sdes						p->p_ucred->cr_uid,
70778031Sdes						p->p_ucred->cr_svuid,
70878031Sdes						/* FreeBSD doesn't have fsuid */
70978031Sdes						p->p_ucred->cr_uid);
71078031Sdes	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
71178031Sdes						p->p_ucred->cr_gid,
71278031Sdes						p->p_ucred->cr_svgid,
71378031Sdes						/* FreeBSD doesn't have fsgid */
71478031Sdes						p->p_ucred->cr_gid);
71578025Sdes	sbuf_cat(sb, "Groups:\t");
71667588Sdes	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
71778031Sdes		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
71871471Sjhb	PROC_UNLOCK(p);
71978025Sdes	sbuf_putc(sb, '\n');
720119068Sdes
72167588Sdes	/*
72267588Sdes	 * Memory
72369799Sdes	 *
72469799Sdes	 * While our approximation of VmLib may not be accurate (I
72569799Sdes	 * don't know of a simple way to verify it, and I'm not sure
72669799Sdes	 * it has much meaning anyway), I believe it's good enough.
72769799Sdes	 *
72869799Sdes	 * The same code that could (I think) accurately compute VmLib
72969799Sdes	 * could also compute VmLck, but I don't really care enough to
73069799Sdes	 * implement it. Submissions are welcome.
73167588Sdes	 */
732113574Sjhb	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
73378025Sdes	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
734113574Sjhb	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
735113574Sjhb	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
736113574Sjhb	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
737113574Sjhb	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
73869995Sdes	lsize = B2P(kp.ki_size) - kp.ki_dsize -
73969995Sdes	    kp.ki_ssize - kp.ki_tsize - 1;
740113574Sjhb	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
74167588Sdes
74267588Sdes	/*
74367588Sdes	 * Signal masks
74467588Sdes	 *
74567588Sdes	 * We support up to 128 signals, while Linux supports 32,
74667588Sdes	 * but we only define 32 (the same 32 as Linux, to boot), so
74767588Sdes	 * just show the lower 32 bits of each mask. XXX hack.
74867588Sdes	 *
74967588Sdes	 * NB: on certain platforms (Sparc at least) Linux actually
75067588Sdes	 * supports 64 signals, but this code is a long way from
75167588Sdes	 * running on anything but i386, so ignore that for now.
75267588Sdes	 */
75371471Sjhb	PROC_LOCK(p);
754104306Sjmallett	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
75569799Sdes	/*
75669799Sdes	 * I can't seem to find out where the signal mask is in
75769799Sdes	 * relation to struct proc, so SigBlk is left unimplemented.
75869799Sdes	 */
75978025Sdes	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
760114983Sjhb	ps = p->p_sigacts;
761114983Sjhb	mtx_lock(&ps->ps_mtx);
762114983Sjhb	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
763114983Sjhb	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
764114983Sjhb	mtx_unlock(&ps->ps_mtx);
76571471Sjhb	PROC_UNLOCK(p);
766119068Sdes
76767588Sdes	/*
76867588Sdes	 * Linux also prints the capability masks, but we don't have
76967588Sdes	 * capabilities yet, and when we do get them they're likely to
77067588Sdes	 * be meaningless to Linux programs, so we lie. XXX
77167588Sdes	 */
77278025Sdes	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
77378025Sdes	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
77478025Sdes	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
775119068Sdes
77678025Sdes	return (0);
77767588Sdes}
77874135Sjlemon
779119911Sdes
78078113Sdes/*
781119911Sdes * Filler function for proc/pid/cwd
782119911Sdes */
783119911Sdesstatic int
784119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS)
785119911Sdes{
786119911Sdes	char *fullpath = "unknown";
787119911Sdes	char *freepath = NULL;
788119911Sdes
789119911Sdes	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
790119911Sdes	sbuf_printf(sb, "%s", fullpath);
791119911Sdes	if (freepath)
792119911Sdes		free(freepath, M_TEMP);
793119911Sdes	return (0);
794119911Sdes}
795119911Sdes
796119911Sdes/*
797119911Sdes * Filler function for proc/pid/root
798119911Sdes */
799119911Sdesstatic int
800119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS)
801119911Sdes{
802119911Sdes	struct vnode *rvp;
803119911Sdes	char *fullpath = "unknown";
804119911Sdes	char *freepath = NULL;
805119911Sdes
806119911Sdes	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
807119911Sdes	vn_fullpath(td, rvp, &fullpath, &freepath);
808119911Sdes	sbuf_printf(sb, "%s", fullpath);
809119911Sdes	if (freepath)
810119911Sdes		free(freepath, M_TEMP);
811119911Sdes	return (0);
812119911Sdes}
813119911Sdes
814119911Sdes/*
81578113Sdes * Filler function for proc/pid/cmdline
81678113Sdes */
81778025Sdesstatic int
81878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS)
81978113Sdes{
82078113Sdes	struct ps_strings pstr;
821138281Scperciva	char **ps_argvstr;
82278113Sdes	int error, i;
82378113Sdes
82478113Sdes	/*
82578113Sdes	 * If we are using the ps/cmdline caching, use that.  Otherwise
82678113Sdes	 * revert back to the old way which only implements full cmdline
82778113Sdes	 * for the currept process and just p->p_comm for all other
82878113Sdes	 * processes.
82978113Sdes	 * Note that if the argv is no longer available, we deliberately
83078113Sdes	 * don't fall back on p->p_comm or return an error: the authentic
83178113Sdes	 * Linux behaviour is to return zero-length in this case.
83278113Sdes	 */
83378113Sdes
83494620Sjhb	PROC_LOCK(p);
835127694Spjd	if (p->p_args && p_cansee(td, p) == 0) {
83694620Sjhb		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
83794620Sjhb		PROC_UNLOCK(p);
83894620Sjhb	} else if (p != td->td_proc) {
83994620Sjhb		PROC_UNLOCK(p);
84094620Sjhb		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
84194620Sjhb	} else {
84294620Sjhb		PROC_UNLOCK(p);
843103767Sjake		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
844103767Sjake		    sizeof(pstr));
84594620Sjhb		if (error)
84694620Sjhb			return (error);
847138281Scperciva		if (pstr.ps_nargvstr > ARG_MAX)
848138281Scperciva			return (E2BIG);
849138281Scperciva		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
850138281Scperciva		    M_TEMP, M_WAITOK);
851138281Scperciva		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
852138281Scperciva		    pstr.ps_nargvstr * sizeof(char *));
853138281Scperciva		if (error) {
854138281Scperciva			free(ps_argvstr, M_TEMP);
855138281Scperciva			return (error);
856138281Scperciva		}
85794620Sjhb		for (i = 0; i < pstr.ps_nargvstr; i++) {
858138281Scperciva			sbuf_copyin(sb, ps_argvstr[i], 0);
85994620Sjhb			sbuf_printf(sb, "%c", '\0');
86078113Sdes		}
861138281Scperciva		free(ps_argvstr, M_TEMP);
86278113Sdes	}
86378113Sdes
86478113Sdes	return (0);
86578113Sdes}
86678113Sdes
86778113Sdes/*
868116173Sobrien * Filler function for proc/pid/environ
869116173Sobrien */
870116173Sobrienstatic int
871116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS)
872116173Sobrien{
873168762Sdes
874116173Sobrien	sbuf_printf(sb, "doprocenviron\n%c", '\0');
875116173Sobrien	return (0);
876116173Sobrien}
877116173Sobrien
878116173Sobrien/*
879116173Sobrien * Filler function for proc/pid/maps
880116173Sobrien */
881116173Sobrienstatic int
882116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS)
883116173Sobrien{
884185984Skib	struct vmspace *vm;
885185984Skib	vm_map_t map;
886185765Skib	vm_map_entry_t entry, tmp_entry;
887121265Scognet	vm_object_t obj, tobj, lobj;
888185765Skib	vm_offset_t e_start, e_end;
889121265Scognet	vm_ooffset_t off = 0;
890185765Skib	vm_prot_t e_prot;
891185765Skib	unsigned int last_timestamp;
892121265Scognet	char *name = "", *freename = NULL;
893121265Scognet	ino_t ino;
894121265Scognet	int ref_count, shadow_count, flags;
895121265Scognet	int error;
896137507Sphk	struct vnode *vp;
897137507Sphk	struct vattr vat;
898161094Skib	int locked;
899168762Sdes
900121246Scognet	PROC_LOCK(p);
901121246Scognet	error = p_candebug(td, p);
902121246Scognet	PROC_UNLOCK(p);
903121246Scognet	if (error)
904121246Scognet		return (error);
905168762Sdes
906121246Scognet	if (uio->uio_rw != UIO_READ)
907121246Scognet		return (EOPNOTSUPP);
908168762Sdes
909121246Scognet	error = 0;
910185984Skib	vm = vmspace_acquire_ref(p);
911185984Skib	if (vm == NULL)
912185984Skib		return (ESRCH);
913185984Skib	map = &vm->vm_map;
914169156Salc	vm_map_lock_read(map);
915183600Skib	for (entry = map->header.next; entry != &map->header;
916121246Scognet	    entry = entry->next) {
917121265Scognet		name = "";
918121265Scognet		freename = NULL;
919121246Scognet		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
920121246Scognet			continue;
921185765Skib		e_prot = entry->protection;
922185765Skib		e_start = entry->start;
923185765Skib		e_end = entry->end;
924121246Scognet		obj = entry->object.vm_object;
925169156Salc		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
926169156Salc			VM_OBJECT_LOCK(tobj);
927169156Salc			if (lobj != obj)
928169156Salc				VM_OBJECT_UNLOCK(lobj);
929121246Scognet			lobj = tobj;
930169156Salc		}
931185765Skib		last_timestamp = map->timestamp;
932185765Skib		vm_map_unlock_read(map);
933121246Scognet		ino = 0;
934121246Scognet		if (lobj) {
935121246Scognet			off = IDX_TO_OFF(lobj->size);
936161094Skib			if (lobj->type == OBJT_VNODE) {
937161094Skib				vp = lobj->handle;
938161094Skib				if (vp)
939161094Skib					vref(vp);
940121246Scognet			}
941161094Skib			else
942161094Skib				vp = NULL;
943169156Salc			if (lobj != obj)
944169156Salc				VM_OBJECT_UNLOCK(lobj);
945121246Scognet			flags = obj->flags;
946121246Scognet			ref_count = obj->ref_count;
947121246Scognet			shadow_count = obj->shadow_count;
948169156Salc			VM_OBJECT_UNLOCK(obj);
949161094Skib			if (vp) {
950161094Skib				vn_fullpath(td, vp, &name, &freename);
951161094Skib				locked = VFS_LOCK_GIANT(vp->v_mount);
952175202Sattilio				vn_lock(vp, LK_SHARED | LK_RETRY);
953182371Sattilio				VOP_GETATTR(vp, &vat, td->td_ucred);
954161094Skib				ino = vat.va_fileid;
955161094Skib				vput(vp);
956161094Skib				VFS_UNLOCK_GIANT(locked);
957161094Skib			}
958121246Scognet		} else {
959121246Scognet			flags = 0;
960121246Scognet			ref_count = 0;
961121246Scognet			shadow_count = 0;
962121246Scognet		}
963168762Sdes
964121246Scognet		/*
965168762Sdes		 * format:
966121246Scognet		 *  start, end, access, offset, major, minor, inode, name.
967121246Scognet		 */
968183600Skib		error = sbuf_printf(sb,
969121246Scognet		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
970185765Skib		    (u_long)e_start, (u_long)e_end,
971185765Skib		    (e_prot & VM_PROT_READ)?"r":"-",
972185765Skib		    (e_prot & VM_PROT_WRITE)?"w":"-",
973185765Skib		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
974121246Scognet		    "p",
975121265Scognet		    (u_long)off,
976121246Scognet		    0,
977121246Scognet		    0,
978121265Scognet		    (u_long)ino,
979121246Scognet		    *name ? "     " : "",
980121246Scognet		    name
981121246Scognet		    );
982121246Scognet		if (freename)
983121246Scognet			free(freename, M_TEMP);
984185864Skib		vm_map_lock_read(map);
985183600Skib		if (error == -1) {
986183600Skib			error = 0;
987121246Scognet			break;
988169156Salc		}
989186563Skib		if (last_timestamp != map->timestamp) {
990185765Skib			/*
991185765Skib			 * Look again for the entry because the map was
992185765Skib			 * modified while it was unlocked.  Specifically,
993185765Skib			 * the entry may have been clipped, merged, or deleted.
994185765Skib			 */
995185765Skib			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
996185765Skib			entry = tmp_entry;
997185765Skib		}
998121246Scognet	}
999169156Salc	vm_map_unlock_read(map);
1000185984Skib	vmspace_free(vm);
1001168762Sdes
1002121246Scognet	return (error);
1003168762Sdes}
1004168762Sdes
1005116173Sobrien/*
100678113Sdes * Filler function for proc/net/dev
100778113Sdes */
100878025Sdesstatic int
100978025Sdeslinprocfs_donetdev(PFS_FILL_ARGS)
101074135Sjlemon{
1011183550Szec	INIT_VNET_NET(TD_TO_VNET(curthread));
101285129Sdes	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
101374135Sjlemon	struct ifnet *ifp;
101474135Sjlemon
101585129Sdes	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
101683926Sdes	    "Inter-", "   Receive", "  Transmit", " face",
101785129Sdes	    "bytes    packets errs drop fifo frame compressed",
101883926Sdes	    "bytes    packets errs drop fifo frame compressed");
101974135Sjlemon
1020108172Shsu	IFNET_RLOCK();
1021181803Sbz	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
102285129Sdes		linux_ifname(ifp, ifname, sizeof ifname);
102385129Sdes			sbuf_printf(sb, "%6.6s:", ifname);
102483926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
102583926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
102683926Sdes		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
102783926Sdes		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
102874135Sjlemon	}
1029108172Shsu	IFNET_RUNLOCK();
1030119068Sdes
103178025Sdes	return (0);
103274135Sjlemon}
103374135Sjlemon
1034158311Sambrisko/*
1035167159Sjkim * Filler function for proc/sys/kernel/osrelease
1036167159Sjkim */
1037167159Sjkimstatic int
1038167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS)
1039167159Sjkim{
1040167159Sjkim	char osrelease[LINUX_MAX_UTSNAME];
1041167159Sjkim
1042167159Sjkim	linux_get_osrelease(td, osrelease);
1043167159Sjkim	sbuf_printf(sb, "%s\n", osrelease);
1044167159Sjkim
1045167159Sjkim	return (0);
1046167159Sjkim}
1047167159Sjkim
1048167159Sjkim/*
1049167159Sjkim * Filler function for proc/sys/kernel/ostype
1050167159Sjkim */
1051167159Sjkimstatic int
1052167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS)
1053167159Sjkim{
1054167159Sjkim	char osname[LINUX_MAX_UTSNAME];
1055167159Sjkim
1056167159Sjkim	linux_get_osname(td, osname);
1057167159Sjkim	sbuf_printf(sb, "%s\n", osname);
1058167159Sjkim
1059167159Sjkim	return (0);
1060167159Sjkim}
1061167159Sjkim
1062167159Sjkim/*
1063167159Sjkim * Filler function for proc/sys/kernel/version
1064167159Sjkim */
1065167159Sjkimstatic int
1066167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS)
1067167159Sjkim{
1068168762Sdes
1069167159Sjkim	linprocfs_osbuild(td, sb);
1070167159Sjkim	sbuf_cat(sb, "\n");
1071167159Sjkim	return (0);
1072167159Sjkim}
1073167159Sjkim
1074167159Sjkim/*
1075164692Sjkim * Filler function for proc/sys/kernel/msgmni
1076164692Sjkim */
1077164692Sjkimstatic int
1078164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS)
1079164692Sjkim{
1080164692Sjkim
1081168067Sjkim	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1082164692Sjkim	return (0);
1083164692Sjkim}
1084164692Sjkim
1085164692Sjkim/*
1086163251Skeramida * Filler function for proc/sys/kernel/pid_max
1087163129Snetchild */
1088163129Snetchildstatic int
1089163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS)
1090163129Snetchild{
1091163757Snetchild
1092163129Snetchild	sbuf_printf(sb, "%i\n", PID_MAX);
1093163129Snetchild	return (0);
1094163129Snetchild}
1095163129Snetchild
1096163129Snetchild/*
1097164692Sjkim * Filler function for proc/sys/kernel/sem
1098164692Sjkim */
1099164692Sjkimstatic int
1100164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS)
1101164692Sjkim{
1102164692Sjkim
1103168067Sjkim	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1104168067Sjkim	    seminfo.semopm, seminfo.semmni);
1105164692Sjkim	return (0);
1106164692Sjkim}
1107164692Sjkim
1108164692Sjkim/*
1109158311Sambrisko * Filler function for proc/scsi/device_info
1110158311Sambrisko */
1111158311Sambriskostatic int
1112158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS)
1113158311Sambrisko{
1114168762Sdes
1115158311Sambrisko	return (0);
1116158311Sambrisko}
1117158311Sambrisko
1118158311Sambrisko/*
1119158311Sambrisko * Filler function for proc/scsi/scsi
1120158311Sambrisko */
1121158311Sambriskostatic int
1122158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS)
1123158311Sambrisko{
1124168762Sdes
1125158311Sambrisko	return (0);
1126158311Sambrisko}
1127158311Sambrisko
112885538Sphkextern struct cdevsw *cdevsw[];
112985538Sphk
113078113Sdes/*
113178113Sdes * Filler function for proc/devices
113278113Sdes */
113378025Sdesstatic int
113478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS)
113574135Sjlemon{
1136158311Sambrisko	char *char_devices;
113778025Sdes	sbuf_printf(sb, "Character devices:\n");
113874135Sjlemon
1139158311Sambrisko	char_devices = linux_get_char_devices();
1140158311Sambrisko	sbuf_printf(sb, "%s", char_devices);
1141158311Sambrisko	linux_free_get_char_devices(char_devices);
114274135Sjlemon
114378025Sdes	sbuf_printf(sb, "\nBlock devices:\n");
1144119068Sdes
114578025Sdes	return (0);
114674135Sjlemon}
114774135Sjlemon
114878113Sdes/*
114978113Sdes * Filler function for proc/cmdline
115078113Sdes */
115178025Sdesstatic int
115278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS)
115374135Sjlemon{
1154168762Sdes
115578025Sdes	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
115678025Sdes	sbuf_printf(sb, " ro root=302\n");
115778025Sdes	return (0);
115878025Sdes}
115974135Sjlemon
116083926Sdes#if 0
116178025Sdes/*
116283926Sdes * Filler function for proc/modules
116383926Sdes */
116483926Sdesstatic int
116583926Sdeslinprocfs_domodules(PFS_FILL_ARGS)
116683926Sdes{
116783926Sdes	struct linker_file *lf;
1168119068Sdes
116983926Sdes	TAILQ_FOREACH(lf, &linker_files, link) {
117083926Sdes		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
117183926Sdes		    (unsigned long)lf->size, lf->refs);
117283926Sdes	}
117383926Sdes	return (0);
117483926Sdes}
117583926Sdes#endif
117683926Sdes
117783926Sdes/*
117885129Sdes * Constructor
117978025Sdes */
118085129Sdesstatic int
118185129Sdeslinprocfs_init(PFS_INIT_ARGS)
118285129Sdes{
118385129Sdes	struct pfs_node *root;
118485129Sdes	struct pfs_node *dir;
118574135Sjlemon
118685129Sdes	root = pi->pi_root;
118778025Sdes
1188119923Sdes	/* /proc/... */
1189119911Sdes	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1190167482Sdes	    NULL, NULL, NULL, PFS_RD);
1191119911Sdes	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1192167482Sdes	    NULL, NULL, NULL, PFS_RD);
1193119911Sdes	pfs_create_file(root, "devices", &linprocfs_dodevices,
1194167482Sdes	    NULL, NULL, NULL, PFS_RD);
1195119911Sdes	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1196167482Sdes	    NULL, NULL, NULL, PFS_RD);
1197119911Sdes	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1198167482Sdes	    NULL, NULL, NULL, PFS_RD);
119983926Sdes#if 0
1200119911Sdes	pfs_create_file(root, "modules", &linprocfs_domodules,
1201167482Sdes	    NULL, NULL, NULL, PFS_RD);
120283926Sdes#endif
1203158311Sambrisko	pfs_create_file(root, "mounts", &linprocfs_domtab,
1204167482Sdes	    NULL, NULL, NULL, PFS_RD);
1205119911Sdes	pfs_create_file(root, "mtab", &linprocfs_domtab,
1206167482Sdes	    NULL, NULL, NULL, PFS_RD);
120787543Sdes	pfs_create_link(root, "self", &procfs_docurproc,
1208167482Sdes	    NULL, NULL, NULL, 0);
1209119911Sdes	pfs_create_file(root, "stat", &linprocfs_dostat,
1210167482Sdes	    NULL, NULL, NULL, PFS_RD);
1211119911Sdes	pfs_create_file(root, "uptime", &linprocfs_douptime,
1212167482Sdes	    NULL, NULL, NULL, PFS_RD);
1213119911Sdes	pfs_create_file(root, "version", &linprocfs_doversion,
1214167482Sdes	    NULL, NULL, NULL, PFS_RD);
121578025Sdes
1216119923Sdes	/* /proc/net/... */
1217167482Sdes	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
121885129Sdes	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1219167482Sdes	    NULL, NULL, NULL, PFS_RD);
122078025Sdes
1221119923Sdes	/* /proc/<pid>/... */
1222167482Sdes	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
122385129Sdes	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1224167482Sdes	    NULL, NULL, NULL, PFS_RD);
1225119911Sdes	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1226167482Sdes	    NULL, NULL, NULL, 0);
1227116173Sobrien	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1228167482Sdes	    NULL, NULL, NULL, PFS_RD);
122987543Sdes	pfs_create_link(dir, "exe", &procfs_doprocfile,
1230167482Sdes	    NULL, &procfs_notsystem, NULL, 0);
1231116173Sobrien	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1232167482Sdes	    NULL, NULL, NULL, PFS_RD);
123385129Sdes	pfs_create_file(dir, "mem", &procfs_doprocmem,
1234167482Sdes	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1235119911Sdes	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1236167482Sdes	    NULL, NULL, NULL, 0);
123785129Sdes	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1238167482Sdes	    NULL, NULL, NULL, PFS_RD);
1239119911Sdes	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1240167482Sdes	    NULL, NULL, NULL, PFS_RD);
124185129Sdes	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1242167482Sdes	    NULL, NULL, NULL, PFS_RD);
124385129Sdes
1244158311Sambrisko	/* /proc/scsi/... */
1245167482Sdes	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1246158311Sambrisko	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1247167482Sdes	    NULL, NULL, NULL, PFS_RD);
1248158311Sambrisko	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1249167482Sdes	    NULL, NULL, NULL, PFS_RD);
1250163129Snetchild
1251163129Snetchild	/* /proc/sys/... */
1252167482Sdes	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1253163129Snetchild	/* /proc/sys/kernel/... */
1254167482Sdes	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1255167159Sjkim	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1256167482Sdes	    NULL, NULL, NULL, PFS_RD);
1257167159Sjkim	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1258167482Sdes	    NULL, NULL, NULL, PFS_RD);
1259167159Sjkim	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1260167482Sdes	    NULL, NULL, NULL, PFS_RD);
1261164692Sjkim	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1262167482Sdes	    NULL, NULL, NULL, PFS_RD);
1263163129Snetchild	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1264167482Sdes	    NULL, NULL, NULL, PFS_RD);
1265164692Sjkim	pfs_create_file(dir, "sem", &linprocfs_dosem,
1266167482Sdes	    NULL, NULL, NULL, PFS_RD);
1267163129Snetchild
126885129Sdes	return (0);
126985129Sdes}
127085129Sdes
127185129Sdes/*
127285129Sdes * Destructor
127385129Sdes */
127485129Sdesstatic int
127585129Sdeslinprocfs_uninit(PFS_INIT_ARGS)
127685129Sdes{
127785129Sdes
127885129Sdes	/* nothing to do, pseudofs will GC */
127985129Sdes	return (0);
128085129Sdes}
128185129Sdes
128285129SdesPSEUDOFS(linprocfs, 1);
128378025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1);
128478025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1285168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1286168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1287