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