linprocfs.c revision 159995
191174Stmm/*-
291174Stmm * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
391174Stmm * Copyright (c) 1999 Pierre Beyssac
491174Stmm * Copyright (c) 1993 Jan-Simon Pendry
591174Stmm * Copyright (c) 1993
691174Stmm *	The Regents of the University of California.  All rights reserved.
791174Stmm *
891174Stmm * This code is derived from software contributed to Berkeley by
991174Stmm * Jan-Simon Pendry.
1091174Stmm *
1191174Stmm * Redistribution and use in source and binary forms, with or without
1291174Stmm * modification, are permitted provided that the following conditions
1391174Stmm * are met:
1491174Stmm * 1. Redistributions of source code must retain the above copyright
1591174Stmm *    notice, this list of conditions and the following disclaimer.
1691174Stmm * 2. Redistributions in binary form must reproduce the above copyright
1791174Stmm *    notice, this list of conditions and the following disclaimer in the
1891174Stmm *    documentation and/or other materials provided with the distribution.
1991174Stmm * 3. All advertising materials mentioning features or use of this software
2091174Stmm *    must display the following acknowledgement:
2191174Stmm *	This product includes software developed by the University of
2291174Stmm *	California, Berkeley and its contributors.
2391174Stmm * 4. Neither the name of the University nor the names of its contributors
2491174Stmm *    may be used to endorse or promote products derived from this software
2591174Stmm *    without specific prior written permission.
2691174Stmm *
2791174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2891174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2991174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3091174Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3191174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3291174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3391174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3491174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3591174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3691174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3791174Stmm * SUCH DAMAGE.
3891174Stmm *
3991174Stmm *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
4091174Stmm */
4191174Stmm
4291174Stmm#include <sys/cdefs.h>
4391174Stmm__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 159995 2006-06-27 20:11:58Z netchild $");
4491174Stmm
4591174Stmm#include <sys/param.h>
4691174Stmm#include <sys/queue.h>
4791174Stmm#include <sys/blist.h>
4891174Stmm#include <sys/conf.h>
4991174Stmm#include <sys/exec.h>
5091174Stmm#include <sys/filedesc.h>
5191174Stmm#include <sys/jail.h>
5291174Stmm#include <sys/kernel.h>
5391174Stmm#include <sys/linker.h>
5491174Stmm#include <sys/lock.h>
5591174Stmm#include <sys/malloc.h>
5691174Stmm#include <sys/mount.h>
5791174Stmm#include <sys/mutex.h>
5891174Stmm#include <sys/namei.h>
5991174Stmm#include <sys/proc.h>
6091174Stmm#include <sys/resourcevar.h>
6191174Stmm#include <sys/sbuf.h>
6291174Stmm#include <sys/smp.h>
6391174Stmm#include <sys/socket.h>
6491174Stmm#include <sys/sysctl.h>
6591174Stmm#include <sys/systm.h>
6691174Stmm#include <sys/time.h>
6791174Stmm#include <sys/tty.h>
6891174Stmm#include <sys/user.h>
6991174Stmm#include <sys/vmmeter.h>
7091174Stmm#include <sys/vnode.h>
7191174Stmm
7291174Stmm#include <net/if.h>
7391174Stmm
7491174Stmm#include <vm/vm.h>
7591174Stmm#include <vm/pmap.h>
7691174Stmm#include <vm/vm_map.h>
7791174Stmm#include <vm/vm_param.h>
7891174Stmm#include <vm/vm_object.h>
7991174Stmm#include <vm/swap_pager.h>
8091174Stmm
8191174Stmm#include <machine/clock.h>
8291174Stmm
8391174Stmm#if defined(__i386__) || defined(__amd64__)
8491174Stmm#include <machine/cputypes.h>
8591174Stmm#include <machine/md_var.h>
8691174Stmm#endif /* __i386__ || __amd64__ */
8791174Stmm
8891174Stmm#include "opt_compat.h"
8991174Stmm#ifdef COMPAT_LINUX32				/* XXX */
9091174Stmm#include <machine/../linux32/linux.h>
9191174Stmm#else
9291174Stmm#include <machine/../linux/linux.h>
9391174Stmm#endif
9491174Stmm#include <compat/linux/linux_ioctl.h>
9591174Stmm#include <compat/linux/linux_mib.h>
9691174Stmm#include <compat/linux/linux_util.h>
9791174Stmm#include <fs/pseudofs/pseudofs.h>
9891174Stmm#include <fs/procfs/procfs.h>
9991174Stmm
10091174Stmm/*
10191174Stmm * Various conversion macros
10291174Stmm */
10391174Stmm#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
10491174Stmm#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
10591174Stmm#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
10691174Stmm#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
10791174Stmm#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
10891174Stmm#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
10991174Stmm
11091174Stmm/**
11191174Stmm * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
11291174Stmm *
11391174Stmm * The linux procfs state field displays one of the characters RSDZTW to
11491174Stmm * denote running, sleeping in an interruptible wait, waiting in an
11591174Stmm * uninteruptible disk sleep, a zombie process, process is being traced
11691174Stmm * or stopped, or process is paging respectively.
11791174Stmm *
11891174Stmm * Our struct kinfo_proc contains the variable ki_stat which contains a
11991174Stmm * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
12091174Stmm *
12191174Stmm * This character array is used with ki_stati-1 as an index and tries to
12291174Stmm * map our states to suitable linux states.
12391174Stmm */
12491174Stmmstatic char *linux_state = "RRSTZDD";
12591174Stmm
12691174Stmm/*
12791174Stmm * Filler function for proc/meminfo
12891174Stmm */
12991174Stmmstatic int
13091174Stmmlinprocfs_domeminfo(PFS_FILL_ARGS)
13191174Stmm{
13291174Stmm	unsigned long memtotal;		/* total memory in bytes */
13391174Stmm	unsigned long memused;		/* used memory in bytes */
13491174Stmm	unsigned long memfree;		/* free memory in bytes */
13591174Stmm	unsigned long memshared;	/* shared memory ??? */
13691174Stmm	unsigned long buffers, cached;	/* buffer / cache memory ??? */
13791174Stmm	unsigned long long swaptotal;	/* total swap space in bytes */
13891174Stmm	unsigned long long swapused;	/* used swap space in bytes */
13991174Stmm	unsigned long long swapfree;	/* free swap space in bytes */
14091174Stmm	vm_object_t object;
14191174Stmm	int i, j;
14291174Stmm
14391174Stmm	memtotal = physmem * PAGE_SIZE;
14491174Stmm	/*
14591174Stmm	 * The correct thing here would be:
14691174Stmm	 *
14791174Stmm	memfree = cnt.v_free_count * PAGE_SIZE;
14891174Stmm	memused = memtotal - memfree;
14991174Stmm	 *
15091174Stmm	 * but it might mislead linux binaries into thinking there
15191174Stmm	 * is very little memory left, so we cheat and tell them that
15291174Stmm	 * all memory that isn't wired down is free.
15391174Stmm	 */
15491174Stmm	memused = cnt.v_wire_count * PAGE_SIZE;
15591174Stmm	memfree = memtotal - memused;
15691174Stmm	swap_pager_status(&i, &j);
15791174Stmm	swaptotal = (unsigned long long)i * PAGE_SIZE;
15891174Stmm	swapused = (unsigned long long)j * PAGE_SIZE;
15992889Sobrien	swapfree = swaptotal - swapused;
16091174Stmm	memshared = 0;
16192889Sobrien	mtx_lock(&vm_object_list_mtx);
16292889Sobrien	TAILQ_FOREACH(object, &vm_object_list, object_list)
16392889Sobrien		if (object->shadow_count > 1)
16491174Stmm			memshared += object->resident_page_count;
16591174Stmm	mtx_unlock(&vm_object_list_mtx);
16691174Stmm	memshared *= PAGE_SIZE;
16791174Stmm	/*
16891174Stmm	 * We'd love to be able to write:
16991174Stmm	 *
17091174Stmm	buffers = bufspace;
17191174Stmm	 *
17291174Stmm	 * but bufspace is internal to vfs_bio.c and we don't feel
17391174Stmm	 * like unstaticizing it just for linprocfs's sake.
17491174Stmm	 */
17591174Stmm	buffers = 0;
17691174Stmm	cached = cnt.v_cache_count * PAGE_SIZE;
17791174Stmm
17891174Stmm	sbuf_printf(sb,
17991174Stmm	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
18091174Stmm	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
18191174Stmm	    "Swap: %llu %llu %llu\n"
18291174Stmm	    "MemTotal: %9lu kB\n"
18391174Stmm	    "MemFree:  %9lu kB\n"
18491174Stmm	    "MemShared:%9lu kB\n"
18591174Stmm	    "Buffers:  %9lu kB\n"
18691174Stmm	    "Cached:   %9lu kB\n"
18791174Stmm	    "SwapTotal:%9llu kB\n"
18891174Stmm	    "SwapFree: %9llu kB\n",
18991174Stmm	    memtotal, memused, memfree, memshared, buffers, cached,
19091174Stmm	    swaptotal, swapused, swapfree,
19191174Stmm	    B2K(memtotal), B2K(memfree),
19291174Stmm	    B2K(memshared), B2K(buffers), B2K(cached),
19391174Stmm	    B2K(swaptotal), B2K(swapfree));
19491174Stmm
19591174Stmm	return (0);
19691174Stmm}
19791174Stmm
19891174Stmm#if defined(__i386__) || defined(__amd64__)
19991174Stmm/*
20091174Stmm * Filler function for proc/cpuinfo (i386 & amd64 version)
20191174Stmm */
20291174Stmmstatic int
20391174Stmmlinprocfs_docpuinfo(PFS_FILL_ARGS)
20491174Stmm{
20591174Stmm	int hw_model[2];
20691174Stmm	char model[128];
20791174Stmm	size_t size;
20891174Stmm	int class, fqmhz, fqkhz;
20991174Stmm	int i;
21091174Stmm
21191174Stmm	/*
21291174Stmm	 * We default the flags to include all non-conflicting flags,
21391174Stmm	 * and the Intel versions of conflicting flags.
21491174Stmm	 */
21591174Stmm	static char *flags[] = {
21691174Stmm		"fpu",	    "vme",     "de",	   "pse",      "tsc",
21791174Stmm		"msr",	    "pae",     "mce",	   "cx8",      "apic",
21891174Stmm		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
21991174Stmm		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
22091174Stmm		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
22191174Stmm		"xmm",	    "b26",     "b27",	   "b28",      "b29",
22291174Stmm		"3dnowext", "3dnow"
22391174Stmm	};
22491174Stmm
22591174Stmm	switch (cpu_class) {
22691174Stmm#ifdef __i386__
22791174Stmm	case CPUCLASS_286:
22891174Stmm		class = 2;
22991174Stmm		break;
23091174Stmm	case CPUCLASS_386:
23191174Stmm		class = 3;
23291174Stmm		break;
23391174Stmm	case CPUCLASS_486:
23491174Stmm		class = 4;
23591174Stmm		break;
23691174Stmm	case CPUCLASS_586:
23791174Stmm		class = 5;
23891174Stmm		break;
23991174Stmm	case CPUCLASS_686:
24091174Stmm		class = 6;
24191174Stmm		break;
24291174Stmm	default:
24391174Stmm		class = 0;
24491174Stmm		break;
24591174Stmm#else /* __amd64__ */
24691174Stmm	default:
24791174Stmm		class = 15;
24891174Stmm		break;
24991174Stmm#endif
25091174Stmm	}
25191174Stmm
25291174Stmm	hw_model[0] = CTL_HW;
25391174Stmm	hw_model[1] = HW_MODEL;
25491174Stmm	model[0] = '\0';
25591174Stmm	size = sizeof(model);
25691174Stmm	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
25791174Stmm		strcpy(model, "unknown");
25891174Stmm	for (i = 0; i < mp_ncpus; ++i) {
25991174Stmm		sbuf_printf(sb,
26091174Stmm		    "processor\t: %d\n"
26191174Stmm		    "vendor_id\t: %.20s\n"
26291174Stmm		    "cpu family\t: %d\n"
26391174Stmm		    "model\t\t: %d\n"
26491174Stmm		    "model name\t: %s\n"
26591174Stmm		    "stepping\t: %d\n",
26691174Stmm		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
26791174Stmm		/* XXX per-cpu vendor / class / model / id? */
26891174Stmm	}
26991174Stmm
27091174Stmm	sbuf_cat(sb,
27191174Stmm	    "flags\t\t:");
272
273	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
274		flags[16] = "fcmov";
275	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
276		flags[24] = "cxmmx";
277	}
278
279	for (i = 0; i < 32; i++)
280		if (cpu_feature & (1 << i))
281			sbuf_printf(sb, " %s", flags[i]);
282	sbuf_cat(sb, "\n");
283	if (class >= 5) {
284		fqmhz = (tsc_freq + 4999) / 1000000;
285		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
286		sbuf_printf(sb,
287		    "cpu MHz\t\t: %d.%02d\n"
288		    "bogomips\t: %d.%02d\n",
289		    fqmhz, fqkhz, fqmhz, fqkhz);
290	}
291
292	return (0);
293}
294#endif /* __i386__ || __amd64__ */
295
296/*
297 * Filler function for proc/mtab
298 *
299 * This file doesn't exist in Linux' procfs, but is included here so
300 * users can symlink /compat/linux/etc/mtab to /proc/mtab
301 */
302static int
303linprocfs_domtab(PFS_FILL_ARGS)
304{
305	struct nameidata nd;
306	struct mount *mp;
307	const char *lep;
308	char *dlep, *flep, *mntto, *mntfrom, *fstype;
309	size_t lep_len;
310	int error;
311
312	/* resolve symlinks etc. in the emulation tree prefix */
313	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
314	flep = NULL;
315	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
316		lep = linux_emul_path;
317	else
318		lep = dlep;
319	lep_len = strlen(lep);
320
321	mtx_lock(&mountlist_mtx);
322	error = 0;
323	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
324		/* determine device name */
325		mntfrom = mp->mnt_stat.f_mntfromname;
326
327		/* determine mount point */
328		mntto = mp->mnt_stat.f_mntonname;
329		if (strncmp(mntto, lep, lep_len) == 0 &&
330		    mntto[lep_len] == '/')
331			mntto += lep_len;
332
333		/* determine fs type */
334		fstype = mp->mnt_stat.f_fstypename;
335		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
336			mntfrom = fstype = "proc";
337		else if (strcmp(fstype, "procfs") == 0)
338			continue;
339
340		if (strcmp(fstype, "linsysfs") == 0) {
341			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
342			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
343		} else {
344			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
345			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
346		}
347#define ADD_OPTION(opt, name) \
348	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
349		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
350		ADD_OPTION(MNT_NOEXEC,		"noexec");
351		ADD_OPTION(MNT_NOSUID,		"nosuid");
352		ADD_OPTION(MNT_UNION,		"union");
353		ADD_OPTION(MNT_ASYNC,		"async");
354		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
355		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
356		ADD_OPTION(MNT_NOATIME,		"noatime");
357#undef ADD_OPTION
358		/* a real Linux mtab will also show NFS options */
359		sbuf_printf(sb, " 0 0\n");
360	}
361	mtx_unlock(&mountlist_mtx);
362	if (flep != NULL)
363		free(flep, M_TEMP);
364	return (error);
365}
366
367/*
368 * Filler function for proc/stat
369 */
370static int
371linprocfs_dostat(PFS_FILL_ARGS)
372{
373	int i;
374
375	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
376	    T2J(cp_time[CP_USER]),
377	    T2J(cp_time[CP_NICE]),
378	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
379	    T2J(cp_time[CP_IDLE]));
380	for (i = 0; i < mp_ncpus; ++i)
381		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
382		    T2J(cp_time[CP_USER]) / mp_ncpus,
383		    T2J(cp_time[CP_NICE]) / mp_ncpus,
384		    T2J(cp_time[CP_SYS]) / mp_ncpus,
385		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
386	sbuf_printf(sb,
387	    "disk 0 0 0 0\n"
388	    "page %u %u\n"
389	    "swap %u %u\n"
390	    "intr %u\n"
391	    "ctxt %u\n"
392	    "btime %lld\n",
393	    cnt.v_vnodepgsin,
394	    cnt.v_vnodepgsout,
395	    cnt.v_swappgsin,
396	    cnt.v_swappgsout,
397	    cnt.v_intr,
398	    cnt.v_swtch,
399	    (long long)boottime.tv_sec);
400	return (0);
401}
402
403/*
404 * Filler function for proc/uptime
405 */
406static int
407linprocfs_douptime(PFS_FILL_ARGS)
408{
409	struct timeval tv;
410
411	getmicrouptime(&tv);
412	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
413	    (long long)tv.tv_sec, tv.tv_usec / 10000,
414	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
415	return (0);
416}
417
418/*
419 * Filler function for proc/version
420 */
421static int
422linprocfs_doversion(PFS_FILL_ARGS)
423{
424	char osname[LINUX_MAX_UTSNAME];
425	char osrelease[LINUX_MAX_UTSNAME];
426
427	linux_get_osname(td, osname);
428	linux_get_osrelease(td, osrelease);
429
430	sbuf_printf(sb,
431	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
432	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
433	return (0);
434}
435
436/*
437 * Filler function for proc/loadavg
438 */
439static int
440linprocfs_doloadavg(PFS_FILL_ARGS)
441{
442	sbuf_printf(sb,
443	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
444	    (int)(averunnable.ldavg[0] / averunnable.fscale),
445	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
446	    (int)(averunnable.ldavg[1] / averunnable.fscale),
447	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
448	    (int)(averunnable.ldavg[2] / averunnable.fscale),
449	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
450	    1,				/* number of running tasks */
451	    nprocs,			/* number of tasks */
452	    lastpid			/* the last pid */
453	);
454
455	return (0);
456}
457
458/*
459 * Filler function for proc/pid/stat
460 */
461static int
462linprocfs_doprocstat(PFS_FILL_ARGS)
463{
464	struct kinfo_proc kp;
465
466	PROC_LOCK(p);
467	fill_kinfo_proc(p, &kp);
468	sbuf_printf(sb, "%d", p->p_pid);
469#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
470	PS_ADD("comm",		"(%s)",	p->p_comm);
471	KASSERT(kp.ki_stat <= sizeof(linux_state),
472		("linprocfs: don't know how to handle unknown FreeBSD state"));
473	PS_ADD("state",		"%c",	linux_state[kp.ki_stat - 1]);
474	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
475	PS_ADD("pgrp",		"%d",	p->p_pgid);
476	PS_ADD("session",	"%d",	p->p_session->s_sid);
477	PROC_UNLOCK(p);
478	PS_ADD("tty",		"%d",	0); /* XXX */
479	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
480	PS_ADD("flags",		"%u",	0); /* XXX */
481	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
482	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
483	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
484	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
485	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
486	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
487	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
488	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
489	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
490	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
491	PS_ADD("0",		"%d",	0); /* removed field */
492	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
493	/* XXX: starttime is not right, it is the _same_ for _every_ process.
494	   It should be the number of jiffies between system boot and process
495	   start. */
496	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
497	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
498	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
499	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
500	PS_ADD("startcode",	"%u",	(unsigned)0);
501	PS_ADD("endcode",	"%u",	0); /* XXX */
502	PS_ADD("startstack",	"%u",	0); /* XXX */
503	PS_ADD("kstkesp",	"%u",	0); /* XXX */
504	PS_ADD("kstkeip",	"%u",	0); /* XXX */
505	PS_ADD("signal",	"%u",	0); /* XXX */
506	PS_ADD("blocked",	"%u",	0); /* XXX */
507	PS_ADD("sigignore",	"%u",	0); /* XXX */
508	PS_ADD("sigcatch",	"%u",	0); /* XXX */
509	PS_ADD("wchan",		"%u",	0); /* XXX */
510	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
511	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
512	PS_ADD("exitsignal",	"%d",	0); /* XXX */
513	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
514	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
515	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
516#undef PS_ADD
517	sbuf_putc(sb, '\n');
518
519	return (0);
520}
521
522/*
523 * Filler function for proc/pid/statm
524 */
525static int
526linprocfs_doprocstatm(PFS_FILL_ARGS)
527{
528	struct kinfo_proc kp;
529	segsz_t lsize;
530
531	PROC_LOCK(p);
532	fill_kinfo_proc(p, &kp);
533	PROC_UNLOCK(p);
534
535	/*
536	 * See comments in linprocfs_doprocstatus() regarding the
537	 * computation of lsize.
538	 */
539	/* size resident share trs drs lrs dt */
540	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
541	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
542	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
543	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
544	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
545	lsize = B2P(kp.ki_size) - kp.ki_dsize -
546	    kp.ki_ssize - kp.ki_tsize - 1;
547	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
548	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
549
550	return (0);
551}
552
553/*
554 * Filler function for proc/pid/status
555 */
556static int
557linprocfs_doprocstatus(PFS_FILL_ARGS)
558{
559	struct kinfo_proc kp;
560	char *state;
561	segsz_t lsize;
562	struct thread *td2;
563	struct sigacts *ps;
564	int i;
565
566	PROC_LOCK(p);
567	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
568
569	if (P_SHOULDSTOP(p)) {
570		state = "T (stopped)";
571	} else {
572		mtx_lock_spin(&sched_lock);
573		switch(p->p_state) {
574		case PRS_NEW:
575			state = "I (idle)";
576			break;
577		case PRS_NORMAL:
578			if (p->p_flag & P_WEXIT) {
579				state = "X (exiting)";
580				break;
581			}
582			switch(td2->td_state) {
583			case TDS_INHIBITED:
584				state = "S (sleeping)";
585				break;
586			case TDS_RUNQ:
587			case TDS_RUNNING:
588				state = "R (running)";
589				break;
590			default:
591				state = "? (unknown)";
592				break;
593			}
594			break;
595		case PRS_ZOMBIE:
596			state = "Z (zombie)";
597			break;
598		default:
599			state = "? (unknown)";
600			break;
601		}
602		mtx_unlock_spin(&sched_lock);
603	}
604
605	fill_kinfo_proc(p, &kp);
606	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
607	sbuf_printf(sb, "State:\t%s\n",		state);
608
609	/*
610	 * Credentials
611	 */
612	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
613	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
614						p->p_pptr->p_pid : 0);
615	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
616						p->p_ucred->cr_uid,
617						p->p_ucred->cr_svuid,
618						/* FreeBSD doesn't have fsuid */
619						p->p_ucred->cr_uid);
620	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
621						p->p_ucred->cr_gid,
622						p->p_ucred->cr_svgid,
623						/* FreeBSD doesn't have fsgid */
624						p->p_ucred->cr_gid);
625	sbuf_cat(sb, "Groups:\t");
626	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
627		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
628	PROC_UNLOCK(p);
629	sbuf_putc(sb, '\n');
630
631	/*
632	 * Memory
633	 *
634	 * While our approximation of VmLib may not be accurate (I
635	 * don't know of a simple way to verify it, and I'm not sure
636	 * it has much meaning anyway), I believe it's good enough.
637	 *
638	 * The same code that could (I think) accurately compute VmLib
639	 * could also compute VmLck, but I don't really care enough to
640	 * implement it. Submissions are welcome.
641	 */
642	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
643	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
644	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
645	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
646	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
647	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
648	lsize = B2P(kp.ki_size) - kp.ki_dsize -
649	    kp.ki_ssize - kp.ki_tsize - 1;
650	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
651
652	/*
653	 * Signal masks
654	 *
655	 * We support up to 128 signals, while Linux supports 32,
656	 * but we only define 32 (the same 32 as Linux, to boot), so
657	 * just show the lower 32 bits of each mask. XXX hack.
658	 *
659	 * NB: on certain platforms (Sparc at least) Linux actually
660	 * supports 64 signals, but this code is a long way from
661	 * running on anything but i386, so ignore that for now.
662	 */
663	PROC_LOCK(p);
664	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
665	/*
666	 * I can't seem to find out where the signal mask is in
667	 * relation to struct proc, so SigBlk is left unimplemented.
668	 */
669	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
670	ps = p->p_sigacts;
671	mtx_lock(&ps->ps_mtx);
672	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
673	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
674	mtx_unlock(&ps->ps_mtx);
675	PROC_UNLOCK(p);
676
677	/*
678	 * Linux also prints the capability masks, but we don't have
679	 * capabilities yet, and when we do get them they're likely to
680	 * be meaningless to Linux programs, so we lie. XXX
681	 */
682	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
683	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
684	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
685
686	return (0);
687}
688
689
690/*
691 * Filler function for proc/pid/cwd
692 */
693static int
694linprocfs_doproccwd(PFS_FILL_ARGS)
695{
696	char *fullpath = "unknown";
697	char *freepath = NULL;
698
699	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
700	sbuf_printf(sb, "%s", fullpath);
701	if (freepath)
702		free(freepath, M_TEMP);
703	return (0);
704}
705
706/*
707 * Filler function for proc/pid/root
708 */
709static int
710linprocfs_doprocroot(PFS_FILL_ARGS)
711{
712	struct vnode *rvp;
713	char *fullpath = "unknown";
714	char *freepath = NULL;
715
716	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
717	vn_fullpath(td, rvp, &fullpath, &freepath);
718	sbuf_printf(sb, "%s", fullpath);
719	if (freepath)
720		free(freepath, M_TEMP);
721	return (0);
722}
723
724/*
725 * Filler function for proc/pid/cmdline
726 */
727static int
728linprocfs_doproccmdline(PFS_FILL_ARGS)
729{
730	struct ps_strings pstr;
731	char **ps_argvstr;
732	int error, i;
733
734	/*
735	 * If we are using the ps/cmdline caching, use that.  Otherwise
736	 * revert back to the old way which only implements full cmdline
737	 * for the currept process and just p->p_comm for all other
738	 * processes.
739	 * Note that if the argv is no longer available, we deliberately
740	 * don't fall back on p->p_comm or return an error: the authentic
741	 * Linux behaviour is to return zero-length in this case.
742	 */
743
744	PROC_LOCK(p);
745	if (p->p_args && p_cansee(td, p) == 0) {
746		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
747		PROC_UNLOCK(p);
748	} else if (p != td->td_proc) {
749		PROC_UNLOCK(p);
750		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
751	} else {
752		PROC_UNLOCK(p);
753		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
754		    sizeof(pstr));
755		if (error)
756			return (error);
757		if (pstr.ps_nargvstr > ARG_MAX)
758			return (E2BIG);
759		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
760		    M_TEMP, M_WAITOK);
761		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
762		    pstr.ps_nargvstr * sizeof(char *));
763		if (error) {
764			free(ps_argvstr, M_TEMP);
765			return (error);
766		}
767		for (i = 0; i < pstr.ps_nargvstr; i++) {
768			sbuf_copyin(sb, ps_argvstr[i], 0);
769			sbuf_printf(sb, "%c", '\0');
770		}
771		free(ps_argvstr, M_TEMP);
772	}
773
774	return (0);
775}
776
777/*
778 * Filler function for proc/pid/environ
779 */
780static int
781linprocfs_doprocenviron(PFS_FILL_ARGS)
782{
783	sbuf_printf(sb, "doprocenviron\n%c", '\0');
784
785	return (0);
786}
787
788/*
789 * Filler function for proc/pid/maps
790 */
791static int
792linprocfs_doprocmaps(PFS_FILL_ARGS)
793{
794	char mebuffer[512];
795	vm_map_t map = &p->p_vmspace->vm_map;
796	vm_map_entry_t entry;
797	vm_object_t obj, tobj, lobj;
798	vm_ooffset_t off = 0;
799	char *name = "", *freename = NULL;
800	size_t len;
801	ino_t ino;
802	int ref_count, shadow_count, flags;
803	int error;
804	struct vnode *vp;
805	struct vattr vat;
806
807	PROC_LOCK(p);
808	error = p_candebug(td, p);
809	PROC_UNLOCK(p);
810	if (error)
811		return (error);
812
813	if (uio->uio_rw != UIO_READ)
814		return (EOPNOTSUPP);
815
816	if (uio->uio_offset != 0)
817		return (0);
818
819	error = 0;
820	if (map != &curthread->td_proc->p_vmspace->vm_map)
821		vm_map_lock_read(map);
822        for (entry = map->header.next;
823	    ((uio->uio_resid > 0) && (entry != &map->header));
824	    entry = entry->next) {
825		name = "";
826		freename = NULL;
827		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
828			continue;
829		obj = entry->object.vm_object;
830		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
831			lobj = tobj;
832		ino = 0;
833		if (lobj) {
834			vp = lobj->handle;
835			VM_OBJECT_LOCK(lobj);
836			off = IDX_TO_OFF(lobj->size);
837			if (lobj->type == OBJT_VNODE && lobj->handle) {
838				vn_fullpath(td, vp, &name, &freename);
839				VOP_GETATTR(vp, &vat, td->td_ucred, td);
840				ino = vat.va_fileid;
841			}
842			flags = obj->flags;
843			ref_count = obj->ref_count;
844			shadow_count = obj->shadow_count;
845			VM_OBJECT_UNLOCK(lobj);
846		} else {
847			flags = 0;
848			ref_count = 0;
849			shadow_count = 0;
850		}
851
852		/*
853	     	 * format:
854		 *  start, end, access, offset, major, minor, inode, name.
855		 */
856		snprintf(mebuffer, sizeof mebuffer,
857		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
858		    (u_long)entry->start, (u_long)entry->end,
859		    (entry->protection & VM_PROT_READ)?"r":"-",
860		    (entry->protection & VM_PROT_WRITE)?"w":"-",
861		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
862		    "p",
863		    (u_long)off,
864		    0,
865		    0,
866		    (u_long)ino,
867		    *name ? "     " : "",
868		    name
869		    );
870		if (freename)
871			free(freename, M_TEMP);
872		len = strlen(mebuffer);
873		if (len > uio->uio_resid)
874			len = uio->uio_resid; /*
875					       * XXX We should probably return
876					       * EFBIG here, as in procfs.
877					       */
878		error = uiomove(mebuffer, len, uio);
879		if (error)
880			break;
881	}
882	if (map != &curthread->td_proc->p_vmspace->vm_map)
883		vm_map_unlock_read(map);
884
885	return (error);
886}
887
888/*
889 * Filler function for proc/net/dev
890 */
891static int
892linprocfs_donetdev(PFS_FILL_ARGS)
893{
894	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
895	struct ifnet *ifp;
896
897	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
898	    "Inter-", "   Receive", "  Transmit", " face",
899	    "bytes    packets errs drop fifo frame compressed",
900	    "bytes    packets errs drop fifo frame compressed");
901
902	IFNET_RLOCK();
903	TAILQ_FOREACH(ifp, &ifnet, if_link) {
904		linux_ifname(ifp, ifname, sizeof ifname);
905			sbuf_printf(sb, "%6.6s:", ifname);
906		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
907		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
908		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
909		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
910	}
911	IFNET_RUNLOCK();
912
913	return (0);
914}
915
916/*
917 * Filler function for proc/scsi/device_info
918 */
919static int
920linprocfs_doscsidevinfo(PFS_FILL_ARGS)
921{
922	return (0);
923}
924
925/*
926 * Filler function for proc/scsi/scsi
927 */
928static int
929linprocfs_doscsiscsi(PFS_FILL_ARGS)
930{
931	return (0);
932}
933
934extern struct cdevsw *cdevsw[];
935
936/*
937 * Filler function for proc/devices
938 */
939static int
940linprocfs_dodevices(PFS_FILL_ARGS)
941{
942	char *char_devices;
943	sbuf_printf(sb, "Character devices:\n");
944
945	char_devices = linux_get_char_devices();
946	sbuf_printf(sb, "%s", char_devices);
947	linux_free_get_char_devices(char_devices);
948
949	sbuf_printf(sb, "\nBlock devices:\n");
950
951	return (0);
952}
953
954/*
955 * Filler function for proc/cmdline
956 */
957static int
958linprocfs_docmdline(PFS_FILL_ARGS)
959{
960	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
961	sbuf_printf(sb, " ro root=302\n");
962	return (0);
963}
964
965#if 0
966/*
967 * Filler function for proc/modules
968 */
969static int
970linprocfs_domodules(PFS_FILL_ARGS)
971{
972	struct linker_file *lf;
973
974	TAILQ_FOREACH(lf, &linker_files, link) {
975		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
976		    (unsigned long)lf->size, lf->refs);
977	}
978	return (0);
979}
980#endif
981
982/*
983 * Constructor
984 */
985static int
986linprocfs_init(PFS_INIT_ARGS)
987{
988	struct pfs_node *root;
989	struct pfs_node *dir;
990
991	root = pi->pi_root;
992
993	/* /proc/... */
994	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
995	    NULL, NULL, PFS_RD);
996	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
997	    NULL, NULL, PFS_RD);
998	pfs_create_file(root, "devices", &linprocfs_dodevices,
999	    NULL, NULL, PFS_RD);
1000	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1001	    NULL, NULL, PFS_RD);
1002	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1003	    NULL, NULL, PFS_RD);
1004#if 0
1005	pfs_create_file(root, "modules", &linprocfs_domodules,
1006	    NULL, NULL, PFS_RD);
1007#endif
1008	pfs_create_file(root, "mounts", &linprocfs_domtab,
1009	    NULL, NULL, PFS_RD);
1010	pfs_create_file(root, "mtab", &linprocfs_domtab,
1011	    NULL, NULL, PFS_RD);
1012	pfs_create_link(root, "self", &procfs_docurproc,
1013	    NULL, NULL, 0);
1014	pfs_create_file(root, "stat", &linprocfs_dostat,
1015	    NULL, NULL, PFS_RD);
1016	pfs_create_file(root, "uptime", &linprocfs_douptime,
1017	    NULL, NULL, PFS_RD);
1018	pfs_create_file(root, "version", &linprocfs_doversion,
1019	    NULL, NULL, PFS_RD);
1020
1021	/* /proc/net/... */
1022	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1023	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1024	    NULL, NULL, PFS_RD);
1025
1026	/* /proc/<pid>/... */
1027	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1028	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1029	    NULL, NULL, PFS_RD);
1030	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1031	    NULL, NULL, 0);
1032	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1033	    NULL, NULL, PFS_RD);
1034	pfs_create_link(dir, "exe", &procfs_doprocfile,
1035	    NULL, &procfs_notsystem, 0);
1036	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1037	    NULL, NULL, PFS_RD);
1038	pfs_create_file(dir, "mem", &procfs_doprocmem,
1039	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1040	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1041	    NULL, NULL, 0);
1042	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1043	    NULL, NULL, PFS_RD);
1044	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1045	    NULL, NULL, PFS_RD);
1046	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1047	    NULL, NULL, PFS_RD);
1048
1049	/* /proc/scsi/... */
1050	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1051	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1052	    NULL, NULL, PFS_RD);
1053	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1054	    NULL, NULL, PFS_RD);
1055	return (0);
1056}
1057
1058/*
1059 * Destructor
1060 */
1061static int
1062linprocfs_uninit(PFS_INIT_ARGS)
1063{
1064
1065	/* nothing to do, pseudofs will GC */
1066	return (0);
1067}
1068
1069PSEUDOFS(linprocfs, 1);
1070MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1071MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1072