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