linprocfs.c revision 76839
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 76839 2001-05-19 05:54:26Z jlemon $
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/mutex.h>
54#include <sys/proc.h>
55#include <sys/resourcevar.h>
56#include <sys/sbuf.h>
57#include <sys/sysctl.h>
58#include <sys/tty.h>
59#include <sys/vnode.h>
60
61#include <vm/vm.h>
62#include <vm/pmap.h>
63#include <vm/vm_map.h>
64#include <vm/vm_param.h>
65#include <vm/vm_object.h>
66#include <vm/vm_zone.h>
67#include <vm/swap_pager.h>
68
69#include <sys/exec.h>
70#include <sys/user.h>
71#include <sys/vmmeter.h>
72
73#include <machine/clock.h>
74#include <machine/cputypes.h>
75#include <machine/md_var.h>
76
77#include <sys/socket.h>
78#include <net/if.h>
79
80#include <compat/linux/linux_mib.h>
81#include <compat/linprocfs/linprocfs.h>
82
83extern struct 	cdevsw *cdevsw[];
84
85/*
86 * Various conversion macros
87 */
88#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
89#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
90#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
91#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
92#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
93#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
94
95#define COMMON_START						\
96	struct sbuf sb;						\
97	char *ps;						\
98	int error, xlen
99
100#define COMMON_END						\
101	sbuf_finish(&sb);					\
102	ps = sbuf_data(&sb) + uio->uio_offset;			\
103	xlen = sbuf_len(&sb) -  uio->uio_offset;		\
104	xlen = imin(xlen, uio->uio_resid);			\
105	error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));	\
106	sbuf_delete(&sb);					\
107	return (error)
108
109int
110linprocfs_domeminfo(curp, p, pfs, uio)
111	struct proc *curp;
112	struct proc *p;
113	struct pfsnode *pfs;
114	struct uio *uio;
115{
116	COMMON_START;
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	if (uio->uio_rw != UIO_READ)
128		return (EOPNOTSUPP);
129
130	memtotal = physmem * PAGE_SIZE;
131	/*
132	 * The correct thing here would be:
133	 *
134	memfree = cnt.v_free_count * PAGE_SIZE;
135	memused = memtotal - memfree;
136	 *
137	 * but it might mislead linux binaries into thinking there
138	 * is very little memory left, so we cheat and tell them that
139	 * all memory that isn't wired down is free.
140	 */
141	memused = cnt.v_wire_count * PAGE_SIZE;
142	memfree = memtotal - memused;
143	if (swapblist == NULL) {
144		swaptotal = 0;
145		swapfree = 0;
146	} else {
147		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
148		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
149	}
150	swapused = swaptotal - swapfree;
151	memshared = 0;
152	TAILQ_FOREACH(object, &vm_object_list, object_list)
153		if (object->shadow_count > 1)
154			memshared += object->resident_page_count;
155	memshared *= PAGE_SIZE;
156	/*
157	 * We'd love to be able to write:
158	 *
159	buffers = bufspace;
160	 *
161	 * but bufspace is internal to vfs_bio.c and we don't feel
162	 * like unstaticizing it just for linprocfs's sake.
163	 */
164	buffers = 0;
165	cached = cnt.v_cache_count * PAGE_SIZE;
166
167	sbuf_new(&sb, NULL, 512, 0);
168	sbuf_printf(&sb,
169	    "        total:    used:    free:  shared: buffers:  cached:\n"
170	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
171	    "Swap: %llu %llu %llu\n"
172	    "MemTotal: %9lu kB\n"
173	    "MemFree:  %9lu kB\n"
174	    "MemShared:%9lu kB\n"
175	    "Buffers:  %9lu kB\n"
176	    "Cached:   %9lu kB\n"
177	    "SwapTotal:%9llu kB\n"
178	    "SwapFree: %9llu kB\n",
179	    memtotal, memused, memfree, memshared, buffers, cached,
180	    swaptotal, swapused, swapfree,
181	    B2K(memtotal), B2K(memfree),
182	    B2K(memshared), B2K(buffers), B2K(cached),
183	    B2K(swaptotal), B2K(swapfree));
184
185	COMMON_END;
186}
187
188int
189linprocfs_docpuinfo(curp, p, pfs, uio)
190	struct proc *curp;
191	struct proc *p;
192	struct pfsnode *pfs;
193	struct uio *uio;
194{
195	COMMON_START;
196	int class, i, fqmhz, fqkhz;
197
198	/*
199         * We default the flags to include all non-conflicting flags,
200         * and the Intel versions of conflicting flags.
201	 */
202        static char *flags[] = {
203		"fpu",      "vme",     "de",       "pse",      "tsc",
204		"msr",      "pae",     "mce",      "cx8",      "apic",
205		"sep",      "sep",     "mtrr",     "pge",      "mca",
206		"cmov",     "pat",     "pse36",    "pn",       "b19",
207		"b20",      "b21",     "mmxext",   "mmx",      "fxsr",
208		"xmm",      "b26",     "b27",      "b28",      "b29",
209		"3dnowext", "3dnow"
210	};
211
212	if (uio->uio_rw != UIO_READ)
213		return (EOPNOTSUPP);
214
215	switch (cpu_class) {
216	case CPUCLASS_286:
217		class = 2;
218		break;
219	case CPUCLASS_386:
220		class = 3;
221		break;
222	case CPUCLASS_486:
223		class = 4;
224		break;
225	case CPUCLASS_586:
226		class = 5;
227		break;
228	case CPUCLASS_686:
229		class = 6;
230		break;
231	default:
232                class = 0;
233		break;
234	}
235
236	sbuf_new(&sb, NULL, 512, 0);
237	sbuf_printf(&sb,
238            "processor\t: %d\n"
239	    "vendor_id\t: %.20s\n"
240	    "cpu family\t: %d\n"
241	    "model\t\t: %d\n"
242	    "stepping\t: %d\n",
243	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
244
245        sbuf_cat(&sb,
246            "flags\t\t:");
247
248        if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
249		flags[16] = "fcmov";
250        } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
251		flags[24] = "cxmmx";
252        }
253
254        for (i = 0; i < 32; i++)
255		if (cpu_feature & (1 << i))
256			sbuf_printf(&sb, " %s", flags[i]);
257	sbuf_cat(&sb, "\n");
258        if (class >= 5) {
259		fqmhz = (tsc_freq + 4999) / 1000000;
260		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
261		sbuf_printf(&sb,
262		    "cpu MHz\t\t: %d.%02d\n"
263		    "bogomips\t: %d.%02d\n",
264		    fqmhz, fqkhz, fqmhz, fqkhz);
265        }
266
267	COMMON_END;
268}
269
270int
271linprocfs_dostat(curp, p, pfs, uio)
272	struct proc *curp;
273	struct proc *p;
274	struct pfsnode *pfs;
275	struct uio *uio;
276{
277	COMMON_START;
278
279	sbuf_new(&sb, NULL, 512, 0);
280	sbuf_printf(&sb,
281	    "cpu %ld %ld %ld %ld\n"
282	    "disk 0 0 0 0\n"
283	    "page %u %u\n"
284	    "swap %u %u\n"
285	    "intr %u\n"
286	    "ctxt %u\n"
287	    "btime %ld\n",
288	    T2J(cp_time[CP_USER]),
289	    T2J(cp_time[CP_NICE]),
290	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
291	    T2J(cp_time[CP_IDLE]),
292	    cnt.v_vnodepgsin,
293	    cnt.v_vnodepgsout,
294	    cnt.v_swappgsin,
295	    cnt.v_swappgsout,
296	    cnt.v_intr,
297	    cnt.v_swtch,
298	    boottime.tv_sec);
299
300	COMMON_END;
301}
302
303int
304linprocfs_douptime(curp, p, pfs, uio)
305	struct proc *curp;
306	struct proc *p;
307	struct pfsnode *pfs;
308	struct uio *uio;
309{
310	COMMON_START;
311	struct timeval tv;
312
313	getmicrouptime(&tv);
314	sbuf_new(&sb, NULL, 64, 0);
315	sbuf_printf(&sb, "%ld.%02ld %ld.%02ld\n",
316	    tv.tv_sec, tv.tv_usec / 10000,
317	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
318
319	COMMON_END;
320}
321
322int
323linprocfs_doversion(curp, p, pfs, uio)
324	struct proc *curp;
325	struct proc *p;
326	struct pfsnode *pfs;
327	struct uio *uio;
328{
329	COMMON_START;
330
331	sbuf_new(&sb, NULL, 128, 0);
332	sbuf_printf(&sb,
333	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
334	    " #4 Sun Dec 18 04:30:00 CET 1977\n",
335	    linux_get_osname(curp),
336	    linux_get_osrelease(curp));
337
338	COMMON_END;
339}
340
341int
342linprocfs_doloadavg(curp, p, pfs, uio)
343	struct proc *curp;
344	struct proc *p;
345	struct pfsnode *pfs;
346	struct uio *uio;
347{
348	COMMON_START;
349	int lastpid, ilen;
350
351	ilen = sizeof(lastpid);
352	if (kernel_sysctlbyname(p, "kern.lastpid",
353	    &lastpid, &ilen, NULL, 0, NULL) != 0)
354		lastpid = -1;				/* fake it */
355
356	sbuf_new(&sb, NULL, 128, 0);
357	sbuf_printf(&sb,
358	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
359	    (int)(averunnable.ldavg[0] / averunnable.fscale),
360	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
361	    (int)(averunnable.ldavg[1] / averunnable.fscale),
362	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
363	    (int)(averunnable.ldavg[2] / averunnable.fscale),
364	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
365	    1,				/* number of running tasks */
366	    nprocs,			/* number of tasks */
367	    lastpid			/* the last pid */
368	);
369
370	COMMON_END;
371}
372
373int
374linprocfs_doprocstat(curp, p, pfs, uio)
375    	struct proc *curp;
376	struct proc *p;
377	struct pfsnode *pfs;
378	struct uio *uio;
379{
380	COMMON_START;
381	struct kinfo_proc kp;
382
383	fill_kinfo_proc(p, &kp);
384	sbuf_new(&sb, NULL, 1024, 0);
385	sbuf_printf(&sb, "%d", p->p_pid);
386#define PS_ADD(name, fmt, arg) sbuf_printf(&sb, " " fmt, arg)
387	PS_ADD("comm",		"(%s)",	p->p_comm);
388	PS_ADD("statr",		"%c",	'0'); /* XXX */
389	PROC_LOCK(p);
390	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
391	PROC_UNLOCK(p);
392	PS_ADD("pgrp",		"%d",	p->p_pgid);
393	PS_ADD("session",	"%d",	p->p_session->s_sid);
394	PS_ADD("tty",		"%d",	0); /* XXX */
395	PS_ADD("tpgid",		"%d",	0); /* XXX */
396	PS_ADD("flags",		"%u",	0); /* XXX */
397	PS_ADD("minflt",	"%u",	0); /* XXX */
398	PS_ADD("cminflt",	"%u",	0); /* XXX */
399	PS_ADD("majflt",	"%u",	0); /* XXX */
400	PS_ADD("cminflt",	"%u",	0); /* XXX */
401	PS_ADD("utime",		"%d",	0); /* XXX */
402	PS_ADD("stime",		"%d",	0); /* XXX */
403	PS_ADD("cutime",	"%d",	0); /* XXX */
404	PS_ADD("cstime",	"%d",	0); /* XXX */
405	PS_ADD("counter",	"%d",	0); /* XXX */
406	PS_ADD("priority",	"%d",	0); /* XXX */
407	PS_ADD("timeout",	"%u",	0); /* XXX */
408	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
409	PS_ADD("starttime",	"%d",	0); /* XXX */
410	PS_ADD("vsize",		"%u",	kp.ki_size);
411	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
412	PS_ADD("rlim",		"%u",	0); /* XXX */
413	PS_ADD("startcode",	"%u",	(unsigned)0);
414	PS_ADD("endcode",	"%u",	0); /* XXX */
415	PS_ADD("startstack",	"%u",	0); /* XXX */
416	PS_ADD("esp",		"%u",	0); /* XXX */
417	PS_ADD("eip",		"%u",	0); /* XXX */
418	PS_ADD("signal",	"%d",	0); /* XXX */
419	PS_ADD("blocked",	"%d",	0); /* XXX */
420	PS_ADD("sigignore",	"%d",	0); /* XXX */
421	PS_ADD("sigcatch",	"%d",	0); /* XXX */
422	PS_ADD("wchan",		"%u",	0); /* XXX */
423	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
424	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
425	PS_ADD("exitsignal",	"%d",	0); /* XXX */
426	PS_ADD("processor",	"%d",	0); /* XXX */
427#undef PS_ADD
428	sbuf_putc(&sb, '\n');
429
430	COMMON_END;
431}
432
433/*
434 * Map process state to descriptive letter. Note that this does not
435 * quite correspond to what Linux outputs, but it's close enough.
436 */
437static char *state_str[] = {
438	"? (unknown)",
439	"I (idle)",
440	"R (running)",
441	"S (sleeping)",
442	"T (stopped)",
443	"Z (zombie)",
444	"W (waiting)",
445	"M (mutex)"
446};
447
448int
449linprocfs_doprocstatus(curp, p, pfs, uio)
450    	struct proc *curp;
451	struct proc *p;
452	struct pfsnode *pfs;
453	struct uio *uio;
454{
455	COMMON_START;
456	struct kinfo_proc kp;
457	char *state;
458	segsz_t lsize;
459	int i;
460
461	sbuf_new(&sb, NULL, 1024, 0);
462
463	mtx_lock_spin(&sched_lock);
464	if (p->p_stat > sizeof state_str / sizeof *state_str)
465		state = state_str[0];
466	else
467		state = state_str[(int)p->p_stat];
468	mtx_unlock_spin(&sched_lock);
469
470	fill_kinfo_proc(p, &kp);
471	sbuf_printf(&sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
472	sbuf_printf(&sb, "State:\t%s\n",	state);
473
474	/*
475	 * Credentials
476	 */
477	sbuf_printf(&sb, "Pid:\t%d\n",		p->p_pid);
478	PROC_LOCK(p);
479	sbuf_printf(&sb, "PPid:\t%d\n",		p->p_pptr ?
480						p->p_pptr->p_pid : 0);
481	sbuf_printf(&sb, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid,
482			                        p->p_ucred->cr_uid,
483			                        p->p_cred->p_svuid,
484			                        /* FreeBSD doesn't have fsuid */
485				                p->p_ucred->cr_uid);
486	sbuf_printf(&sb, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid,
487			                        p->p_ucred->cr_gid,
488			                        p->p_cred->p_svgid,
489			                        /* FreeBSD doesn't have fsgid */
490				                p->p_ucred->cr_gid);
491	sbuf_cat(&sb, "Groups:\t");
492	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
493		sbuf_printf(&sb, "%d ", p->p_ucred->cr_groups[i]);
494	PROC_UNLOCK(p);
495	sbuf_putc(&sb, '\n');
496
497	/*
498	 * Memory
499	 *
500	 * While our approximation of VmLib may not be accurate (I
501	 * don't know of a simple way to verify it, and I'm not sure
502	 * it has much meaning anyway), I believe it's good enough.
503	 *
504	 * The same code that could (I think) accurately compute VmLib
505	 * could also compute VmLck, but I don't really care enough to
506	 * implement it. Submissions are welcome.
507	 */
508	sbuf_printf(&sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
509	sbuf_printf(&sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
510	sbuf_printf(&sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
511	sbuf_printf(&sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
512	sbuf_printf(&sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
513	sbuf_printf(&sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
514	lsize = B2P(kp.ki_size) - kp.ki_dsize -
515	    kp.ki_ssize - kp.ki_tsize - 1;
516	sbuf_printf(&sb, "VmLib:\t%8u kB\n",	P2K(lsize));
517
518	/*
519	 * Signal masks
520	 *
521	 * We support up to 128 signals, while Linux supports 32,
522	 * but we only define 32 (the same 32 as Linux, to boot), so
523	 * just show the lower 32 bits of each mask. XXX hack.
524	 *
525	 * NB: on certain platforms (Sparc at least) Linux actually
526	 * supports 64 signals, but this code is a long way from
527	 * running on anything but i386, so ignore that for now.
528	 */
529	PROC_LOCK(p);
530	sbuf_printf(&sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
531	/*
532	 * I can't seem to find out where the signal mask is in
533	 * relation to struct proc, so SigBlk is left unimplemented.
534	 */
535	sbuf_printf(&sb, "SigBlk:\t%08x\n",	0); /* XXX */
536	sbuf_printf(&sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
537	sbuf_printf(&sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
538	PROC_UNLOCK(p);
539
540	/*
541	 * Linux also prints the capability masks, but we don't have
542	 * capabilities yet, and when we do get them they're likely to
543	 * be meaningless to Linux programs, so we lie. XXX
544	 */
545	sbuf_printf(&sb, "CapInh:\t%016x\n",	0);
546	sbuf_printf(&sb, "CapPrm:\t%016x\n",	0);
547	sbuf_printf(&sb, "CapEff:\t%016x\n",	0);
548
549	COMMON_END;
550}
551
552int
553linprocfs_doselflink(curp, p, pfs, uio)
554	struct proc *curp;
555	struct proc *p;
556	struct pfsnode *pfs;
557	struct uio *uio;
558{
559	char buf[16];		/* should be enough */
560	int len;
561
562		/* XXX shouldn't this be uio->uio_procp->p_pid? */
563	len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
564
565	return (uiomove(buf, len, uio));
566}
567
568int
569linprocfs_doexelink(curp, p, pfs, uio)
570	struct proc *curp;
571	struct proc *p;
572	struct pfsnode *pfs;
573	struct uio *uio;
574{
575	int error = 0;
576	char *fullpath = "unknown";
577	char *freepath = NULL;
578
579	p = PFIND(pfs->pfs_pid);
580	if (p == NULL || p->p_cred == NULL || p->p_ucred == NULL) {
581		if (p != NULL)
582			PROC_UNLOCK(p);
583		printf("doexelink: pid %d disappeared\n", pfs->pfs_pid);
584	} else {
585		PROC_UNLOCK(p);
586		/* fullpath/freepath are unchanged if textvp_fullpath fails */
587		error = textvp_fullpath(p, &fullpath, &freepath);
588	}
589	error = uiomove(fullpath, strlen(fullpath), uio);
590	if (freepath)
591		free(freepath, M_TEMP);
592	return (error);
593}
594
595int
596linprocfs_donetdev(curp, p, pfs, uio)
597	struct proc *curp;
598	struct proc *p;
599	struct pfsnode *pfs;
600	struct uio *uio;
601{
602	COMMON_START;
603	struct ifnet *ifp;
604	int eth_index = 0;
605
606	sbuf_new(&sb, NULL, 1024, 0);
607	sbuf_printf(&sb,
608	    "Inter-|   Receive                                       "
609	    "         |  Transmit\n"
610	    " face |bytes    packets errs drop fifo frame compressed "
611	    "multicast|bytes    packets errs drop fifo colls carrier "
612	    "compressed\n");
613
614	TAILQ_FOREACH(ifp, &ifnet, if_link) {
615		if (strcmp(ifp->if_name, "lo") == 0) {
616			sbuf_printf(&sb, "%6.6s:", ifp->if_name);
617		} else {
618			sbuf_printf(&sb, "%5.5s%d:", "eth", eth_index);
619			eth_index++;
620		}
621		sbuf_printf(&sb,
622		    "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
623		    "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
624		    0, 0, 0, 0, 0, 0, 0, 0,
625		    0, 0, 0, 0, 0, 0, 0, 0);
626	}
627
628	COMMON_END;
629}
630
631int
632linprocfs_dodevices(curp, p, pfs, uio)
633	struct proc *curp;
634	struct proc *p;
635	struct pfsnode *pfs;
636	struct uio *uio;
637{
638	COMMON_START;
639	int i;
640
641	sbuf_new(&sb, NULL, 1024, 0);
642	sbuf_printf(&sb, "Character devices:\n");
643
644	for (i = 0; i < NUMCDEVSW; i++) {
645		if (cdevsw[i] != NULL)
646			sbuf_printf(&sb, "%3d %s\n", i, cdevsw[i]->d_name);
647	}
648
649	sbuf_printf(&sb, "\nBlock devices:\n");
650
651	COMMON_END;
652}
653
654int
655linprocfs_docmdline(curp, p, pfs, uio)
656	struct proc *curp;
657	struct proc *p;
658	struct pfsnode *pfs;
659	struct uio *uio;
660{
661	COMMON_START;
662
663	sbuf_new(&sb, NULL, 128, 0);
664	sbuf_printf(&sb, "BOOT_IMAGE=%s", kernelname);
665	sbuf_printf(&sb, " ro root=302\n");
666
667	COMMON_END;
668}
669