xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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$
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>
80 extern 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 
94 extern 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  */
109 static int
110 linprocfs_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  */
183 static int
184 linprocfs_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  */
253 static int
254 linprocfs_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  */
330 static int
331 linprocfs_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  */
358 static int
359 linprocfs_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  */
373 static int
374 linprocfs_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  */
387 static int
388 linprocfs_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  */
409 static int
410 linprocfs_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  */
467 static 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  */
481 static int
482 linprocfs_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  */
581 static int
582 linprocfs_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  */
591 static int
592 linprocfs_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_cansee(curp, p))) {
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  */
627 static int
628 linprocfs_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  */
643 static int
644 linprocfs_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  */
676 static int
677 linprocfs_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  */
695 static int
696 linprocfs_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 
707 static 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 
719 static 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 
727 static 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 
745 static struct pfs_node linprocfs_root =
746 	PFS_ROOT(linprocfs_root_nodes);
747 
748 PSEUDOFS(linprocfs, linprocfs_root);
749 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
750 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
751