linprocfs.c revision 78116
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 78116 2001-06-11 23:00:35Z des $
42 */
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/blist.h>
47#include <sys/conf.h>
48#include <sys/dkstat.h>
49#include <sys/jail.h>
50#include <sys/kernel.h>
51#include <sys/lock.h>
52#include <sys/malloc.h>
53#include <sys/mount.h>
54#include <sys/mutex.h>
55#include <sys/proc.h>
56#include <sys/resourcevar.h>
57#include <sys/sbuf.h>
58#include <sys/sysctl.h>
59#include <sys/tty.h>
60#include <sys/vnode.h>
61
62#include <vm/vm.h>
63#include <vm/pmap.h>
64#include <vm/vm_map.h>
65#include <vm/vm_param.h>
66#include <vm/vm_object.h>
67#include <vm/vm_zone.h>
68#include <vm/swap_pager.h>
69
70#include <sys/exec.h>
71#include <sys/user.h>
72#include <sys/vmmeter.h>
73
74#include <machine/clock.h>
75
76#ifdef __alpha__
77#include <machine/alpha_cpu.h>
78#include <machine/cpuconf.h>
79#include <machine/rpb.h>
80extern int ncpus;
81#endif /* __alpha__ */
82
83#ifdef __i386__
84#include <machine/cputypes.h>
85#include <machine/md_var.h>
86#endif /* __i386__ */
87
88#include <sys/socket.h>
89#include <net/if.h>
90
91#include <compat/linux/linux_mib.h>
92#include <fs/pseudofs/pseudofs.h>
93
94extern struct cdevsw *cdevsw[];
95
96/*
97 * Various conversion macros
98 */
99#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
100#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
101#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
102#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
103#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
104#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
105
106/*
107 * Filler function for proc/meminfo
108 */
109static int
110linprocfs_domeminfo(PFS_FILL_ARGS)
111{
112	unsigned long memtotal;		/* total memory in bytes */
113	unsigned long memused;		/* used memory in bytes */
114	unsigned long memfree;		/* free memory in bytes */
115	unsigned long memshared;	/* shared memory ??? */
116	unsigned long buffers, cached;	/* buffer / cache memory ??? */
117	u_quad_t swaptotal;		/* total swap space in bytes */
118	u_quad_t swapused;		/* used swap space in bytes */
119	u_quad_t swapfree;		/* free swap space in bytes */
120	vm_object_t object;
121
122	memtotal = physmem * PAGE_SIZE;
123	/*
124	 * The correct thing here would be:
125	 *
126	memfree = cnt.v_free_count * PAGE_SIZE;
127	memused = memtotal - memfree;
128	 *
129	 * but it might mislead linux binaries into thinking there
130	 * is very little memory left, so we cheat and tell them that
131	 * all memory that isn't wired down is free.
132	 */
133	memused = cnt.v_wire_count * PAGE_SIZE;
134	memfree = memtotal - memused;
135	if (swapblist == NULL) {
136		swaptotal = 0;
137		swapfree = 0;
138	} else {
139		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
140		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
141	}
142	swapused = swaptotal - swapfree;
143	memshared = 0;
144	TAILQ_FOREACH(object, &vm_object_list, object_list)
145		if (object->shadow_count > 1)
146			memshared += object->resident_page_count;
147	memshared *= PAGE_SIZE;
148	/*
149	 * We'd love to be able to write:
150	 *
151	buffers = bufspace;
152	 *
153	 * but bufspace is internal to vfs_bio.c and we don't feel
154	 * like unstaticizing it just for linprocfs's sake.
155	 */
156	buffers = 0;
157	cached = cnt.v_cache_count * PAGE_SIZE;
158
159	sbuf_printf(sb,
160	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
161	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
162	    "Swap: %llu %llu %llu\n"
163	    "MemTotal: %9lu kB\n"
164	    "MemFree:  %9lu kB\n"
165	    "MemShared:%9lu kB\n"
166	    "Buffers:  %9lu kB\n"
167	    "Cached:   %9lu kB\n"
168	    "SwapTotal:%9llu kB\n"
169	    "SwapFree: %9llu kB\n",
170	    memtotal, memused, memfree, memshared, buffers, cached,
171	    swaptotal, swapused, swapfree,
172	    B2K(memtotal), B2K(memfree),
173	    B2K(memshared), B2K(buffers), B2K(cached),
174	    B2K(swaptotal), B2K(swapfree));
175
176	return (0);
177}
178
179#ifdef __alpha__
180/*
181 * Filler function for proc/cpuinfo (Alpha version)
182 */
183static int
184linprocfs_docpuinfo(PFS_FILL_ARGS)
185{
186	u_int64_t type, major;
187	struct pcs *pcsp;
188	const char *model, *sysname;
189
190	static const char *cpuname[] = {
191		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
192		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
193	};
194
195	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
196	type = pcsp->pcs_proc_type;
197	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
198	if (major < sizeof(cpuname)/sizeof(char *)) {
199		model = cpuname[major - 1];
200	} else {
201		model = "unknown";
202	}
203
204	sysname = alpha_dsr_sysname();
205
206	sbuf_printf(sb,
207	    "cpu\t\t\t: Alpha\n"
208	    "cpu model\t\t: %s\n"
209	    "cpu variation\t\t: %ld\n"
210	    "cpu revision\t\t: %ld\n"
211	    "cpu serial number\t: %s\n"
212	    "system type\t\t: %s\n"
213	    "system variation\t: %s\n"
214	    "system revision\t\t: %ld\n"
215	    "system serial number\t: %s\n"
216	    "cycle frequency [Hz]\t: %lu\n"
217	    "timer frequency [Hz]\t: %lu\n"
218	    "page size [bytes]\t: %ld\n"
219	    "phys. address bits\t: %ld\n"
220	    "max. addr. space #\t: %ld\n"
221	    "BogoMIPS\t\t: %lu.%02lu\n"
222	    "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
223	    "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
224	    "platform string\t\t: %s\n"
225	    "cpus detected\t\t: %d\n"
226	    ,
227	    model,
228	    pcsp->pcs_proc_var,
229	    *(int *)hwrpb->rpb_revision,
230	    " ",
231	    " ",
232	    "0",
233	    0,
234	    " ",
235	    hwrpb->rpb_cc_freq,
236	    hz,
237	    hwrpb->rpb_page_size,
238	    hwrpb->rpb_phys_addr_size,
239	    hwrpb->rpb_max_asn,
240	    0, 0,
241	    0, 0, 0,
242	    0, 0, 0,
243	    sysname,
244	    ncpus);
245	return (0);
246}
247#endif /* __alpha__ */
248
249#ifdef __i386__
250/*
251 * Filler function for proc/cpuinfo (i386 version)
252 */
253static int
254linprocfs_docpuinfo(PFS_FILL_ARGS)
255{
256	int class, i, fqmhz, fqkhz;
257
258	/*
259	 * We default the flags to include all non-conflicting flags,
260	 * and the Intel versions of conflicting flags.
261	 */
262	static char *flags[] = {
263		"fpu",	    "vme",     "de",	   "pse",      "tsc",
264		"msr",	    "pae",     "mce",	   "cx8",      "apic",
265		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
266		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
267		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
268		"xmm",	    "b26",     "b27",	   "b28",      "b29",
269		"3dnowext", "3dnow"
270	};
271
272	switch (cpu_class) {
273	case CPUCLASS_286:
274		class = 2;
275		break;
276	case CPUCLASS_386:
277		class = 3;
278		break;
279	case CPUCLASS_486:
280		class = 4;
281		break;
282	case CPUCLASS_586:
283		class = 5;
284		break;
285	case CPUCLASS_686:
286		class = 6;
287		break;
288	default:
289		class = 0;
290		break;
291	}
292
293	sbuf_printf(sb,
294	    "processor\t: %d\n"
295	    "vendor_id\t: %.20s\n"
296	    "cpu family\t: %d\n"
297	    "model\t\t: %d\n"
298	    "stepping\t: %d\n",
299	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
300
301	sbuf_cat(sb,
302	    "flags\t\t:");
303
304	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
305		flags[16] = "fcmov";
306	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
307		flags[24] = "cxmmx";
308	}
309
310	for (i = 0; i < 32; i++)
311		if (cpu_feature & (1 << i))
312			sbuf_printf(sb, " %s", flags[i]);
313	sbuf_cat(sb, "\n");
314	if (class >= 5) {
315		fqmhz = (tsc_freq + 4999) / 1000000;
316		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
317		sbuf_printf(sb,
318		    "cpu MHz\t\t: %d.%02d\n"
319		    "bogomips\t: %d.%02d\n",
320		    fqmhz, fqkhz, fqmhz, fqkhz);
321	}
322
323	return (0);
324}
325#endif /* __i386__ */
326
327/*
328 * Filler function for proc/stat
329 */
330static int
331linprocfs_dostat(PFS_FILL_ARGS)
332{
333	sbuf_printf(sb,
334	    "cpu %ld %ld %ld %ld\n"
335	    "disk 0 0 0 0\n"
336	    "page %u %u\n"
337	    "swap %u %u\n"
338	    "intr %u\n"
339	    "ctxt %u\n"
340	    "btime %ld\n",
341	    T2J(cp_time[CP_USER]),
342	    T2J(cp_time[CP_NICE]),
343	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
344	    T2J(cp_time[CP_IDLE]),
345	    cnt.v_vnodepgsin,
346	    cnt.v_vnodepgsout,
347	    cnt.v_swappgsin,
348	    cnt.v_swappgsout,
349	    cnt.v_intr,
350	    cnt.v_swtch,
351	    boottime.tv_sec);
352	return (0);
353}
354
355/*
356 * Filler function for proc/uptime
357 */
358static int
359linprocfs_douptime(PFS_FILL_ARGS)
360{
361	struct timeval tv;
362
363	getmicrouptime(&tv);
364	sbuf_printf(sb, "%ld.%02ld %ld.%02ld\n",
365	    tv.tv_sec, tv.tv_usec / 10000,
366	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
367	return (0);
368}
369
370/*
371 * Filler function for proc/version
372 */
373static int
374linprocfs_doversion(PFS_FILL_ARGS)
375{
376	sbuf_printf(sb,
377	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
378	    " #4 Sun Dec 18 04:30:00 CET 1977\n",
379	    linux_get_osname(curp),
380	    linux_get_osrelease(curp));
381	return (0);
382}
383
384/*
385 * Filler function for proc/loadavg
386 */
387static int
388linprocfs_doloadavg(PFS_FILL_ARGS)
389{
390	sbuf_printf(sb,
391	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
392	    (int)(averunnable.ldavg[0] / averunnable.fscale),
393	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
394	    (int)(averunnable.ldavg[1] / averunnable.fscale),
395	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
396	    (int)(averunnable.ldavg[2] / averunnable.fscale),
397	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
398	    1,				/* number of running tasks */
399	    nprocs,			/* number of tasks */
400	    lastpid			/* the last pid */
401	);
402
403	return (0);
404}
405
406/*
407 * Filler function for proc/pid/stat
408 */
409static int
410linprocfs_doprocstat(PFS_FILL_ARGS)
411{
412	struct kinfo_proc kp;
413
414	fill_kinfo_proc(p, &kp);
415	sbuf_printf(sb, "%d", p->p_pid);
416#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
417	PS_ADD("comm",		"(%s)",	p->p_comm);
418	PS_ADD("statr",		"%c",	'0'); /* XXX */
419	PROC_LOCK(p);
420	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
421	PROC_UNLOCK(p);
422	PS_ADD("pgrp",		"%d",	p->p_pgid);
423	PS_ADD("session",	"%d",	p->p_session->s_sid);
424	PS_ADD("tty",		"%d",	0); /* XXX */
425	PS_ADD("tpgid",		"%d",	0); /* XXX */
426	PS_ADD("flags",		"%u",	0); /* XXX */
427	PS_ADD("minflt",	"%u",	0); /* XXX */
428	PS_ADD("cminflt",	"%u",	0); /* XXX */
429	PS_ADD("majflt",	"%u",	0); /* XXX */
430	PS_ADD("cminflt",	"%u",	0); /* XXX */
431	PS_ADD("utime",		"%d",	0); /* XXX */
432	PS_ADD("stime",		"%d",	0); /* XXX */
433	PS_ADD("cutime",	"%d",	0); /* XXX */
434	PS_ADD("cstime",	"%d",	0); /* XXX */
435	PS_ADD("counter",	"%d",	0); /* XXX */
436	PS_ADD("priority",	"%d",	0); /* XXX */
437	PS_ADD("timeout",	"%u",	0); /* XXX */
438	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
439	PS_ADD("starttime",	"%d",	0); /* XXX */
440	PS_ADD("vsize",		"%u",	kp.ki_size);
441	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
442	PS_ADD("rlim",		"%u",	0); /* XXX */
443	PS_ADD("startcode",	"%u",	(unsigned)0);
444	PS_ADD("endcode",	"%u",	0); /* XXX */
445	PS_ADD("startstack",	"%u",	0); /* XXX */
446	PS_ADD("esp",		"%u",	0); /* XXX */
447	PS_ADD("eip",		"%u",	0); /* XXX */
448	PS_ADD("signal",	"%d",	0); /* XXX */
449	PS_ADD("blocked",	"%d",	0); /* XXX */
450	PS_ADD("sigignore",	"%d",	0); /* XXX */
451	PS_ADD("sigcatch",	"%d",	0); /* XXX */
452	PS_ADD("wchan",		"%u",	0); /* XXX */
453	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
454	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
455	PS_ADD("exitsignal",	"%d",	0); /* XXX */
456	PS_ADD("processor",	"%d",	0); /* XXX */
457#undef PS_ADD
458	sbuf_putc(sb, '\n');
459
460	return (0);
461}
462
463/*
464 * Map process state to descriptive letter. Note that this does not
465 * quite correspond to what Linux outputs, but it's close enough.
466 */
467static char *state_str[] = {
468	"? (unknown)",
469	"I (idle)",
470	"R (running)",
471	"S (sleeping)",
472	"T (stopped)",
473	"Z (zombie)",
474	"W (waiting)",
475	"M (mutex)"
476};
477
478/*
479 * Filler function for proc/pid/status
480 */
481static int
482linprocfs_doprocstatus(PFS_FILL_ARGS)
483{
484	struct kinfo_proc kp;
485	char *state;
486	segsz_t lsize;
487	int i;
488
489	mtx_lock_spin(&sched_lock);
490	if (p->p_stat > sizeof state_str / sizeof *state_str)
491		state = state_str[0];
492	else
493		state = state_str[(int)p->p_stat];
494	mtx_unlock_spin(&sched_lock);
495
496	fill_kinfo_proc(p, &kp);
497	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
498	sbuf_printf(sb, "State:\t%s\n",		state);
499
500	/*
501	 * Credentials
502	 */
503	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
504	PROC_LOCK(p);
505	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
506						p->p_pptr->p_pid : 0);
507	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
508						p->p_ucred->cr_uid,
509						p->p_ucred->cr_svuid,
510						/* FreeBSD doesn't have fsuid */
511						p->p_ucred->cr_uid);
512	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
513						p->p_ucred->cr_gid,
514						p->p_ucred->cr_svgid,
515						/* FreeBSD doesn't have fsgid */
516						p->p_ucred->cr_gid);
517	sbuf_cat(sb, "Groups:\t");
518	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
519		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
520	PROC_UNLOCK(p);
521	sbuf_putc(sb, '\n');
522
523	/*
524	 * Memory
525	 *
526	 * While our approximation of VmLib may not be accurate (I
527	 * don't know of a simple way to verify it, and I'm not sure
528	 * it has much meaning anyway), I believe it's good enough.
529	 *
530	 * The same code that could (I think) accurately compute VmLib
531	 * could also compute VmLck, but I don't really care enough to
532	 * implement it. Submissions are welcome.
533	 */
534	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
535	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
536	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
537	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
538	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
539	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
540	lsize = B2P(kp.ki_size) - kp.ki_dsize -
541	    kp.ki_ssize - kp.ki_tsize - 1;
542	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
543
544	/*
545	 * Signal masks
546	 *
547	 * We support up to 128 signals, while Linux supports 32,
548	 * but we only define 32 (the same 32 as Linux, to boot), so
549	 * just show the lower 32 bits of each mask. XXX hack.
550	 *
551	 * NB: on certain platforms (Sparc at least) Linux actually
552	 * supports 64 signals, but this code is a long way from
553	 * running on anything but i386, so ignore that for now.
554	 */
555	PROC_LOCK(p);
556	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
557	/*
558	 * I can't seem to find out where the signal mask is in
559	 * relation to struct proc, so SigBlk is left unimplemented.
560	 */
561	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
562	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
563	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
564	PROC_UNLOCK(p);
565
566	/*
567	 * Linux also prints the capability masks, but we don't have
568	 * capabilities yet, and when we do get them they're likely to
569	 * be meaningless to Linux programs, so we lie. XXX
570	 */
571	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
572	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
573	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
574
575	return (0);
576}
577
578/*
579 * Filler function for proc/self
580 */
581static int
582linprocfs_doselflink(PFS_FILL_ARGS)
583{
584	sbuf_printf(sb, "%ld", (long)curp->p_pid);
585	return (0);
586}
587
588/*
589 * Filler function for proc/pid/cmdline
590 */
591static int
592linprocfs_doproccmdline(PFS_FILL_ARGS)
593{
594	struct ps_strings pstr;
595	int error, i;
596
597	/*
598	 * If we are using the ps/cmdline caching, use that.  Otherwise
599	 * revert back to the old way which only implements full cmdline
600	 * for the currept process and just p->p_comm for all other
601	 * processes.
602	 * Note that if the argv is no longer available, we deliberately
603	 * don't fall back on p->p_comm or return an error: the authentic
604	 * Linux behaviour is to return zero-length in this case.
605	 */
606
607	if (p->p_args && (ps_argsopen || !p_can(curp, p, P_CAN_SEE, NULL))) {
608		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
609	} else if (p != curp) {
610		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
611	} else {
612		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
613		if (error)
614			return (error);
615		for (i = 0; i < pstr.ps_nargvstr; i++) {
616			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
617			sbuf_printf(sb, "%c", '\0');
618		}
619	}
620
621	return (0);
622}
623
624/*
625 * Filler function for proc/pid/exe
626 */
627static int
628linprocfs_doexelink(PFS_FILL_ARGS)
629{
630	char *fullpath = "unknown";
631	char *freepath = NULL;
632
633	textvp_fullpath(p, &fullpath, &freepath);
634	sbuf_printf(sb, "%s", fullpath);
635	if (freepath)
636		free(freepath, M_TEMP);
637	return (0);
638}
639
640/*
641 * Filler function for proc/net/dev
642 */
643static int
644linprocfs_donetdev(PFS_FILL_ARGS)
645{
646	struct ifnet *ifp;
647	int eth_index = 0;
648
649	sbuf_printf(sb,
650	    "Inter-|   Receive					     "
651	    "	      |	 Transmit\n"
652	    " face |bytes    packets errs drop fifo frame compressed "
653	    "multicast|bytes	packets errs drop fifo colls carrier "
654	    "compressed\n");
655
656	TAILQ_FOREACH(ifp, &ifnet, if_link) {
657		if (strcmp(ifp->if_name, "lo") == 0) {
658			sbuf_printf(sb, "%6.6s:", ifp->if_name);
659		} else {
660			sbuf_printf(sb, "%5.5s%d:", "eth", eth_index);
661			eth_index++;
662		}
663		sbuf_printf(sb,
664		    "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
665		    "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
666		    0, 0, 0, 0, 0, 0, 0, 0,
667		    0, 0, 0, 0, 0, 0, 0, 0);
668	}
669
670	return (0);
671}
672
673/*
674 * Filler function for proc/devices
675 */
676static int
677linprocfs_dodevices(PFS_FILL_ARGS)
678{
679	int i;
680
681	sbuf_printf(sb, "Character devices:\n");
682
683	for (i = 0; i < NUMCDEVSW; i++)
684		if (cdevsw[i] != NULL)
685			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
686
687	sbuf_printf(sb, "\nBlock devices:\n");
688
689	return (0);
690}
691
692/*
693 * Filler function for proc/cmdline
694 */
695static int
696linprocfs_docmdline(PFS_FILL_ARGS)
697{
698	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
699	sbuf_printf(sb, " ro root=302\n");
700	return (0);
701}
702
703/*
704 * Directory structure
705 */
706
707static struct pfs_node linprocfs_proc_nodes[] = {
708	PFS_THIS,
709	PFS_PARENT,
710	/*	    name	flags uid  gid	mode  data */
711        PFS_FILE(   "cmdline",	0,    0,   0,	0444, linprocfs_doproccmdline),
712	PFS_SYMLINK("exe",	0,    0,   0,	0444, linprocfs_doexelink),
713     /* PFS_FILE(   "mem",	0,    0,   0,	0444, procfs_domem), */
714	PFS_FILE(   "stat",	0,    0,   0,	0444, linprocfs_doprocstat),
715	PFS_FILE(   "status",	0,    0,   0,	0444, linprocfs_doprocstatus),
716	PFS_LASTNODE
717};
718
719static struct pfs_node linprocfs_net_nodes[] = {
720	PFS_THIS,
721	PFS_PARENT,
722	/*	    name	flags uid  gid	mode  data */
723	PFS_FILE(   "dev",	0,    0,   0,	0444, linprocfs_donetdev),
724	PFS_LASTNODE
725};
726
727static struct pfs_node linprocfs_root_nodes[] = {
728	PFS_THIS,
729	PFS_PARENT,
730	/*	    name	flags uid  gid	mode  data */
731	PFS_FILE(   "cmdline",	0,    0,   0,	0444, linprocfs_docmdline),
732	PFS_FILE(   "cpuinfo",	0,    0,   0,	0444, linprocfs_docpuinfo),
733	PFS_FILE(   "devices",	0,    0,   0,	0444, linprocfs_dodevices),
734	PFS_FILE(   "loadavg",	0,    0,   0,	0444, linprocfs_doloadavg),
735	PFS_FILE(   "meminfo",	0,    0,   0,	0444, linprocfs_domeminfo),
736	PFS_FILE(   "stat",	0,    0,   0,	0444, linprocfs_dostat),
737	PFS_FILE(   "uptime",	0,    0,   0,	0444, linprocfs_douptime),
738	PFS_FILE(   "version",	0,    0,   0,	0444, linprocfs_doversion),
739	PFS_DIR(    "net",	0,    0,   0,	0555, linprocfs_net_nodes),
740	PFS_PROCDIR(		0,    0,   0,	0555, linprocfs_proc_nodes),
741	PFS_SYMLINK("self",	0,    0,   0,	0555, linprocfs_doselflink),
742	PFS_LASTNODE
743};
744
745static struct pfs_node linprocfs_root =
746	PFS_ROOT(linprocfs_root_nodes);
747
748PSEUDOFS(linprocfs, linprocfs_root);
749MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
750MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
751