linprocfs.c revision 91334
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 91334 2002-02-26 23:38:34Z julian $
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	const char *lep;
343	char *dlep, *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, &dlep, &flep) == -1)
351		lep = linux_emul_path;
352	else
353		lep = dlep;
354	lep_len = strlen(lep);
355
356	mtx_lock(&mountlist_mtx);
357	error = 0;
358	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
359		error = VFS_STATFS(mp, &mp->mnt_stat, td);
360		if (error)
361			break;
362
363		/* determine device name */
364		mntfrom = mp->mnt_stat.f_mntfromname;
365
366		/* determine mount point */
367		mntto = mp->mnt_stat.f_mntonname;
368		if (strncmp(mntto, lep, lep_len) == 0 &&
369		    mntto[lep_len] == '/')
370			mntto += lep_len;
371
372		/* determine fs type */
373		fstype = mp->mnt_stat.f_fstypename;
374		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
375			mntfrom = fstype = "proc";
376		else if (strcmp(fstype, "procfs") == 0)
377			continue;
378
379		sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
380		    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
381#define ADD_OPTION(opt, name) \
382	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
383		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
384		ADD_OPTION(MNT_NOEXEC,		"noexec");
385		ADD_OPTION(MNT_NOSUID,		"nosuid");
386		ADD_OPTION(MNT_NODEV,		"nodev");
387		ADD_OPTION(MNT_UNION,		"union");
388		ADD_OPTION(MNT_ASYNC,		"async");
389		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
390		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
391		ADD_OPTION(MNT_NOATIME,		"noatime");
392#undef ADD_OPTION
393		/* a real Linux mtab will also show NFS options */
394		sbuf_printf(sb, " 0 0\n");
395	}
396	mtx_unlock(&mountlist_mtx);
397	if (flep != NULL)
398		free(flep, M_TEMP);
399	return (error);
400}
401
402/*
403 * Filler function for proc/stat
404 */
405static int
406linprocfs_dostat(PFS_FILL_ARGS)
407{
408	sbuf_printf(sb,
409	    "cpu %ld %ld %ld %ld\n"
410	    "disk 0 0 0 0\n"
411	    "page %u %u\n"
412	    "swap %u %u\n"
413	    "intr %u\n"
414	    "ctxt %u\n"
415	    "btime %lld\n",
416	    T2J(cp_time[CP_USER]),
417	    T2J(cp_time[CP_NICE]),
418	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
419	    T2J(cp_time[CP_IDLE]),
420	    cnt.v_vnodepgsin,
421	    cnt.v_vnodepgsout,
422	    cnt.v_swappgsin,
423	    cnt.v_swappgsout,
424	    cnt.v_intr,
425	    cnt.v_swtch,
426	    (quad_t)boottime.tv_sec);
427	return (0);
428}
429
430/*
431 * Filler function for proc/uptime
432 */
433static int
434linprocfs_douptime(PFS_FILL_ARGS)
435{
436	struct timeval tv;
437
438	getmicrouptime(&tv);
439	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
440	    (quad_t)tv.tv_sec, tv.tv_usec / 10000,
441	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
442	return (0);
443}
444
445/*
446 * Filler function for proc/version
447 */
448static int
449linprocfs_doversion(PFS_FILL_ARGS)
450{
451	char osname[LINUX_MAX_UTSNAME];
452	char osrelease[LINUX_MAX_UTSNAME];
453
454	linux_get_osname(td->td_proc, osname);
455	linux_get_osrelease(td->td_proc, osrelease);
456
457	sbuf_printf(sb,
458	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
459	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
460	return (0);
461}
462
463/*
464 * Filler function for proc/loadavg
465 */
466static int
467linprocfs_doloadavg(PFS_FILL_ARGS)
468{
469	sbuf_printf(sb,
470	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
471	    (int)(averunnable.ldavg[0] / averunnable.fscale),
472	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
473	    (int)(averunnable.ldavg[1] / averunnable.fscale),
474	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
475	    (int)(averunnable.ldavg[2] / averunnable.fscale),
476	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
477	    1,				/* number of running tasks */
478	    nprocs,			/* number of tasks */
479	    lastpid			/* the last pid */
480	);
481
482	return (0);
483}
484
485/*
486 * Filler function for proc/pid/stat
487 */
488static int
489linprocfs_doprocstat(PFS_FILL_ARGS)
490{
491	struct kinfo_proc kp;
492
493	fill_kinfo_proc(p, &kp);
494	sbuf_printf(sb, "%d", p->p_pid);
495#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
496	PS_ADD("comm",		"(%s)",	p->p_comm);
497	PS_ADD("statr",		"%c",	'0'); /* XXX */
498	PROC_LOCK(p);
499	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
500	PS_ADD("pgrp",		"%d",	p->p_pgid);
501	PS_ADD("session",	"%d",	p->p_session->s_sid);
502	PROC_UNLOCK(p);
503	PS_ADD("tty",		"%d",	0); /* XXX */
504	PS_ADD("tpgid",		"%d",	0); /* XXX */
505	PS_ADD("flags",		"%u",	0); /* XXX */
506	PS_ADD("minflt",	"%u",	0); /* XXX */
507	PS_ADD("cminflt",	"%u",	0); /* XXX */
508	PS_ADD("majflt",	"%u",	0); /* XXX */
509	PS_ADD("cminflt",	"%u",	0); /* XXX */
510	PS_ADD("utime",		"%d",	0); /* XXX */
511	PS_ADD("stime",		"%d",	0); /* XXX */
512	PS_ADD("cutime",	"%d",	0); /* XXX */
513	PS_ADD("cstime",	"%d",	0); /* XXX */
514	PS_ADD("counter",	"%d",	0); /* XXX */
515	PS_ADD("priority",	"%d",	0); /* XXX */
516	PS_ADD("timeout",	"%u",	0); /* XXX */
517	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
518	PS_ADD("starttime",	"%d",	0); /* XXX */
519	PS_ADD("vsize",		"%u",	kp.ki_size);
520	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
521	PS_ADD("rlim",		"%u",	0); /* XXX */
522	PS_ADD("startcode",	"%u",	(unsigned)0);
523	PS_ADD("endcode",	"%u",	0); /* XXX */
524	PS_ADD("startstack",	"%u",	0); /* XXX */
525	PS_ADD("esp",		"%u",	0); /* XXX */
526	PS_ADD("eip",		"%u",	0); /* XXX */
527	PS_ADD("signal",	"%d",	0); /* XXX */
528	PS_ADD("blocked",	"%d",	0); /* XXX */
529	PS_ADD("sigignore",	"%d",	0); /* XXX */
530	PS_ADD("sigcatch",	"%d",	0); /* XXX */
531	PS_ADD("wchan",		"%u",	0); /* XXX */
532	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
533	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
534	PS_ADD("exitsignal",	"%d",	0); /* XXX */
535	PS_ADD("processor",	"%d",	0); /* XXX */
536#undef PS_ADD
537	sbuf_putc(sb, '\n');
538
539	return (0);
540}
541
542/*
543 * Map process state to descriptive letter. Note that this does not
544 * quite correspond to what Linux outputs, but it's close enough.
545 */
546static char *state_str[] = {
547	"? (unknown)",
548	"I (idle)",
549	"R (running)",
550	"S (sleeping)",
551	"T (stopped)",
552	"Z (zombie)",
553	"W (waiting)",
554	"M (mutex)"
555};
556
557/*
558 * Filler function for proc/pid/status
559 */
560static int
561linprocfs_doprocstatus(PFS_FILL_ARGS)
562{
563	struct kinfo_proc kp;
564	char *state;
565	segsz_t lsize;
566	int i;
567
568	mtx_lock_spin(&sched_lock);
569	if (p->p_stat > sizeof state_str / sizeof *state_str)
570		state = state_str[0];
571	else
572		state = state_str[(int)p->p_stat];
573	mtx_unlock_spin(&sched_lock);
574
575	fill_kinfo_proc(p, &kp);
576	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
577	sbuf_printf(sb, "State:\t%s\n",		state);
578
579	/*
580	 * Credentials
581	 */
582	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
583	PROC_LOCK(p);
584	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
585						p->p_pptr->p_pid : 0);
586	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
587						p->p_ucred->cr_uid,
588						p->p_ucred->cr_svuid,
589						/* FreeBSD doesn't have fsuid */
590						p->p_ucred->cr_uid);
591	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
592						p->p_ucred->cr_gid,
593						p->p_ucred->cr_svgid,
594						/* FreeBSD doesn't have fsgid */
595						p->p_ucred->cr_gid);
596	sbuf_cat(sb, "Groups:\t");
597	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
598		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
599	PROC_UNLOCK(p);
600	sbuf_putc(sb, '\n');
601
602	/*
603	 * Memory
604	 *
605	 * While our approximation of VmLib may not be accurate (I
606	 * don't know of a simple way to verify it, and I'm not sure
607	 * it has much meaning anyway), I believe it's good enough.
608	 *
609	 * The same code that could (I think) accurately compute VmLib
610	 * could also compute VmLck, but I don't really care enough to
611	 * implement it. Submissions are welcome.
612	 */
613	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
614	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
615	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
616	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
617	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
618	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
619	lsize = B2P(kp.ki_size) - kp.ki_dsize -
620	    kp.ki_ssize - kp.ki_tsize - 1;
621	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
622
623	/*
624	 * Signal masks
625	 *
626	 * We support up to 128 signals, while Linux supports 32,
627	 * but we only define 32 (the same 32 as Linux, to boot), so
628	 * just show the lower 32 bits of each mask. XXX hack.
629	 *
630	 * NB: on certain platforms (Sparc at least) Linux actually
631	 * supports 64 signals, but this code is a long way from
632	 * running on anything but i386, so ignore that for now.
633	 */
634	PROC_LOCK(p);
635	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
636	/*
637	 * I can't seem to find out where the signal mask is in
638	 * relation to struct proc, so SigBlk is left unimplemented.
639	 */
640	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
641	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
642	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
643	PROC_UNLOCK(p);
644
645	/*
646	 * Linux also prints the capability masks, but we don't have
647	 * capabilities yet, and when we do get them they're likely to
648	 * be meaningless to Linux programs, so we lie. XXX
649	 */
650	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
651	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
652	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
653
654	return (0);
655}
656
657/*
658 * Filler function for proc/pid/cmdline
659 */
660static int
661linprocfs_doproccmdline(PFS_FILL_ARGS)
662{
663	struct ps_strings pstr;
664	int error, i;
665
666	/*
667	 * If we are using the ps/cmdline caching, use that.  Otherwise
668	 * revert back to the old way which only implements full cmdline
669	 * for the currept process and just p->p_comm for all other
670	 * processes.
671	 * Note that if the argv is no longer available, we deliberately
672	 * don't fall back on p->p_comm or return an error: the authentic
673	 * Linux behaviour is to return zero-length in this case.
674	 */
675
676	if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) {
677		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
678	} else if (p != td->td_proc) {
679		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
680	} else {
681		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
682		if (error)
683			return (error);
684		for (i = 0; i < pstr.ps_nargvstr; i++) {
685			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
686			sbuf_printf(sb, "%c", '\0');
687		}
688	}
689
690	return (0);
691}
692
693/*
694 * Filler function for proc/net/dev
695 */
696static int
697linprocfs_donetdev(PFS_FILL_ARGS)
698{
699	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
700	struct ifnet *ifp;
701
702	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
703	    "Inter-", "   Receive", "  Transmit", " face",
704	    "bytes    packets errs drop fifo frame compressed",
705	    "bytes    packets errs drop fifo frame compressed");
706
707	TAILQ_FOREACH(ifp, &ifnet, if_link) {
708		linux_ifname(ifp, ifname, sizeof ifname);
709			sbuf_printf(sb, "%6.6s:", ifname);
710		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
711		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
712		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
713		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
714	}
715
716	return (0);
717}
718
719#if 0
720extern struct cdevsw *cdevsw[];
721
722/*
723 * Filler function for proc/devices
724 */
725static int
726linprocfs_dodevices(PFS_FILL_ARGS)
727{
728	int i;
729
730	sbuf_printf(sb, "Character devices:\n");
731
732	for (i = 0; i < NUMCDEVSW; i++)
733		if (cdevsw[i] != NULL)
734			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
735
736	sbuf_printf(sb, "\nBlock devices:\n");
737
738	return (0);
739}
740#endif
741
742/*
743 * Filler function for proc/cmdline
744 */
745static int
746linprocfs_docmdline(PFS_FILL_ARGS)
747{
748	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
749	sbuf_printf(sb, " ro root=302\n");
750	return (0);
751}
752
753#if 0
754/*
755 * Filler function for proc/modules
756 */
757static int
758linprocfs_domodules(PFS_FILL_ARGS)
759{
760	struct linker_file *lf;
761
762	TAILQ_FOREACH(lf, &linker_files, link) {
763		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
764		    (unsigned long)lf->size, lf->refs);
765	}
766	return (0);
767}
768#endif
769
770/*
771 * Constructor
772 */
773static int
774linprocfs_init(PFS_INIT_ARGS)
775{
776	struct pfs_node *root;
777	struct pfs_node *dir;
778
779	root = pi->pi_root;
780
781#define PFS_CREATE_FILE(name) \
782	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
783	PFS_CREATE_FILE(cmdline);
784	PFS_CREATE_FILE(cpuinfo);
785#if 0
786	PFS_CREATE_FILE(devices);
787#endif
788	PFS_CREATE_FILE(loadavg);
789	PFS_CREATE_FILE(meminfo);
790#if 0
791	PFS_CREATE_FILE(modules);
792#endif
793	PFS_CREATE_FILE(mtab);
794	PFS_CREATE_FILE(stat);
795	PFS_CREATE_FILE(uptime);
796	PFS_CREATE_FILE(version);
797#undef PFS_CREATE_FILE
798	pfs_create_link(root, "self", &procfs_docurproc,
799	    NULL, NULL, 0);
800
801	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
802	pfs_create_file(dir, "dev", &linprocfs_donetdev,
803	    NULL, NULL, PFS_RD);
804
805	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
806	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
807	    NULL, NULL, PFS_RD);
808	pfs_create_link(dir, "exe", &procfs_doprocfile,
809	    NULL, &procfs_notsystem, 0);
810	pfs_create_file(dir, "mem", &procfs_doprocmem,
811	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
812	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
813	    NULL, NULL, PFS_RD);
814	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
815	    NULL, NULL, PFS_RD);
816
817	return (0);
818}
819
820/*
821 * Destructor
822 */
823static int
824linprocfs_uninit(PFS_INIT_ARGS)
825{
826
827	/* nothing to do, pseudofs will GC */
828	return (0);
829}
830
831PSEUDOFS(linprocfs, 1);
832MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
833MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
834