linprocfs.c revision 87275
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 * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 87275 2001-12-03 16:12:27Z rwatson $
42 */
43
44#include <sys/param.h>
45#include <sys/queue.h>
46#include <sys/blist.h>
47#include <sys/conf.h>
48#include <sys/dkstat.h>
49#include <sys/exec.h>
50#include <sys/jail.h>
51#include <sys/kernel.h>
52#include <sys/linker.h>
53#include <sys/lock.h>
54#include <sys/malloc.h>
55#include <sys/mount.h>
56#include <sys/mutex.h>
57#include <sys/namei.h>
58#include <sys/proc.h>
59#include <sys/resourcevar.h>
60#include <sys/sbuf.h>
61#include <sys/socket.h>
62#include <sys/sysctl.h>
63#include <sys/systm.h>
64#include <sys/tty.h>
65#include <sys/user.h>
66#include <sys/vmmeter.h>
67#include <sys/vnode.h>
68
69#include <net/if.h>
70
71#include <vm/vm.h>
72#include <vm/pmap.h>
73#include <vm/vm_map.h>
74#include <vm/vm_param.h>
75#include <vm/vm_object.h>
76#include <vm/vm_zone.h>
77#include <vm/swap_pager.h>
78
79#include <machine/clock.h>
80
81#ifdef __alpha__
82#include <machine/alpha_cpu.h>
83#include <machine/cpuconf.h>
84#include <machine/rpb.h>
85extern int ncpus;
86#endif /* __alpha__ */
87
88#ifdef __i386__
89#include <machine/cputypes.h>
90#include <machine/md_var.h>
91#endif /* __i386__ */
92
93#include <machine/../linux/linux.h>
94#include <compat/linux/linux_ioctl.h>
95#include <compat/linux/linux_mib.h>
96#include <compat/linux/linux_util.h>
97#include <fs/pseudofs/pseudofs.h>
98#include <fs/procfs/procfs.h>
99
100/*
101 * Various conversion macros
102 */
103#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
104#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
105#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
106#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
107#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
108#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
109
110/*
111 * Filler function for proc/meminfo
112 */
113static int
114linprocfs_domeminfo(PFS_FILL_ARGS)
115{
116	unsigned long memtotal;		/* total memory in bytes */
117	unsigned long memused;		/* used memory in bytes */
118	unsigned long memfree;		/* free memory in bytes */
119	unsigned long memshared;	/* shared memory ??? */
120	unsigned long buffers, cached;	/* buffer / cache memory ??? */
121	u_quad_t swaptotal;		/* total swap space in bytes */
122	u_quad_t swapused;		/* used swap space in bytes */
123	u_quad_t swapfree;		/* free swap space in bytes */
124	vm_object_t object;
125
126	memtotal = physmem * PAGE_SIZE;
127	/*
128	 * The correct thing here would be:
129	 *
130	memfree = cnt.v_free_count * PAGE_SIZE;
131	memused = memtotal - memfree;
132	 *
133	 * but it might mislead linux binaries into thinking there
134	 * is very little memory left, so we cheat and tell them that
135	 * all memory that isn't wired down is free.
136	 */
137	memused = cnt.v_wire_count * PAGE_SIZE;
138	memfree = memtotal - memused;
139	if (swapblist == NULL) {
140		swaptotal = 0;
141		swapfree = 0;
142	} else {
143		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
144		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
145	}
146	swapused = swaptotal - swapfree;
147	memshared = 0;
148	TAILQ_FOREACH(object, &vm_object_list, object_list)
149		if (object->shadow_count > 1)
150			memshared += object->resident_page_count;
151	memshared *= PAGE_SIZE;
152	/*
153	 * We'd love to be able to write:
154	 *
155	buffers = bufspace;
156	 *
157	 * but bufspace is internal to vfs_bio.c and we don't feel
158	 * like unstaticizing it just for linprocfs's sake.
159	 */
160	buffers = 0;
161	cached = cnt.v_cache_count * PAGE_SIZE;
162
163	sbuf_printf(sb,
164	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
165	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
166	    "Swap: %llu %llu %llu\n"
167	    "MemTotal: %9lu kB\n"
168	    "MemFree:  %9lu kB\n"
169	    "MemShared:%9lu kB\n"
170	    "Buffers:  %9lu kB\n"
171	    "Cached:   %9lu kB\n"
172	    "SwapTotal:%9llu kB\n"
173	    "SwapFree: %9llu kB\n",
174	    memtotal, memused, memfree, memshared, buffers, cached,
175	    swaptotal, swapused, swapfree,
176	    B2K(memtotal), B2K(memfree),
177	    B2K(memshared), B2K(buffers), B2K(cached),
178	    B2K(swaptotal), B2K(swapfree));
179
180	return (0);
181}
182
183#ifdef __alpha__
184/*
185 * Filler function for proc/cpuinfo (Alpha version)
186 */
187static int
188linprocfs_docpuinfo(PFS_FILL_ARGS)
189{
190	u_int64_t type, major;
191	struct pcs *pcsp;
192	const char *model, *sysname;
193
194	static const char *cpuname[] = {
195		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
196		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
197	};
198
199	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
200	type = pcsp->pcs_proc_type;
201	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
202	if (major < sizeof(cpuname)/sizeof(char *)) {
203		model = cpuname[major - 1];
204	} else {
205		model = "unknown";
206	}
207
208	sysname = alpha_dsr_sysname();
209
210	sbuf_printf(sb,
211	    "cpu\t\t\t: Alpha\n"
212	    "cpu model\t\t: %s\n"
213	    "cpu variation\t\t: %ld\n"
214	    "cpu revision\t\t: %ld\n"
215	    "cpu serial number\t: %s\n"
216	    "system type\t\t: %s\n"
217	    "system variation\t: %s\n"
218	    "system revision\t\t: %ld\n"
219	    "system serial number\t: %s\n"
220	    "cycle frequency [Hz]\t: %lu\n"
221	    "timer frequency [Hz]\t: %lu\n"
222	    "page size [bytes]\t: %ld\n"
223	    "phys. address bits\t: %ld\n"
224	    "max. addr. space #\t: %ld\n"
225	    "BogoMIPS\t\t: %lu.%02lu\n"
226	    "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
227	    "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
228	    "platform string\t\t: %s\n"
229	    "cpus detected\t\t: %d\n"
230	    ,
231	    model,
232	    pcsp->pcs_proc_var,
233	    *(int *)hwrpb->rpb_revision,
234	    " ",
235	    " ",
236	    "0",
237	    0,
238	    " ",
239	    hwrpb->rpb_cc_freq,
240	    hz,
241	    hwrpb->rpb_page_size,
242	    hwrpb->rpb_phys_addr_size,
243	    hwrpb->rpb_max_asn,
244	    0, 0,
245	    0, 0, 0,
246	    0, 0, 0,
247	    sysname,
248	    ncpus);
249	return (0);
250}
251#endif /* __alpha__ */
252
253#ifdef __i386__
254/*
255 * Filler function for proc/cpuinfo (i386 version)
256 */
257static int
258linprocfs_docpuinfo(PFS_FILL_ARGS)
259{
260	int class, i, fqmhz, fqkhz;
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	sbuf_printf(sb,
298	    "processor\t: %d\n"
299	    "vendor_id\t: %.20s\n"
300	    "cpu family\t: %d\n"
301	    "model\t\t: %d\n"
302	    "stepping\t: %d\n",
303	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
304
305	sbuf_cat(sb,
306	    "flags\t\t:");
307
308	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
309		flags[16] = "fcmov";
310	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
311		flags[24] = "cxmmx";
312	}
313
314	for (i = 0; i < 32; i++)
315		if (cpu_feature & (1 << i))
316			sbuf_printf(sb, " %s", flags[i]);
317	sbuf_cat(sb, "\n");
318	if (class >= 5) {
319		fqmhz = (tsc_freq + 4999) / 1000000;
320		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
321		sbuf_printf(sb,
322		    "cpu MHz\t\t: %d.%02d\n"
323		    "bogomips\t: %d.%02d\n",
324		    fqmhz, fqkhz, fqmhz, fqkhz);
325	}
326
327	return (0);
328}
329#endif /* __i386__ */
330
331/*
332 * Filler function for proc/mtab
333 *
334 * This file doesn't exist in Linux' procfs, but is included here so
335 * users can symlink /compat/linux/etc/mtab to /proc/mtab
336 */
337static int
338linprocfs_domtab(PFS_FILL_ARGS)
339{
340	struct nameidata nd;
341	struct mount *mp;
342	char *lep, *flep, *mntto, *mntfrom, *fstype;
343	size_t lep_len;
344	int error;
345
346	/* resolve symlinks etc. in the emulation tree prefix */
347	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
348	flep = NULL;
349	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1)
350		lep = linux_emul_path;
351	lep_len = strlen(lep);
352
353	mtx_lock(&mountlist_mtx);
354	error = 0;
355	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
356		error = VFS_STATFS(mp, &mp->mnt_stat, td);
357		if (error)
358			break;
359
360		/* determine device name */
361		mntfrom = mp->mnt_stat.f_mntfromname;
362
363		/* determine mount point */
364		mntto = mp->mnt_stat.f_mntonname;
365		if (strncmp(mntto, lep, lep_len) == 0 &&
366		    mntto[lep_len] == '/')
367			mntto += lep_len;
368
369		/* determine fs type */
370		fstype = mp->mnt_stat.f_fstypename;
371		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
372			mntfrom = fstype = "proc";
373		else if (strcmp(fstype, "procfs") == 0)
374			continue;
375
376		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
378#define ADD_OPTION(opt, name) \
379	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
380		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
381		ADD_OPTION(MNT_NOEXEC,		"noexec");
382		ADD_OPTION(MNT_NOSUID,		"nosuid");
383		ADD_OPTION(MNT_NODEV,		"nodev");
384		ADD_OPTION(MNT_UNION,		"union");
385		ADD_OPTION(MNT_ASYNC,		"async");
386		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
387		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
388		ADD_OPTION(MNT_NOATIME,		"noatime");
389#undef ADD_OPTION
390		/* a real Linux mtab will also show NFS options */
391		sbuf_printf(sb, " 0 0\n");
392	}
393	mtx_unlock(&mountlist_mtx);
394	if (flep != NULL)
395		free(flep, M_TEMP);
396	return (error);
397}
398
399/*
400 * Filler function for proc/stat
401 */
402static int
403linprocfs_dostat(PFS_FILL_ARGS)
404{
405	sbuf_printf(sb,
406	    "cpu %ld %ld %ld %ld\n"
407	    "disk 0 0 0 0\n"
408	    "page %u %u\n"
409	    "swap %u %u\n"
410	    "intr %u\n"
411	    "ctxt %u\n"
412	    "btime %lld\n",
413	    T2J(cp_time[CP_USER]),
414	    T2J(cp_time[CP_NICE]),
415	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
416	    T2J(cp_time[CP_IDLE]),
417	    cnt.v_vnodepgsin,
418	    cnt.v_vnodepgsout,
419	    cnt.v_swappgsin,
420	    cnt.v_swappgsout,
421	    cnt.v_intr,
422	    cnt.v_swtch,
423	    (quad_t)boottime.tv_sec);
424	return (0);
425}
426
427/*
428 * Filler function for proc/uptime
429 */
430static int
431linprocfs_douptime(PFS_FILL_ARGS)
432{
433	struct timeval tv;
434
435	getmicrouptime(&tv);
436	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
437	    (quad_t)tv.tv_sec, tv.tv_usec / 10000,
438	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
439	return (0);
440}
441
442/*
443 * Filler function for proc/version
444 */
445static int
446linprocfs_doversion(PFS_FILL_ARGS)
447{
448	char osname[LINUX_MAX_UTSNAME];
449	char osrelease[LINUX_MAX_UTSNAME];
450
451	linux_get_osname(td->td_proc, osname);
452	linux_get_osrelease(td->td_proc, osrelease);
453
454	sbuf_printf(sb,
455	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
456	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
457	return (0);
458}
459
460/*
461 * Filler function for proc/loadavg
462 */
463static int
464linprocfs_doloadavg(PFS_FILL_ARGS)
465{
466	sbuf_printf(sb,
467	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
468	    (int)(averunnable.ldavg[0] / averunnable.fscale),
469	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
470	    (int)(averunnable.ldavg[1] / averunnable.fscale),
471	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
472	    (int)(averunnable.ldavg[2] / averunnable.fscale),
473	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
474	    1,				/* number of running tasks */
475	    nprocs,			/* number of tasks */
476	    lastpid			/* the last pid */
477	);
478
479	return (0);
480}
481
482/*
483 * Filler function for proc/pid/stat
484 */
485static int
486linprocfs_doprocstat(PFS_FILL_ARGS)
487{
488	struct kinfo_proc kp;
489
490	fill_kinfo_proc(p, &kp);
491	sbuf_printf(sb, "%d", p->p_pid);
492#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
493	PS_ADD("comm",		"(%s)",	p->p_comm);
494	PS_ADD("statr",		"%c",	'0'); /* XXX */
495	PROC_LOCK(p);
496	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
497	PROC_UNLOCK(p);
498	PS_ADD("pgrp",		"%d",	p->p_pgid);
499	PS_ADD("session",	"%d",	p->p_session->s_sid);
500	PS_ADD("tty",		"%d",	0); /* XXX */
501	PS_ADD("tpgid",		"%d",	0); /* XXX */
502	PS_ADD("flags",		"%u",	0); /* XXX */
503	PS_ADD("minflt",	"%u",	0); /* XXX */
504	PS_ADD("cminflt",	"%u",	0); /* XXX */
505	PS_ADD("majflt",	"%u",	0); /* XXX */
506	PS_ADD("cminflt",	"%u",	0); /* XXX */
507	PS_ADD("utime",		"%d",	0); /* XXX */
508	PS_ADD("stime",		"%d",	0); /* XXX */
509	PS_ADD("cutime",	"%d",	0); /* XXX */
510	PS_ADD("cstime",	"%d",	0); /* XXX */
511	PS_ADD("counter",	"%d",	0); /* XXX */
512	PS_ADD("priority",	"%d",	0); /* XXX */
513	PS_ADD("timeout",	"%u",	0); /* XXX */
514	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
515	PS_ADD("starttime",	"%d",	0); /* XXX */
516	PS_ADD("vsize",		"%u",	kp.ki_size);
517	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
518	PS_ADD("rlim",		"%u",	0); /* XXX */
519	PS_ADD("startcode",	"%u",	(unsigned)0);
520	PS_ADD("endcode",	"%u",	0); /* XXX */
521	PS_ADD("startstack",	"%u",	0); /* XXX */
522	PS_ADD("esp",		"%u",	0); /* XXX */
523	PS_ADD("eip",		"%u",	0); /* XXX */
524	PS_ADD("signal",	"%d",	0); /* XXX */
525	PS_ADD("blocked",	"%d",	0); /* XXX */
526	PS_ADD("sigignore",	"%d",	0); /* XXX */
527	PS_ADD("sigcatch",	"%d",	0); /* XXX */
528	PS_ADD("wchan",		"%u",	0); /* XXX */
529	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
530	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
531	PS_ADD("exitsignal",	"%d",	0); /* XXX */
532	PS_ADD("processor",	"%d",	0); /* XXX */
533#undef PS_ADD
534	sbuf_putc(sb, '\n');
535
536	return (0);
537}
538
539/*
540 * Map process state to descriptive letter. Note that this does not
541 * quite correspond to what Linux outputs, but it's close enough.
542 */
543static char *state_str[] = {
544	"? (unknown)",
545	"I (idle)",
546	"R (running)",
547	"S (sleeping)",
548	"T (stopped)",
549	"Z (zombie)",
550	"W (waiting)",
551	"M (mutex)"
552};
553
554/*
555 * Filler function for proc/pid/status
556 */
557static int
558linprocfs_doprocstatus(PFS_FILL_ARGS)
559{
560	struct kinfo_proc kp;
561	char *state;
562	segsz_t lsize;
563	int i;
564
565	mtx_lock_spin(&sched_lock);
566	if (p->p_stat > sizeof state_str / sizeof *state_str)
567		state = state_str[0];
568	else
569		state = state_str[(int)p->p_stat];
570	mtx_unlock_spin(&sched_lock);
571
572	fill_kinfo_proc(p, &kp);
573	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
574	sbuf_printf(sb, "State:\t%s\n",		state);
575
576	/*
577	 * Credentials
578	 */
579	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
580	PROC_LOCK(p);
581	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
582						p->p_pptr->p_pid : 0);
583	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
584						p->p_ucred->cr_uid,
585						p->p_ucred->cr_svuid,
586						/* FreeBSD doesn't have fsuid */
587						p->p_ucred->cr_uid);
588	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
589						p->p_ucred->cr_gid,
590						p->p_ucred->cr_svgid,
591						/* FreeBSD doesn't have fsgid */
592						p->p_ucred->cr_gid);
593	sbuf_cat(sb, "Groups:\t");
594	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
595		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
596	PROC_UNLOCK(p);
597	sbuf_putc(sb, '\n');
598
599	/*
600	 * Memory
601	 *
602	 * While our approximation of VmLib may not be accurate (I
603	 * don't know of a simple way to verify it, and I'm not sure
604	 * it has much meaning anyway), I believe it's good enough.
605	 *
606	 * The same code that could (I think) accurately compute VmLib
607	 * could also compute VmLck, but I don't really care enough to
608	 * implement it. Submissions are welcome.
609	 */
610	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
611	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
612	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
613	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
614	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
615	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
616	lsize = B2P(kp.ki_size) - kp.ki_dsize -
617	    kp.ki_ssize - kp.ki_tsize - 1;
618	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
619
620	/*
621	 * Signal masks
622	 *
623	 * We support up to 128 signals, while Linux supports 32,
624	 * but we only define 32 (the same 32 as Linux, to boot), so
625	 * just show the lower 32 bits of each mask. XXX hack.
626	 *
627	 * NB: on certain platforms (Sparc at least) Linux actually
628	 * supports 64 signals, but this code is a long way from
629	 * running on anything but i386, so ignore that for now.
630	 */
631	PROC_LOCK(p);
632	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
633	/*
634	 * I can't seem to find out where the signal mask is in
635	 * relation to struct proc, so SigBlk is left unimplemented.
636	 */
637	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
638	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
639	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
640	PROC_UNLOCK(p);
641
642	/*
643	 * Linux also prints the capability masks, but we don't have
644	 * capabilities yet, and when we do get them they're likely to
645	 * be meaningless to Linux programs, so we lie. XXX
646	 */
647	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
648	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
649	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
650
651	return (0);
652}
653
654/*
655 * Filler function for proc/self
656 */
657static int
658linprocfs_doselflink(PFS_FILL_ARGS)
659{
660	sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid);
661	return (0);
662}
663
664/*
665 * Filler function for proc/pid/cmdline
666 */
667static int
668linprocfs_doproccmdline(PFS_FILL_ARGS)
669{
670	struct ps_strings pstr;
671	int error, i;
672
673	/*
674	 * If we are using the ps/cmdline caching, use that.  Otherwise
675	 * revert back to the old way which only implements full cmdline
676	 * for the currept process and just p->p_comm for all other
677	 * processes.
678	 * Note that if the argv is no longer available, we deliberately
679	 * don't fall back on p->p_comm or return an error: the authentic
680	 * Linux behaviour is to return zero-length in this case.
681	 */
682
683	if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) {
684		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
685	} else if (p != td->td_proc) {
686		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
687	} else {
688		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
689		if (error)
690			return (error);
691		for (i = 0; i < pstr.ps_nargvstr; i++) {
692			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
693			sbuf_printf(sb, "%c", '\0');
694		}
695	}
696
697	return (0);
698}
699
700/*
701 * Filler function for proc/pid/exe
702 */
703static int
704linprocfs_doprocexe(PFS_FILL_ARGS)
705{
706	char *fullpath = "unknown";
707	char *freepath = NULL;
708
709	vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath);
710	sbuf_printf(sb, "%s", fullpath);
711	if (freepath)
712		free(freepath, M_TEMP);
713	return (0);
714}
715
716/*
717 * Filler function for proc/net/dev
718 */
719static int
720linprocfs_donetdev(PFS_FILL_ARGS)
721{
722	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
723	struct ifnet *ifp;
724
725	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
726	    "Inter-", "   Receive", "  Transmit", " face",
727	    "bytes    packets errs drop fifo frame compressed",
728	    "bytes    packets errs drop fifo frame compressed");
729
730	TAILQ_FOREACH(ifp, &ifnet, if_link) {
731		linux_ifname(ifp, ifname, sizeof ifname);
732			sbuf_printf(sb, "%6.6s:", ifname);
733		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
734		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
735		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
736		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
737	}
738
739	return (0);
740}
741
742#if 0
743extern struct cdevsw *cdevsw[];
744
745/*
746 * Filler function for proc/devices
747 */
748static int
749linprocfs_dodevices(PFS_FILL_ARGS)
750{
751	int i;
752
753	sbuf_printf(sb, "Character devices:\n");
754
755	for (i = 0; i < NUMCDEVSW; i++)
756		if (cdevsw[i] != NULL)
757			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
758
759	sbuf_printf(sb, "\nBlock devices:\n");
760
761	return (0);
762}
763#endif
764
765/*
766 * Filler function for proc/cmdline
767 */
768static int
769linprocfs_docmdline(PFS_FILL_ARGS)
770{
771	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
772	sbuf_printf(sb, " ro root=302\n");
773	return (0);
774}
775
776#if 0
777/*
778 * Filler function for proc/modules
779 */
780static int
781linprocfs_domodules(PFS_FILL_ARGS)
782{
783	struct linker_file *lf;
784
785	TAILQ_FOREACH(lf, &linker_files, link) {
786		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
787		    (unsigned long)lf->size, lf->refs);
788	}
789	return (0);
790}
791#endif
792
793/*
794 * Constructor
795 */
796static int
797linprocfs_init(PFS_INIT_ARGS)
798{
799	struct pfs_node *root;
800	struct pfs_node *dir;
801
802	root = pi->pi_root;
803
804#define PFS_CREATE_FILE(name) \
805	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
806	PFS_CREATE_FILE(cmdline);
807	PFS_CREATE_FILE(cpuinfo);
808#if 0
809	PFS_CREATE_FILE(devices);
810#endif
811	PFS_CREATE_FILE(loadavg);
812	PFS_CREATE_FILE(meminfo);
813#if 0
814	PFS_CREATE_FILE(modules);
815#endif
816	PFS_CREATE_FILE(mtab);
817	PFS_CREATE_FILE(stat);
818	PFS_CREATE_FILE(uptime);
819	PFS_CREATE_FILE(version);
820#undef PFS_CREATE_FILE
821	pfs_create_link(root, "self", &linprocfs_doselflink,
822	    NULL, NULL, 0);
823
824	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
825	pfs_create_file(dir, "dev", &linprocfs_donetdev,
826	    NULL, NULL, PFS_RD);
827
828	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
829	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
830	    NULL, NULL, PFS_RD);
831	pfs_create_link(dir, "exe", &linprocfs_doprocexe,
832	    NULL, NULL, 0);
833#if 0
834	pfs_create_file(dir, "mem", &procfs_doprocmem,
835	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
836#endif
837	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
838	    NULL, NULL, PFS_RD);
839	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
840	    NULL, NULL, PFS_RD);
841
842	return (0);
843}
844
845/*
846 * Destructor
847 */
848static int
849linprocfs_uninit(PFS_INIT_ARGS)
850{
851
852	/* nothing to do, pseudofs will GC */
853	return (0);
854}
855
856PSEUDOFS(linprocfs, 1);
857MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
858MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
859