linprocfs.c revision 123246
1/*
2 * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 123246 2003-12-07 17:38:20Z des $");
44
45#include <sys/param.h>
46#include <sys/queue.h>
47#include <sys/blist.h>
48#include <sys/conf.h>
49#include <sys/exec.h>
50#include <sys/filedesc.h>
51#include <sys/jail.h>
52#include <sys/kernel.h>
53#include <sys/linker.h>
54#include <sys/lock.h>
55#include <sys/malloc.h>
56#include <sys/mount.h>
57#include <sys/mutex.h>
58#include <sys/namei.h>
59#include <sys/proc.h>
60#include <sys/resourcevar.h>
61#include <sys/sbuf.h>
62#include <sys/smp.h>
63#include <sys/socket.h>
64#include <sys/sysctl.h>
65#include <sys/systm.h>
66#include <sys/tty.h>
67#include <sys/user.h>
68#include <sys/vmmeter.h>
69#include <sys/vnode.h>
70
71#include <net/if.h>
72
73#include <vm/vm.h>
74#include <vm/pmap.h>
75#include <vm/vm_map.h>
76#include <vm/vm_param.h>
77#include <vm/vm_object.h>
78#include <vm/swap_pager.h>
79
80#include <machine/clock.h>
81
82#ifdef __alpha__
83#include <machine/alpha_cpu.h>
84#include <machine/cpuconf.h>
85#include <machine/rpb.h>
86extern int ncpus;
87#endif /* __alpha__ */
88
89#ifdef __i386__
90#include <machine/cputypes.h>
91#include <machine/md_var.h>
92#endif /* __i386__ */
93
94#include <machine/../linux/linux.h>
95#include <compat/linux/linux_ioctl.h>
96#include <compat/linux/linux_mib.h>
97#include <compat/linux/linux_util.h>
98#include <fs/pseudofs/pseudofs.h>
99#include <fs/procfs/procfs.h>
100
101/*
102 * Various conversion macros
103 */
104#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
105#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
106#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
107#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
108#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
109#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
110
111/*
112 * Filler function for proc/meminfo
113 */
114static int
115linprocfs_domeminfo(PFS_FILL_ARGS)
116{
117	unsigned long memtotal;		/* total memory in bytes */
118	unsigned long memused;		/* used memory in bytes */
119	unsigned long memfree;		/* free memory in bytes */
120	unsigned long memshared;	/* shared memory ??? */
121	unsigned long buffers, cached;	/* buffer / cache memory ??? */
122	unsigned long long swaptotal;	/* total swap space in bytes */
123	unsigned long long swapused;	/* used swap space in bytes */
124	unsigned long long swapfree;	/* free swap space in bytes */
125	vm_object_t object;
126	int i, j;
127
128	memtotal = physmem * PAGE_SIZE;
129	/*
130	 * The correct thing here would be:
131	 *
132	memfree = cnt.v_free_count * PAGE_SIZE;
133	memused = memtotal - memfree;
134	 *
135	 * but it might mislead linux binaries into thinking there
136	 * is very little memory left, so we cheat and tell them that
137	 * all memory that isn't wired down is free.
138	 */
139	memused = cnt.v_wire_count * PAGE_SIZE;
140	memfree = memtotal - memused;
141	swap_pager_status(&i, &j);
142	swaptotal = i * PAGE_SIZE;
143	swapused = j * PAGE_SIZE;
144	swapfree = swaptotal - swapused;
145	memshared = 0;
146	TAILQ_FOREACH(object, &vm_object_list, object_list)
147		if (object->shadow_count > 1)
148			memshared += object->resident_page_count;
149	memshared *= PAGE_SIZE;
150	/*
151	 * We'd love to be able to write:
152	 *
153	buffers = bufspace;
154	 *
155	 * but bufspace is internal to vfs_bio.c and we don't feel
156	 * like unstaticizing it just for linprocfs's sake.
157	 */
158	buffers = 0;
159	cached = cnt.v_cache_count * PAGE_SIZE;
160
161	sbuf_printf(sb,
162	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
163	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
164	    "Swap: %llu %llu %llu\n"
165	    "MemTotal: %9lu kB\n"
166	    "MemFree:  %9lu kB\n"
167	    "MemShared:%9lu kB\n"
168	    "Buffers:  %9lu kB\n"
169	    "Cached:   %9lu kB\n"
170	    "SwapTotal:%9llu kB\n"
171	    "SwapFree: %9llu kB\n",
172	    memtotal, memused, memfree, memshared, buffers, cached,
173	    swaptotal, swapused, swapfree,
174	    B2K(memtotal), B2K(memfree),
175	    B2K(memshared), B2K(buffers), B2K(cached),
176	    B2K(swaptotal), B2K(swapfree));
177
178	return (0);
179}
180
181#ifdef __alpha__
182extern struct rpb *hwrpb;
183/*
184 * Filler function for proc/cpuinfo (Alpha version)
185 */
186static int
187linprocfs_docpuinfo(PFS_FILL_ARGS)
188{
189	u_int64_t type, major;
190	struct pcs *pcsp;
191	const char *model, *sysname;
192
193	static const char *cpuname[] = {
194		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
195		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
196	};
197
198	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
199	type = pcsp->pcs_proc_type;
200	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
201	if (major < sizeof(cpuname)/sizeof(char *)) {
202		model = cpuname[major - 1];
203	} else {
204		model = "unknown";
205	}
206
207	sysname = alpha_dsr_sysname();
208
209	sbuf_printf(sb,
210	    "cpu\t\t\t: Alpha\n"
211	    "cpu model\t\t: %s\n"
212	    "cpu variation\t\t: %ld\n"
213	    "cpu revision\t\t: %d\n"
214	    "cpu serial number\t: %s\n"
215	    "system type\t\t: %s\n"
216	    "system variation\t: %s\n"
217	    "system revision\t\t: %d\n"
218	    "system serial number\t: %s\n"
219	    "cycle frequency [Hz]\t: %lu\n"
220	    "timer frequency [Hz]\t: %u\n"
221	    "page size [bytes]\t: %ld\n"
222	    "phys. address bits\t: %ld\n"
223	    "max. addr. space #\t: %ld\n"
224	    "BogoMIPS\t\t: %u.%02u\n"
225	    "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
226	    "user unaligned acc\t: %d (pc=%x,va=%x)\n"
227	    "platform string\t\t: %s\n"
228	    "cpus detected\t\t: %d\n"
229	    ,
230	    model,
231	    pcsp->pcs_proc_var,
232	    *(int *)hwrpb->rpb_revision,
233	    " ",
234	    " ",
235	    "0",
236	    0,
237	    " ",
238	    hwrpb->rpb_cc_freq,
239	    hz,
240	    hwrpb->rpb_page_size,
241	    hwrpb->rpb_phys_addr_size,
242	    hwrpb->rpb_max_asn,
243	    0, 0,
244	    0, 0, 0,
245	    0, 0, 0,
246	    sysname,
247	    ncpus);
248	return (0);
249}
250#endif /* __alpha__ */
251
252#ifdef __i386__
253/*
254 * Filler function for proc/cpuinfo (i386 version)
255 */
256static int
257linprocfs_docpuinfo(PFS_FILL_ARGS)
258{
259	int class, fqmhz, fqkhz;
260	int i;
261
262	/*
263	 * We default the flags to include all non-conflicting flags,
264	 * and the Intel versions of conflicting flags.
265	 */
266	static char *flags[] = {
267		"fpu",	    "vme",     "de",	   "pse",      "tsc",
268		"msr",	    "pae",     "mce",	   "cx8",      "apic",
269		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
270		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
271		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
272		"xmm",	    "b26",     "b27",	   "b28",      "b29",
273		"3dnowext", "3dnow"
274	};
275
276	switch (cpu_class) {
277	case CPUCLASS_286:
278		class = 2;
279		break;
280	case CPUCLASS_386:
281		class = 3;
282		break;
283	case CPUCLASS_486:
284		class = 4;
285		break;
286	case CPUCLASS_586:
287		class = 5;
288		break;
289	case CPUCLASS_686:
290		class = 6;
291		break;
292	default:
293		class = 0;
294		break;
295	}
296
297	for (i = 0; i < mp_ncpus; ++i) {
298		sbuf_printf(sb,
299		    "processor\t: %d\n"
300		    "vendor_id\t: %.20s\n"
301		    "cpu family\t: %d\n"
302		    "model\t\t: %d\n"
303		    "stepping\t: %d\n",
304		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
305		/* XXX per-cpu vendor / class / id? */
306	}
307
308	sbuf_cat(sb,
309	    "flags\t\t:");
310
311	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
312		flags[16] = "fcmov";
313	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
314		flags[24] = "cxmmx";
315	}
316
317	for (i = 0; i < 32; i++)
318		if (cpu_feature & (1 << i))
319			sbuf_printf(sb, " %s", flags[i]);
320	sbuf_cat(sb, "\n");
321	if (class >= 5) {
322		fqmhz = (tsc_freq + 4999) / 1000000;
323		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
324		sbuf_printf(sb,
325		    "cpu MHz\t\t: %d.%02d\n"
326		    "bogomips\t: %d.%02d\n",
327		    fqmhz, fqkhz, fqmhz, fqkhz);
328	}
329
330	return (0);
331}
332#endif /* __i386__ */
333
334/*
335 * Filler function for proc/mtab
336 *
337 * This file doesn't exist in Linux' procfs, but is included here so
338 * users can symlink /compat/linux/etc/mtab to /proc/mtab
339 */
340static int
341linprocfs_domtab(PFS_FILL_ARGS)
342{
343	struct nameidata nd;
344	struct mount *mp;
345	const char *lep;
346	char *dlep, *flep, *mntto, *mntfrom, *fstype;
347	size_t lep_len;
348	int error;
349
350	/* resolve symlinks etc. in the emulation tree prefix */
351	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
352	flep = NULL;
353	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
354		lep = linux_emul_path;
355	else
356		lep = dlep;
357	lep_len = strlen(lep);
358
359	mtx_lock(&mountlist_mtx);
360	error = 0;
361	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
362		error = VFS_STATFS(mp, &mp->mnt_stat, td);
363		if (error)
364			break;
365
366		/* determine device name */
367		mntfrom = mp->mnt_stat.f_mntfromname;
368
369		/* determine mount point */
370		mntto = mp->mnt_stat.f_mntonname;
371		if (strncmp(mntto, lep, lep_len) == 0 &&
372		    mntto[lep_len] == '/')
373			mntto += lep_len;
374
375		/* determine fs type */
376		fstype = mp->mnt_stat.f_fstypename;
377		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
378			mntfrom = fstype = "proc";
379		else if (strcmp(fstype, "procfs") == 0)
380			continue;
381
382		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
383		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
384#define ADD_OPTION(opt, name) \
385	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
386		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
387		ADD_OPTION(MNT_NOEXEC,		"noexec");
388		ADD_OPTION(MNT_NOSUID,		"nosuid");
389		ADD_OPTION(MNT_NODEV,		"nodev");
390		ADD_OPTION(MNT_UNION,		"union");
391		ADD_OPTION(MNT_ASYNC,		"async");
392		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
393		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
394		ADD_OPTION(MNT_NOATIME,		"noatime");
395#undef ADD_OPTION
396		/* a real Linux mtab will also show NFS options */
397		sbuf_printf(sb, " 0 0\n");
398	}
399	mtx_unlock(&mountlist_mtx);
400	if (flep != NULL)
401		free(flep, M_TEMP);
402	return (error);
403}
404
405/*
406 * Filler function for proc/stat
407 */
408static int
409linprocfs_dostat(PFS_FILL_ARGS)
410{
411	int i;
412
413	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
414	    T2J(cp_time[CP_USER]),
415	    T2J(cp_time[CP_NICE]),
416	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
417	    T2J(cp_time[CP_IDLE]));
418	if (mp_ncpus > 1)
419		for (i = 0; i < mp_ncpus; ++i)
420			sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
421			    T2J(cp_time[CP_USER]) / mp_ncpus,
422			    T2J(cp_time[CP_NICE]) / mp_ncpus,
423			    T2J(cp_time[CP_SYS]) / mp_ncpus,
424			    T2J(cp_time[CP_IDLE]) / mp_ncpus);
425	sbuf_printf(sb,
426	    "disk 0 0 0 0\n"
427	    "page %u %u\n"
428	    "swap %u %u\n"
429	    "intr %u\n"
430	    "ctxt %u\n"
431	    "btime %lld\n",
432	    cnt.v_vnodepgsin,
433	    cnt.v_vnodepgsout,
434	    cnt.v_swappgsin,
435	    cnt.v_swappgsout,
436	    cnt.v_intr,
437	    cnt.v_swtch,
438	    (long long)boottime.tv_sec);
439	return (0);
440}
441
442/*
443 * Filler function for proc/uptime
444 */
445static int
446linprocfs_douptime(PFS_FILL_ARGS)
447{
448	struct timeval tv;
449
450	getmicrouptime(&tv);
451	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
452	    (long long)tv.tv_sec, tv.tv_usec / 10000,
453	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
454	return (0);
455}
456
457/*
458 * Filler function for proc/version
459 */
460static int
461linprocfs_doversion(PFS_FILL_ARGS)
462{
463	char osname[LINUX_MAX_UTSNAME];
464	char osrelease[LINUX_MAX_UTSNAME];
465
466	linux_get_osname(td, osname);
467	linux_get_osrelease(td, osrelease);
468
469	sbuf_printf(sb,
470	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
471	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
472	return (0);
473}
474
475/*
476 * Filler function for proc/loadavg
477 */
478static int
479linprocfs_doloadavg(PFS_FILL_ARGS)
480{
481	sbuf_printf(sb,
482	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
483	    (int)(averunnable.ldavg[0] / averunnable.fscale),
484	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
485	    (int)(averunnable.ldavg[1] / averunnable.fscale),
486	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
487	    (int)(averunnable.ldavg[2] / averunnable.fscale),
488	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
489	    1,				/* number of running tasks */
490	    nprocs,			/* number of tasks */
491	    lastpid			/* the last pid */
492	);
493
494	return (0);
495}
496
497/*
498 * Filler function for proc/pid/stat
499 */
500static int
501linprocfs_doprocstat(PFS_FILL_ARGS)
502{
503	struct kinfo_proc kp;
504
505	PROC_LOCK(p);
506	fill_kinfo_proc(p, &kp);
507	sbuf_printf(sb, "%d", p->p_pid);
508#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
509	PS_ADD("comm",		"(%s)",	p->p_comm);
510	PS_ADD("statr",		"%c",	'0'); /* XXX */
511	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
512	PS_ADD("pgrp",		"%d",	p->p_pgid);
513	PS_ADD("session",	"%d",	p->p_session->s_sid);
514	PROC_UNLOCK(p);
515	PS_ADD("tty",		"%d",	0); /* XXX */
516	PS_ADD("tpgid",		"%d",	0); /* XXX */
517	PS_ADD("flags",		"%u",	0); /* XXX */
518	PS_ADD("minflt",	"%u",	0); /* XXX */
519	PS_ADD("cminflt",	"%u",	0); /* XXX */
520	PS_ADD("majflt",	"%u",	0); /* XXX */
521	PS_ADD("cminflt",	"%u",	0); /* XXX */
522	PS_ADD("utime",		"%d",	0); /* XXX */
523	PS_ADD("stime",		"%d",	0); /* XXX */
524	PS_ADD("cutime",	"%d",	0); /* XXX */
525	PS_ADD("cstime",	"%d",	0); /* XXX */
526	PS_ADD("counter",	"%d",	0); /* XXX */
527	PS_ADD("priority",	"%d",	0); /* XXX */
528	PS_ADD("timeout",	"%u",	0); /* XXX */
529	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
530	PS_ADD("starttime",	"%d",	0); /* XXX */
531	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
532	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
533	PS_ADD("rlim",		"%u",	0); /* XXX */
534	PS_ADD("startcode",	"%u",	(unsigned)0);
535	PS_ADD("endcode",	"%u",	0); /* XXX */
536	PS_ADD("startstack",	"%u",	0); /* XXX */
537	PS_ADD("esp",		"%u",	0); /* XXX */
538	PS_ADD("eip",		"%u",	0); /* XXX */
539	PS_ADD("signal",	"%d",	0); /* XXX */
540	PS_ADD("blocked",	"%d",	0); /* XXX */
541	PS_ADD("sigignore",	"%d",	0); /* XXX */
542	PS_ADD("sigcatch",	"%d",	0); /* XXX */
543	PS_ADD("wchan",		"%u",	0); /* XXX */
544	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
545	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
546	PS_ADD("exitsignal",	"%d",	0); /* XXX */
547	PS_ADD("processor",	"%d",	0); /* XXX */
548#undef PS_ADD
549	sbuf_putc(sb, '\n');
550
551	return (0);
552}
553
554/*
555 * Filler function for proc/pid/statm
556 */
557static int
558linprocfs_doprocstatm(PFS_FILL_ARGS)
559{
560	struct kinfo_proc kp;
561	segsz_t lsize;
562
563	PROC_LOCK(p);
564	fill_kinfo_proc(p, &kp);
565	PROC_UNLOCK(p);
566
567	/*
568	 * See comments in linprocfs_doprocstatus() regarding the
569	 * computation of lsize.
570	 */
571	/* size resident share trs drs lrs dt */
572	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
573	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
574	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
575	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
576	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
577	lsize = B2P(kp.ki_size) - kp.ki_dsize -
578	    kp.ki_ssize - kp.ki_tsize - 1;
579	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
580	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
581
582	return (0);
583}
584
585/*
586 * Filler function for proc/pid/status
587 */
588static int
589linprocfs_doprocstatus(PFS_FILL_ARGS)
590{
591	struct kinfo_proc kp;
592	char *state;
593	segsz_t lsize;
594	struct thread *td2;
595	struct sigacts *ps;
596	int i;
597
598	PROC_LOCK(p);
599	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
600
601	if (P_SHOULDSTOP(p)) {
602		state = "T (stopped)";
603	} else {
604		mtx_lock_spin(&sched_lock);
605		switch(p->p_state) {
606		case PRS_NEW:
607			state = "I (idle)";
608			break;
609		case PRS_NORMAL:
610			if (p->p_flag & P_WEXIT) {
611				state = "X (exiting)";
612				break;
613			}
614			switch(td2->td_state) {
615			case TDS_INHIBITED:
616				state = "S (sleeping)";
617				break;
618			case TDS_RUNQ:
619			case TDS_RUNNING:
620				state = "R (running)";
621				break;
622			default:
623				state = "? (unknown)";
624				break;
625			}
626			break;
627		case PRS_ZOMBIE:
628			state = "Z (zombie)";
629			break;
630		default:
631			state = "? (unknown)";
632			break;
633		}
634		mtx_unlock_spin(&sched_lock);
635	}
636
637	fill_kinfo_proc(p, &kp);
638	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
639	sbuf_printf(sb, "State:\t%s\n",		state);
640
641	/*
642	 * Credentials
643	 */
644	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
645	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
646						p->p_pptr->p_pid : 0);
647	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
648						p->p_ucred->cr_uid,
649						p->p_ucred->cr_svuid,
650						/* FreeBSD doesn't have fsuid */
651						p->p_ucred->cr_uid);
652	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
653						p->p_ucred->cr_gid,
654						p->p_ucred->cr_svgid,
655						/* FreeBSD doesn't have fsgid */
656						p->p_ucred->cr_gid);
657	sbuf_cat(sb, "Groups:\t");
658	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
659		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
660	PROC_UNLOCK(p);
661	sbuf_putc(sb, '\n');
662
663	/*
664	 * Memory
665	 *
666	 * While our approximation of VmLib may not be accurate (I
667	 * don't know of a simple way to verify it, and I'm not sure
668	 * it has much meaning anyway), I believe it's good enough.
669	 *
670	 * The same code that could (I think) accurately compute VmLib
671	 * could also compute VmLck, but I don't really care enough to
672	 * implement it. Submissions are welcome.
673	 */
674	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
675	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
676	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
677	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
678	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
679	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
680	lsize = B2P(kp.ki_size) - kp.ki_dsize -
681	    kp.ki_ssize - kp.ki_tsize - 1;
682	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
683
684	/*
685	 * Signal masks
686	 *
687	 * We support up to 128 signals, while Linux supports 32,
688	 * but we only define 32 (the same 32 as Linux, to boot), so
689	 * just show the lower 32 bits of each mask. XXX hack.
690	 *
691	 * NB: on certain platforms (Sparc at least) Linux actually
692	 * supports 64 signals, but this code is a long way from
693	 * running on anything but i386, so ignore that for now.
694	 */
695	PROC_LOCK(p);
696	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
697	/*
698	 * I can't seem to find out where the signal mask is in
699	 * relation to struct proc, so SigBlk is left unimplemented.
700	 */
701	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
702	ps = p->p_sigacts;
703	mtx_lock(&ps->ps_mtx);
704	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
705	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
706	mtx_unlock(&ps->ps_mtx);
707	PROC_UNLOCK(p);
708
709	/*
710	 * Linux also prints the capability masks, but we don't have
711	 * capabilities yet, and when we do get them they're likely to
712	 * be meaningless to Linux programs, so we lie. XXX
713	 */
714	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
715	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
716	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
717
718	return (0);
719}
720
721
722/*
723 * Filler function for proc/pid/cwd
724 */
725static int
726linprocfs_doproccwd(PFS_FILL_ARGS)
727{
728	char *fullpath = "unknown";
729	char *freepath = NULL;
730
731	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
732	sbuf_printf(sb, "%s", fullpath);
733	if (freepath)
734		free(freepath, M_TEMP);
735	return (0);
736}
737
738/*
739 * Filler function for proc/pid/root
740 */
741static int
742linprocfs_doprocroot(PFS_FILL_ARGS)
743{
744	struct vnode *rvp;
745	char *fullpath = "unknown";
746	char *freepath = NULL;
747
748	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
749	vn_fullpath(td, rvp, &fullpath, &freepath);
750	sbuf_printf(sb, "%s", fullpath);
751	if (freepath)
752		free(freepath, M_TEMP);
753	return (0);
754}
755
756/*
757 * Filler function for proc/pid/cmdline
758 */
759static int
760linprocfs_doproccmdline(PFS_FILL_ARGS)
761{
762	struct ps_strings pstr;
763	int error, i;
764
765	/*
766	 * If we are using the ps/cmdline caching, use that.  Otherwise
767	 * revert back to the old way which only implements full cmdline
768	 * for the currept process and just p->p_comm for all other
769	 * processes.
770	 * Note that if the argv is no longer available, we deliberately
771	 * don't fall back on p->p_comm or return an error: the authentic
772	 * Linux behaviour is to return zero-length in this case.
773	 */
774
775	PROC_LOCK(p);
776	if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
777		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
778		PROC_UNLOCK(p);
779	} else if (p != td->td_proc) {
780		PROC_UNLOCK(p);
781		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
782	} else {
783		PROC_UNLOCK(p);
784		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
785		    sizeof(pstr));
786		if (error)
787			return (error);
788		for (i = 0; i < pstr.ps_nargvstr; i++) {
789			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
790			sbuf_printf(sb, "%c", '\0');
791		}
792	}
793
794	return (0);
795}
796
797/*
798 * Filler function for proc/pid/environ
799 */
800static int
801linprocfs_doprocenviron(PFS_FILL_ARGS)
802{
803	sbuf_printf(sb, "doprocenviron\n%c", '\0');
804
805	return (0);
806}
807
808/*
809 * Filler function for proc/pid/maps
810 */
811static int
812linprocfs_doprocmaps(PFS_FILL_ARGS)
813{
814	char mebuffer[512];
815	vm_map_t map = &p->p_vmspace->vm_map;
816	vm_map_entry_t entry;
817	vm_object_t obj, tobj, lobj;
818	vm_ooffset_t off = 0;
819	char *name = "", *freename = NULL;
820	size_t len;
821	ino_t ino;
822	int ref_count, shadow_count, flags;
823	int error;
824
825	PROC_LOCK(p);
826	error = p_candebug(td, p);
827	PROC_UNLOCK(p);
828	if (error)
829		return (error);
830
831	if (uio->uio_rw != UIO_READ)
832		return (EOPNOTSUPP);
833
834	if (uio->uio_offset != 0)
835		return (0);
836
837	error = 0;
838	if (map != &curthread->td_proc->p_vmspace->vm_map)
839		vm_map_lock_read(map);
840        for (entry = map->header.next;
841	    ((uio->uio_resid > 0) && (entry != &map->header));
842	    entry = entry->next) {
843		name = "";
844		freename = NULL;
845		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
846			continue;
847		obj = entry->object.vm_object;
848		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
849			lobj = tobj;
850		ino = 0;
851		if (lobj) {
852			VM_OBJECT_LOCK(lobj);
853			off = IDX_TO_OFF(lobj->size);
854			if (lobj->type == OBJT_VNODE && lobj->handle) {
855				vn_fullpath(td, (struct vnode *)lobj->handle,
856				    &name, &freename);
857				ino = ((struct vnode *)
858				    lobj->handle)->v_cachedid;
859			}
860			flags = obj->flags;
861			ref_count = obj->ref_count;
862			shadow_count = obj->shadow_count;
863			VM_OBJECT_UNLOCK(lobj);
864		} else {
865			flags = 0;
866			ref_count = 0;
867			shadow_count = 0;
868		}
869
870		/*
871	     	 * format:
872		 *  start, end, access, offset, major, minor, inode, name.
873		 */
874		snprintf(mebuffer, sizeof mebuffer,
875		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
876		    (u_long)entry->start, (u_long)entry->end,
877		    (entry->protection & VM_PROT_READ)?"r":"-",
878		    (entry->protection & VM_PROT_WRITE)?"w":"-",
879		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
880		    "p",
881		    (u_long)off,
882		    0,
883		    0,
884		    (u_long)ino,
885		    *name ? "     " : "",
886		    name
887		    );
888		if (freename)
889			free(freename, M_TEMP);
890		len = strlen(mebuffer);
891		if (len > uio->uio_resid)
892			len = uio->uio_resid; /*
893					       * XXX We should probably return
894					       * EFBIG here, as in procfs.
895					       */
896		error = uiomove(mebuffer, len, uio);
897		if (error)
898			break;
899	}
900	if (map != &curthread->td_proc->p_vmspace->vm_map)
901		vm_map_unlock_read(map);
902
903	return (error);
904}
905
906/*
907 * Filler function for proc/net/dev
908 */
909static int
910linprocfs_donetdev(PFS_FILL_ARGS)
911{
912	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
913	struct ifnet *ifp;
914
915	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
916	    "Inter-", "   Receive", "  Transmit", " face",
917	    "bytes    packets errs drop fifo frame compressed",
918	    "bytes    packets errs drop fifo frame compressed");
919
920	IFNET_RLOCK();
921	TAILQ_FOREACH(ifp, &ifnet, if_link) {
922		linux_ifname(ifp, ifname, sizeof ifname);
923			sbuf_printf(sb, "%6.6s:", ifname);
924		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
925		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
926		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
927		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
928	}
929	IFNET_RUNLOCK();
930
931	return (0);
932}
933
934#if 0
935extern struct cdevsw *cdevsw[];
936
937/*
938 * Filler function for proc/devices
939 */
940static int
941linprocfs_dodevices(PFS_FILL_ARGS)
942{
943	int i;
944
945	sbuf_printf(sb, "Character devices:\n");
946
947	for (i = 0; i < NUMCDEVSW; i++)
948		if (cdevsw[i] != NULL)
949			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
950
951	sbuf_printf(sb, "\nBlock devices:\n");
952
953	return (0);
954}
955#endif
956
957/*
958 * Filler function for proc/cmdline
959 */
960static int
961linprocfs_docmdline(PFS_FILL_ARGS)
962{
963	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
964	sbuf_printf(sb, " ro root=302\n");
965	return (0);
966}
967
968#if 0
969/*
970 * Filler function for proc/modules
971 */
972static int
973linprocfs_domodules(PFS_FILL_ARGS)
974{
975	struct linker_file *lf;
976
977	TAILQ_FOREACH(lf, &linker_files, link) {
978		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
979		    (unsigned long)lf->size, lf->refs);
980	}
981	return (0);
982}
983#endif
984
985/*
986 * Constructor
987 */
988static int
989linprocfs_init(PFS_INIT_ARGS)
990{
991	struct pfs_node *root;
992	struct pfs_node *dir;
993
994	root = pi->pi_root;
995
996	/* /proc/... */
997	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
998	    NULL, NULL, PFS_RD);
999	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1000	    NULL, NULL, PFS_RD);
1001#if 0
1002	pfs_create_file(root, "devices", &linprocfs_dodevices,
1003	    NULL, NULL, PFS_RD);
1004#endif
1005	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1006	    NULL, NULL, PFS_RD);
1007	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1008	    NULL, NULL, PFS_RD);
1009#if 0
1010	pfs_create_file(root, "modules", &linprocfs_domodules,
1011	    NULL, NULL, PFS_RD);
1012#endif
1013	pfs_create_file(root, "mtab", &linprocfs_domtab,
1014	    NULL, NULL, PFS_RD);
1015	pfs_create_link(root, "self", &procfs_docurproc,
1016	    NULL, NULL, 0);
1017	pfs_create_file(root, "stat", &linprocfs_dostat,
1018	    NULL, NULL, PFS_RD);
1019	pfs_create_file(root, "uptime", &linprocfs_douptime,
1020	    NULL, NULL, PFS_RD);
1021	pfs_create_file(root, "version", &linprocfs_doversion,
1022	    NULL, NULL, PFS_RD);
1023
1024	/* /proc/net/... */
1025	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1026	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1027	    NULL, NULL, PFS_RD);
1028
1029	/* /proc/<pid>/... */
1030	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1031	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1032	    NULL, NULL, PFS_RD);
1033	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1034	    NULL, NULL, 0);
1035	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1036	    NULL, NULL, PFS_RD);
1037	pfs_create_link(dir, "exe", &procfs_doprocfile,
1038	    NULL, &procfs_notsystem, 0);
1039	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1040	    NULL, NULL, PFS_RD);
1041	pfs_create_file(dir, "mem", &procfs_doprocmem,
1042	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1043	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1044	    NULL, NULL, 0);
1045	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1046	    NULL, NULL, PFS_RD);
1047	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1048	    NULL, NULL, PFS_RD);
1049	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1050	    NULL, NULL, PFS_RD);
1051
1052	return (0);
1053}
1054
1055/*
1056 * Destructor
1057 */
1058static int
1059linprocfs_uninit(PFS_INIT_ARGS)
1060{
1061
1062	/* nothing to do, pseudofs will GC */
1063	return (0);
1064}
1065
1066PSEUDOFS(linprocfs, 1);
1067MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1068MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1069