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