linprocfs.c revision 220433
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
42#include "opt_compat.h"
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 220433 2011-04-07 23:28:28Z jkim $");
46
47#include <sys/param.h>
48#include <sys/queue.h>
49#include <sys/blist.h>
50#include <sys/conf.h>
51#include <sys/exec.h>
52#include <sys/fcntl.h>
53#include <sys/filedesc.h>
54#include <sys/jail.h>
55#include <sys/kernel.h>
56#include <sys/linker.h>
57#include <sys/lock.h>
58#include <sys/malloc.h>
59#include <sys/mount.h>
60#include <sys/msg.h>
61#include <sys/mutex.h>
62#include <sys/namei.h>
63#include <sys/proc.h>
64#include <sys/ptrace.h>
65#include <sys/resourcevar.h>
66#include <sys/sbuf.h>
67#include <sys/sem.h>
68#include <sys/smp.h>
69#include <sys/socket.h>
70#include <sys/sysctl.h>
71#include <sys/systm.h>
72#include <sys/time.h>
73#include <sys/tty.h>
74#include <sys/user.h>
75#include <sys/vmmeter.h>
76#include <sys/vnode.h>
77#include <sys/bus.h>
78
79#include <net/if.h>
80#include <net/vnet.h>
81
82#include <vm/vm.h>
83#include <vm/vm_extern.h>
84#include <vm/pmap.h>
85#include <vm/vm_map.h>
86#include <vm/vm_param.h>
87#include <vm/vm_object.h>
88#include <vm/swap_pager.h>
89
90#include <machine/clock.h>
91
92#include <geom/geom.h>
93#include <geom/geom_int.h>
94
95#if defined(__i386__) || defined(__amd64__)
96#include <machine/cputypes.h>
97#include <machine/md_var.h>
98#endif /* __i386__ || __amd64__ */
99
100#ifdef COMPAT_FREEBSD32
101#include <compat/freebsd32/freebsd32_util.h>
102#endif
103
104#ifdef COMPAT_LINUX32				/* XXX */
105#include <machine/../linux32/linux.h>
106#else
107#include <machine/../linux/linux.h>
108#endif
109#include <compat/linux/linux_ioctl.h>
110#include <compat/linux/linux_mib.h>
111#include <compat/linux/linux_util.h>
112#include <fs/pseudofs/pseudofs.h>
113#include <fs/procfs/procfs.h>
114
115/*
116 * Various conversion macros
117 */
118#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to jiffies */
119#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to centiseconds */
120#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
121#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
122#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
123#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
124#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
125#define TV2J(x)	((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
126
127/**
128 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
129 *
130 * The linux procfs state field displays one of the characters RSDZTW to
131 * denote running, sleeping in an interruptible wait, waiting in an
132 * uninterruptible disk sleep, a zombie process, process is being traced
133 * or stopped, or process is paging respectively.
134 *
135 * Our struct kinfo_proc contains the variable ki_stat which contains a
136 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
137 *
138 * This character array is used with ki_stati-1 as an index and tries to
139 * map our states to suitable linux states.
140 */
141static char linux_state[] = "RRSTZDD";
142
143/*
144 * Filler function for proc/meminfo
145 */
146static int
147linprocfs_domeminfo(PFS_FILL_ARGS)
148{
149	unsigned long memtotal;		/* total memory in bytes */
150	unsigned long memused;		/* used memory in bytes */
151	unsigned long memfree;		/* free memory in bytes */
152	unsigned long memshared;	/* shared memory ??? */
153	unsigned long buffers, cached;	/* buffer / cache memory ??? */
154	unsigned long long swaptotal;	/* total swap space in bytes */
155	unsigned long long swapused;	/* used swap space in bytes */
156	unsigned long long swapfree;	/* free swap space in bytes */
157	vm_object_t object;
158	int i, j;
159
160	memtotal = physmem * PAGE_SIZE;
161	/*
162	 * The correct thing here would be:
163	 *
164	memfree = cnt.v_free_count * PAGE_SIZE;
165	memused = memtotal - memfree;
166	 *
167	 * but it might mislead linux binaries into thinking there
168	 * is very little memory left, so we cheat and tell them that
169	 * all memory that isn't wired down is free.
170	 */
171	memused = cnt.v_wire_count * PAGE_SIZE;
172	memfree = memtotal - memused;
173	swap_pager_status(&i, &j);
174	swaptotal = (unsigned long long)i * PAGE_SIZE;
175	swapused = (unsigned long long)j * PAGE_SIZE;
176	swapfree = swaptotal - swapused;
177	memshared = 0;
178	mtx_lock(&vm_object_list_mtx);
179	TAILQ_FOREACH(object, &vm_object_list, object_list)
180		if (object->shadow_count > 1)
181			memshared += object->resident_page_count;
182	mtx_unlock(&vm_object_list_mtx);
183	memshared *= PAGE_SIZE;
184	/*
185	 * We'd love to be able to write:
186	 *
187	buffers = bufspace;
188	 *
189	 * but bufspace is internal to vfs_bio.c and we don't feel
190	 * like unstaticizing it just for linprocfs's sake.
191	 */
192	buffers = 0;
193	cached = cnt.v_cache_count * PAGE_SIZE;
194
195	sbuf_printf(sb,
196	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
197	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
198	    "Swap: %llu %llu %llu\n"
199	    "MemTotal: %9lu kB\n"
200	    "MemFree:  %9lu kB\n"
201	    "MemShared:%9lu kB\n"
202	    "Buffers:  %9lu kB\n"
203	    "Cached:   %9lu kB\n"
204	    "SwapTotal:%9llu kB\n"
205	    "SwapFree: %9llu kB\n",
206	    memtotal, memused, memfree, memshared, buffers, cached,
207	    swaptotal, swapused, swapfree,
208	    B2K(memtotal), B2K(memfree),
209	    B2K(memshared), B2K(buffers), B2K(cached),
210	    B2K(swaptotal), B2K(swapfree));
211
212	return (0);
213}
214
215#if defined(__i386__) || defined(__amd64__)
216/*
217 * Filler function for proc/cpuinfo (i386 & amd64 version)
218 */
219static int
220linprocfs_docpuinfo(PFS_FILL_ARGS)
221{
222	int hw_model[2];
223	char model[128];
224	uint64_t freq;
225	size_t size;
226	int class, fqmhz, fqkhz;
227	int i;
228
229	/*
230	 * We default the flags to include all non-conflicting flags,
231	 * and the Intel versions of conflicting flags.
232	 */
233	static char *flags[] = {
234		"fpu",	    "vme",     "de",	   "pse",      "tsc",
235		"msr",	    "pae",     "mce",	   "cx8",      "apic",
236		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
237		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
238		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
239		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
240		"3dnowext", "3dnow"
241	};
242
243	switch (cpu_class) {
244#ifdef __i386__
245	case CPUCLASS_286:
246		class = 2;
247		break;
248	case CPUCLASS_386:
249		class = 3;
250		break;
251	case CPUCLASS_486:
252		class = 4;
253		break;
254	case CPUCLASS_586:
255		class = 5;
256		break;
257	case CPUCLASS_686:
258		class = 6;
259		break;
260	default:
261		class = 0;
262		break;
263#else /* __amd64__ */
264	default:
265		class = 15;
266		break;
267#endif
268	}
269
270	hw_model[0] = CTL_HW;
271	hw_model[1] = HW_MODEL;
272	model[0] = '\0';
273	size = sizeof(model);
274	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
275		strcpy(model, "unknown");
276	for (i = 0; i < mp_ncpus; ++i) {
277		sbuf_printf(sb,
278		    "processor\t: %d\n"
279		    "vendor_id\t: %.20s\n"
280		    "cpu family\t: %u\n"
281		    "model\t\t: %u\n"
282		    "model name\t: %s\n"
283		    "stepping\t: %u\n\n",
284		    i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
285		    CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
286		/* XXX per-cpu vendor / class / model / id? */
287	}
288
289	sbuf_cat(sb, "flags\t\t:");
290
291#ifdef __i386__
292	switch (cpu_vendor_id) {
293	case CPU_VENDOR_AMD:
294		if (class < 6)
295			flags[16] = "fcmov";
296		break;
297	case CPU_VENDOR_CYRIX:
298		flags[24] = "cxmmx";
299		break;
300	}
301#endif
302
303	for (i = 0; i < 32; i++)
304		if (cpu_feature & (1 << i))
305			sbuf_printf(sb, " %s", flags[i]);
306	sbuf_cat(sb, "\n");
307	freq = atomic_load_acq_64(&tsc_freq);
308	if (freq != 0) {
309		fqmhz = (freq + 4999) / 1000000;
310		fqkhz = ((freq + 4999) / 10000) % 100;
311		sbuf_printf(sb,
312		    "cpu MHz\t\t: %d.%02d\n"
313		    "bogomips\t: %d.%02d\n",
314		    fqmhz, fqkhz, fqmhz, fqkhz);
315	}
316
317	return (0);
318}
319#endif /* __i386__ || __amd64__ */
320
321/*
322 * Filler function for proc/mtab
323 *
324 * This file doesn't exist in Linux' procfs, but is included here so
325 * users can symlink /compat/linux/etc/mtab to /proc/mtab
326 */
327static int
328linprocfs_domtab(PFS_FILL_ARGS)
329{
330	struct nameidata nd;
331	struct mount *mp;
332	const char *lep;
333	char *dlep, *flep, *mntto, *mntfrom, *fstype;
334	size_t lep_len;
335	int error;
336
337	/* resolve symlinks etc. in the emulation tree prefix */
338	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
339	flep = NULL;
340	error = namei(&nd);
341	lep = linux_emul_path;
342	if (error == 0) {
343		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
344			lep = dlep;
345		vrele(nd.ni_vp);
346		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
347	}
348	lep_len = strlen(lep);
349
350	mtx_lock(&mountlist_mtx);
351	error = 0;
352	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
353		/* determine device name */
354		mntfrom = mp->mnt_stat.f_mntfromname;
355
356		/* determine mount point */
357		mntto = mp->mnt_stat.f_mntonname;
358		if (strncmp(mntto, lep, lep_len) == 0 &&
359		    mntto[lep_len] == '/')
360			mntto += lep_len;
361
362		/* determine fs type */
363		fstype = mp->mnt_stat.f_fstypename;
364		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365			mntfrom = fstype = "proc";
366		else if (strcmp(fstype, "procfs") == 0)
367			continue;
368
369		if (strcmp(fstype, "linsysfs") == 0) {
370			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
372		} else {
373			/* For Linux msdosfs is called vfat */
374			if (strcmp(fstype, "msdosfs") == 0)
375				fstype = "vfat";
376			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
378		}
379#define ADD_OPTION(opt, name) \
380	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
381		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
382		ADD_OPTION(MNT_NOEXEC,		"noexec");
383		ADD_OPTION(MNT_NOSUID,		"nosuid");
384		ADD_OPTION(MNT_UNION,		"union");
385		ADD_OPTION(MNT_ASYNC,		"async");
386		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
387		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
388		ADD_OPTION(MNT_NOATIME,		"noatime");
389#undef ADD_OPTION
390		/* a real Linux mtab will also show NFS options */
391		sbuf_printf(sb, " 0 0\n");
392	}
393	mtx_unlock(&mountlist_mtx);
394	if (flep != NULL)
395		free(flep, M_TEMP);
396	return (error);
397}
398
399/*
400 * Filler function for proc/partitions
401 *
402 */
403static int
404linprocfs_dopartitions(PFS_FILL_ARGS)
405{
406	struct g_class *cp;
407	struct g_geom *gp;
408	struct g_provider *pp;
409	struct nameidata nd;
410	const char *lep;
411	char  *dlep, *flep;
412	size_t lep_len;
413	int error;
414	int major, minor;
415
416	/* resolve symlinks etc. in the emulation tree prefix */
417	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
418	flep = NULL;
419	error = namei(&nd);
420	lep = linux_emul_path;
421	if (error == 0) {
422		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
423			lep = dlep;
424		vrele(nd.ni_vp);
425		VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
426	}
427	lep_len = strlen(lep);
428
429	g_topology_lock();
430	error = 0;
431	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
432	    "ruse wio wmerge wsect wuse running use aveq\n");
433
434	LIST_FOREACH(cp, &g_classes, class) {
435		if (strcmp(cp->name, "DISK") == 0 ||
436		    strcmp(cp->name, "PART") == 0)
437			LIST_FOREACH(gp, &cp->geom, geom) {
438				LIST_FOREACH(pp, &gp->provider, provider) {
439					if (linux_driver_get_major_minor(
440					    pp->name, &major, &minor) != 0) {
441						major = 0;
442						minor = 0;
443					}
444					sbuf_printf(sb, "%d %d %lld %s "
445					    "%d %d %d %d %d "
446					     "%d %d %d %d %d %d\n",
447					     major, minor,
448					     (long long)pp->mediasize, pp->name,
449					     0, 0, 0, 0, 0,
450					     0, 0, 0, 0, 0, 0);
451				}
452			}
453	}
454	g_topology_unlock();
455
456	if (flep != NULL)
457		free(flep, M_TEMP);
458	return (error);
459}
460
461
462/*
463 * Filler function for proc/stat
464 */
465static int
466linprocfs_dostat(PFS_FILL_ARGS)
467{
468	struct pcpu *pcpu;
469	long cp_time[CPUSTATES];
470	long *cp;
471	int i;
472
473	read_cpu_time(cp_time);
474	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
475	    T2J(cp_time[CP_USER]),
476	    T2J(cp_time[CP_NICE]),
477	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
478	    T2J(cp_time[CP_IDLE]));
479	CPU_FOREACH(i) {
480		pcpu = pcpu_find(i);
481		cp = pcpu->pc_cp_time;
482		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
483		    T2J(cp[CP_USER]),
484		    T2J(cp[CP_NICE]),
485		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
486		    T2J(cp[CP_IDLE]));
487	}
488	sbuf_printf(sb,
489	    "disk 0 0 0 0\n"
490	    "page %u %u\n"
491	    "swap %u %u\n"
492	    "intr %u\n"
493	    "ctxt %u\n"
494	    "btime %lld\n",
495	    cnt.v_vnodepgsin,
496	    cnt.v_vnodepgsout,
497	    cnt.v_swappgsin,
498	    cnt.v_swappgsout,
499	    cnt.v_intr,
500	    cnt.v_swtch,
501	    (long long)boottime.tv_sec);
502	return (0);
503}
504
505/*
506 * Filler function for proc/uptime
507 */
508static int
509linprocfs_douptime(PFS_FILL_ARGS)
510{
511	long cp_time[CPUSTATES];
512	struct timeval tv;
513
514	getmicrouptime(&tv);
515	read_cpu_time(cp_time);
516	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
517	    (long long)tv.tv_sec, tv.tv_usec / 10000,
518	    T2S(cp_time[CP_IDLE] / mp_ncpus),
519	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
520	return (0);
521}
522
523/*
524 * Get OS build date
525 */
526static void
527linprocfs_osbuild(struct thread *td, struct sbuf *sb)
528{
529#if 0
530	char osbuild[256];
531	char *cp1, *cp2;
532
533	strncpy(osbuild, version, 256);
534	osbuild[255] = '\0';
535	cp1 = strstr(osbuild, "\n");
536	cp2 = strstr(osbuild, ":");
537	if (cp1 && cp2) {
538		*cp1 = *cp2 = '\0';
539		cp1 = strstr(osbuild, "#");
540	} else
541		cp1 = NULL;
542	if (cp1)
543		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
544	else
545#endif
546		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
547}
548
549/*
550 * Get OS builder
551 */
552static void
553linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
554{
555#if 0
556	char builder[256];
557	char *cp;
558
559	cp = strstr(version, "\n    ");
560	if (cp) {
561		strncpy(builder, cp + 5, 256);
562		builder[255] = '\0';
563		cp = strstr(builder, ":");
564		if (cp)
565			*cp = '\0';
566	}
567	if (cp)
568		sbuf_cat(sb, builder);
569	else
570#endif
571		sbuf_cat(sb, "des@freebsd.org");
572}
573
574/*
575 * Filler function for proc/version
576 */
577static int
578linprocfs_doversion(PFS_FILL_ARGS)
579{
580	char osname[LINUX_MAX_UTSNAME];
581	char osrelease[LINUX_MAX_UTSNAME];
582
583	linux_get_osname(td, osname);
584	linux_get_osrelease(td, osrelease);
585	sbuf_printf(sb, "%s version %s (", osname, osrelease);
586	linprocfs_osbuilder(td, sb);
587	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
588	linprocfs_osbuild(td, sb);
589	sbuf_cat(sb, "\n");
590
591	return (0);
592}
593
594/*
595 * Filler function for proc/loadavg
596 */
597static int
598linprocfs_doloadavg(PFS_FILL_ARGS)
599{
600
601	sbuf_printf(sb,
602	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
603	    (int)(averunnable.ldavg[0] / averunnable.fscale),
604	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
605	    (int)(averunnable.ldavg[1] / averunnable.fscale),
606	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
607	    (int)(averunnable.ldavg[2] / averunnable.fscale),
608	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
609	    1,				/* number of running tasks */
610	    nprocs,			/* number of tasks */
611	    lastpid			/* the last pid */
612	);
613	return (0);
614}
615
616/*
617 * Filler function for proc/pid/stat
618 */
619static int
620linprocfs_doprocstat(PFS_FILL_ARGS)
621{
622	struct kinfo_proc kp;
623	char state;
624	static int ratelimit = 0;
625	vm_offset_t startcode, startdata;
626
627	PROC_LOCK(p);
628	fill_kinfo_proc(p, &kp);
629	if (p->p_vmspace) {
630	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
631	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
632	} else {
633	   startcode = 0;
634	   startdata = 0;
635	};
636	sbuf_printf(sb, "%d", p->p_pid);
637#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
638	PS_ADD("comm",		"(%s)",	p->p_comm);
639	if (kp.ki_stat > sizeof(linux_state)) {
640		state = 'R';
641
642		if (ratelimit == 0) {
643			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
644			    kp.ki_stat, sizeof(linux_state));
645			++ratelimit;
646		}
647	} else
648		state = linux_state[kp.ki_stat - 1];
649	PS_ADD("state",		"%c",	state);
650	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
651	PS_ADD("pgrp",		"%d",	p->p_pgid);
652	PS_ADD("session",	"%d",	p->p_session->s_sid);
653	PROC_UNLOCK(p);
654	PS_ADD("tty",		"%d",	kp.ki_tdev);
655	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
656	PS_ADD("flags",		"%u",	0); /* XXX */
657	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
658	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
659	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
660	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
661	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
662	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
663	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
664	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
665	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
666	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
667	PS_ADD("0",		"%d",	0); /* removed field */
668	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
669	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
670	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
671	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
672	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
673	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
674	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
675	PS_ADD("startstack",	"%u",	0); /* XXX */
676	PS_ADD("kstkesp",	"%u",	0); /* XXX */
677	PS_ADD("kstkeip",	"%u",	0); /* XXX */
678	PS_ADD("signal",	"%u",	0); /* XXX */
679	PS_ADD("blocked",	"%u",	0); /* XXX */
680	PS_ADD("sigignore",	"%u",	0); /* XXX */
681	PS_ADD("sigcatch",	"%u",	0); /* XXX */
682	PS_ADD("wchan",		"%u",	0); /* XXX */
683	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
684	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
685	PS_ADD("exitsignal",	"%d",	0); /* XXX */
686	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
687	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
688	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
689#undef PS_ADD
690	sbuf_putc(sb, '\n');
691
692	return (0);
693}
694
695/*
696 * Filler function for proc/pid/statm
697 */
698static int
699linprocfs_doprocstatm(PFS_FILL_ARGS)
700{
701	struct kinfo_proc kp;
702	segsz_t lsize;
703
704	PROC_LOCK(p);
705	fill_kinfo_proc(p, &kp);
706	PROC_UNLOCK(p);
707
708	/*
709	 * See comments in linprocfs_doprocstatus() regarding the
710	 * computation of lsize.
711	 */
712	/* size resident share trs drs lrs dt */
713	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
714	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
715	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
716	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
717	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
718	lsize = B2P(kp.ki_size) - kp.ki_dsize -
719	    kp.ki_ssize - kp.ki_tsize - 1;
720	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
721	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
722
723	return (0);
724}
725
726/*
727 * Filler function for proc/pid/status
728 */
729static int
730linprocfs_doprocstatus(PFS_FILL_ARGS)
731{
732	struct kinfo_proc kp;
733	char *state;
734	segsz_t lsize;
735	struct thread *td2;
736	struct sigacts *ps;
737	int i;
738
739	PROC_LOCK(p);
740	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
741
742	if (P_SHOULDSTOP(p)) {
743		state = "T (stopped)";
744	} else {
745		switch(p->p_state) {
746		case PRS_NEW:
747			state = "I (idle)";
748			break;
749		case PRS_NORMAL:
750			if (p->p_flag & P_WEXIT) {
751				state = "X (exiting)";
752				break;
753			}
754			switch(td2->td_state) {
755			case TDS_INHIBITED:
756				state = "S (sleeping)";
757				break;
758			case TDS_RUNQ:
759			case TDS_RUNNING:
760				state = "R (running)";
761				break;
762			default:
763				state = "? (unknown)";
764				break;
765			}
766			break;
767		case PRS_ZOMBIE:
768			state = "Z (zombie)";
769			break;
770		default:
771			state = "? (unknown)";
772			break;
773		}
774	}
775
776	fill_kinfo_proc(p, &kp);
777	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
778	sbuf_printf(sb, "State:\t%s\n",		state);
779
780	/*
781	 * Credentials
782	 */
783	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
784	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
785						p->p_pptr->p_pid : 0);
786	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
787						p->p_ucred->cr_uid,
788						p->p_ucred->cr_svuid,
789						/* FreeBSD doesn't have fsuid */
790						p->p_ucred->cr_uid);
791	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
792						p->p_ucred->cr_gid,
793						p->p_ucred->cr_svgid,
794						/* FreeBSD doesn't have fsgid */
795						p->p_ucred->cr_gid);
796	sbuf_cat(sb, "Groups:\t");
797	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
798		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
799	PROC_UNLOCK(p);
800	sbuf_putc(sb, '\n');
801
802	/*
803	 * Memory
804	 *
805	 * While our approximation of VmLib may not be accurate (I
806	 * don't know of a simple way to verify it, and I'm not sure
807	 * it has much meaning anyway), I believe it's good enough.
808	 *
809	 * The same code that could (I think) accurately compute VmLib
810	 * could also compute VmLck, but I don't really care enough to
811	 * implement it. Submissions are welcome.
812	 */
813	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
814	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
815	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
816	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
817	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
818	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
819	lsize = B2P(kp.ki_size) - kp.ki_dsize -
820	    kp.ki_ssize - kp.ki_tsize - 1;
821	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
822
823	/*
824	 * Signal masks
825	 *
826	 * We support up to 128 signals, while Linux supports 32,
827	 * but we only define 32 (the same 32 as Linux, to boot), so
828	 * just show the lower 32 bits of each mask. XXX hack.
829	 *
830	 * NB: on certain platforms (Sparc at least) Linux actually
831	 * supports 64 signals, but this code is a long way from
832	 * running on anything but i386, so ignore that for now.
833	 */
834	PROC_LOCK(p);
835	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
836	/*
837	 * I can't seem to find out where the signal mask is in
838	 * relation to struct proc, so SigBlk is left unimplemented.
839	 */
840	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
841	ps = p->p_sigacts;
842	mtx_lock(&ps->ps_mtx);
843	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
844	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
845	mtx_unlock(&ps->ps_mtx);
846	PROC_UNLOCK(p);
847
848	/*
849	 * Linux also prints the capability masks, but we don't have
850	 * capabilities yet, and when we do get them they're likely to
851	 * be meaningless to Linux programs, so we lie. XXX
852	 */
853	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
854	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
855	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
856
857	return (0);
858}
859
860
861/*
862 * Filler function for proc/pid/cwd
863 */
864static int
865linprocfs_doproccwd(PFS_FILL_ARGS)
866{
867	char *fullpath = "unknown";
868	char *freepath = NULL;
869
870	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
871	sbuf_printf(sb, "%s", fullpath);
872	if (freepath)
873		free(freepath, M_TEMP);
874	return (0);
875}
876
877/*
878 * Filler function for proc/pid/root
879 */
880static int
881linprocfs_doprocroot(PFS_FILL_ARGS)
882{
883	struct vnode *rvp;
884	char *fullpath = "unknown";
885	char *freepath = NULL;
886
887	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
888	vn_fullpath(td, rvp, &fullpath, &freepath);
889	sbuf_printf(sb, "%s", fullpath);
890	if (freepath)
891		free(freepath, M_TEMP);
892	return (0);
893}
894
895#define MAX_ARGV_STR	512	/* Max number of argv-like strings */
896#define UIO_CHUNK_SZ	256	/* Max chunk size (bytes) for uiomove */
897
898static int
899linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
900    void (*resolver)(const struct ps_strings, u_long *, int *))
901{
902	struct iovec iov;
903	struct uio tmp_uio;
904	struct ps_strings pss;
905	int ret, i, n_elements, elm_len;
906	u_long addr, pbegin;
907	char **env_vector, *envp;
908	char env_string[UIO_CHUNK_SZ];
909#ifdef COMPAT_FREEBSD32
910	struct freebsd32_ps_strings pss32;
911	uint32_t *env_vector32;
912#endif
913
914#define	UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td)	\
915do {									\
916	iov.iov_base = (caddr_t)(base);					\
917	iov.iov_len = (len); 						\
918	uio.uio_iov = &(iov); 						\
919	uio.uio_iovcnt = (cnt);	 					\
920	uio.uio_offset = (off_t)(offset);				\
921	uio.uio_resid = (sz); 						\
922	uio.uio_segflg = (flg);						\
923	uio.uio_rw = (rw); 						\
924	uio.uio_td = (td);						\
925} while (0)
926
927	env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
928
929#ifdef COMPAT_FREEBSD32
930	env_vector32 = NULL;
931	if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
932		env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
933		    M_TEMP, M_WAITOK);
934		elm_len = sizeof(int32_t);
935		envp = (char *)env_vector32;
936
937		UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
938		    (off_t)(p->p_sysent->sv_psstrings),
939		    sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
940		ret = proc_rwmem(p, &tmp_uio);
941		if (ret != 0)
942			goto done;
943		pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
944		pss.ps_nargvstr = pss32.ps_nargvstr;
945		pss.ps_envstr = PTRIN(pss32.ps_envstr);
946		pss.ps_nenvstr = pss32.ps_nenvstr;
947	} else {
948#endif
949		elm_len = sizeof(char *);
950		envp = (char *)env_vector;
951
952		UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
953		    (off_t)(p->p_sysent->sv_psstrings),
954		    sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
955		ret = proc_rwmem(p, &tmp_uio);
956		if (ret != 0)
957			goto done;
958#ifdef COMPAT_FREEBSD32
959	}
960#endif
961
962	/* Get the array address and the number of elements */
963	resolver(pss, &addr, &n_elements);
964
965	/* Consistent with lib/libkvm/kvm_proc.c */
966	if (n_elements > MAX_ARGV_STR) {
967		ret = E2BIG;
968		goto done;
969	}
970
971	UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
972	    (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
973	ret = proc_rwmem(p, &tmp_uio);
974	if (ret != 0)
975		goto done;
976#ifdef COMPAT_FREEBSD32
977	if (env_vector32 != NULL) {
978		for (i = 0; i < n_elements; i++)
979			env_vector[i] = PTRIN(env_vector32[i]);
980	}
981#endif
982
983	/* Now we can iterate through the list of strings */
984	for (i = 0; i < n_elements; i++) {
985		pbegin = (vm_offset_t)env_vector[i];
986		for (;;) {
987			UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
988			    1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
989			ret = proc_rwmem(p, &tmp_uio);
990			if (ret != 0)
991				goto done;
992
993			if (!strvalid(env_string, UIO_CHUNK_SZ)) {
994				/*
995				 * We didn't find the end of the string.
996				 * Add the string to the buffer and move
997				 * the pointer.  But do not allow strings
998				 * of unlimited length.
999				 */
1000				sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1001				if (sbuf_len(sb) >= ARG_MAX) {
1002					ret = E2BIG;
1003					goto done;
1004				}
1005				pbegin += UIO_CHUNK_SZ;
1006			} else {
1007				sbuf_cat(sb, env_string);
1008				break;
1009			}
1010		}
1011		sbuf_bcat(sb, "", 1);
1012	}
1013#undef UIO_HELPER
1014
1015done:
1016	free(env_vector, M_TEMP);
1017#ifdef COMPAT_FREEBSD32
1018	free(env_vector32, M_TEMP);
1019#endif
1020	return (ret);
1021}
1022
1023static void
1024ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1025{
1026
1027	*addr = (u_long) ps.ps_argvstr;
1028	*n = ps.ps_nargvstr;
1029}
1030
1031static void
1032ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1033{
1034
1035	*addr = (u_long) ps.ps_envstr;
1036	*n = ps.ps_nenvstr;
1037}
1038
1039/*
1040 * Filler function for proc/pid/cmdline
1041 */
1042static int
1043linprocfs_doproccmdline(PFS_FILL_ARGS)
1044{
1045	int ret;
1046
1047	PROC_LOCK(p);
1048	if ((ret = p_cansee(td, p)) != 0) {
1049		PROC_UNLOCK(p);
1050		return (ret);
1051	}
1052	if (p->p_args != NULL) {
1053		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1054		PROC_UNLOCK(p);
1055		return (0);
1056	}
1057	PROC_UNLOCK(p);
1058
1059	ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1060	return (ret);
1061}
1062
1063/*
1064 * Filler function for proc/pid/environ
1065 */
1066static int
1067linprocfs_doprocenviron(PFS_FILL_ARGS)
1068{
1069	int ret;
1070
1071	PROC_LOCK(p);
1072	if ((ret = p_cansee(td, p)) != 0) {
1073		PROC_UNLOCK(p);
1074		return (ret);
1075	}
1076	PROC_UNLOCK(p);
1077
1078	ret = linprocfs_doargv(td, p, sb, ps_string_env);
1079	return (ret);
1080}
1081
1082/*
1083 * Filler function for proc/pid/maps
1084 */
1085static int
1086linprocfs_doprocmaps(PFS_FILL_ARGS)
1087{
1088	struct vmspace *vm;
1089	vm_map_t map;
1090	vm_map_entry_t entry, tmp_entry;
1091	vm_object_t obj, tobj, lobj;
1092	vm_offset_t e_start, e_end;
1093	vm_ooffset_t off = 0;
1094	vm_prot_t e_prot;
1095	unsigned int last_timestamp;
1096	char *name = "", *freename = NULL;
1097	ino_t ino;
1098	int ref_count, shadow_count, flags;
1099	int error;
1100	struct vnode *vp;
1101	struct vattr vat;
1102	int locked;
1103
1104	PROC_LOCK(p);
1105	error = p_candebug(td, p);
1106	PROC_UNLOCK(p);
1107	if (error)
1108		return (error);
1109
1110	if (uio->uio_rw != UIO_READ)
1111		return (EOPNOTSUPP);
1112
1113	error = 0;
1114	vm = vmspace_acquire_ref(p);
1115	if (vm == NULL)
1116		return (ESRCH);
1117	map = &vm->vm_map;
1118	vm_map_lock_read(map);
1119	for (entry = map->header.next; entry != &map->header;
1120	    entry = entry->next) {
1121		name = "";
1122		freename = NULL;
1123		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1124			continue;
1125		e_prot = entry->protection;
1126		e_start = entry->start;
1127		e_end = entry->end;
1128		obj = entry->object.vm_object;
1129		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1130			VM_OBJECT_LOCK(tobj);
1131			if (lobj != obj)
1132				VM_OBJECT_UNLOCK(lobj);
1133			lobj = tobj;
1134		}
1135		last_timestamp = map->timestamp;
1136		vm_map_unlock_read(map);
1137		ino = 0;
1138		if (lobj) {
1139			off = IDX_TO_OFF(lobj->size);
1140			if (lobj->type == OBJT_VNODE) {
1141				vp = lobj->handle;
1142				if (vp)
1143					vref(vp);
1144			}
1145			else
1146				vp = NULL;
1147			if (lobj != obj)
1148				VM_OBJECT_UNLOCK(lobj);
1149			flags = obj->flags;
1150			ref_count = obj->ref_count;
1151			shadow_count = obj->shadow_count;
1152			VM_OBJECT_UNLOCK(obj);
1153			if (vp) {
1154				vn_fullpath(td, vp, &name, &freename);
1155				locked = VFS_LOCK_GIANT(vp->v_mount);
1156				vn_lock(vp, LK_SHARED | LK_RETRY);
1157				VOP_GETATTR(vp, &vat, td->td_ucred);
1158				ino = vat.va_fileid;
1159				vput(vp);
1160				VFS_UNLOCK_GIANT(locked);
1161			}
1162		} else {
1163			flags = 0;
1164			ref_count = 0;
1165			shadow_count = 0;
1166		}
1167
1168		/*
1169		 * format:
1170		 *  start, end, access, offset, major, minor, inode, name.
1171		 */
1172		error = sbuf_printf(sb,
1173		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1174		    (u_long)e_start, (u_long)e_end,
1175		    (e_prot & VM_PROT_READ)?"r":"-",
1176		    (e_prot & VM_PROT_WRITE)?"w":"-",
1177		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1178		    "p",
1179		    (u_long)off,
1180		    0,
1181		    0,
1182		    (u_long)ino,
1183		    *name ? "     " : "",
1184		    name
1185		    );
1186		if (freename)
1187			free(freename, M_TEMP);
1188		vm_map_lock_read(map);
1189		if (error == -1) {
1190			error = 0;
1191			break;
1192		}
1193		if (last_timestamp != map->timestamp) {
1194			/*
1195			 * Look again for the entry because the map was
1196			 * modified while it was unlocked.  Specifically,
1197			 * the entry may have been clipped, merged, or deleted.
1198			 */
1199			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1200			entry = tmp_entry;
1201		}
1202	}
1203	vm_map_unlock_read(map);
1204	vmspace_free(vm);
1205
1206	return (error);
1207}
1208
1209/*
1210 * Filler function for proc/net/dev
1211 */
1212static int
1213linprocfs_donetdev(PFS_FILL_ARGS)
1214{
1215	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1216	struct ifnet *ifp;
1217
1218	sbuf_printf(sb, "%6s|%58s|%s\n"
1219	    "%6s|%58s|%58s\n",
1220	    "Inter-", "   Receive", "  Transmit",
1221	    " face",
1222	    "bytes    packets errs drop fifo frame compressed multicast",
1223	    "bytes    packets errs drop fifo colls carrier compressed");
1224
1225	CURVNET_SET(TD_TO_VNET(curthread));
1226	IFNET_RLOCK();
1227	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1228		linux_ifname(ifp, ifname, sizeof ifname);
1229		sbuf_printf(sb, "%6.6s: ", ifname);
1230		sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1231		    ifp->if_ibytes,	/* rx_bytes */
1232		    ifp->if_ipackets,	/* rx_packets */
1233		    ifp->if_ierrors,	/* rx_errors */
1234		    ifp->if_iqdrops,	/* rx_dropped +
1235					 * rx_missed_errors */
1236		    0UL,		/* rx_fifo_errors */
1237		    0UL,		/* rx_length_errors +
1238					 * rx_over_errors +
1239		    			 * rx_crc_errors +
1240					 * rx_frame_errors */
1241		    0UL,		/* rx_compressed */
1242		    ifp->if_imcasts);	/* multicast, XXX-BZ rx only? */
1243		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1244		    ifp->if_obytes,	/* tx_bytes */
1245		    ifp->if_opackets,	/* tx_packets */
1246		    ifp->if_oerrors,	/* tx_errors */
1247		    0UL,		/* tx_dropped */
1248		    0UL,		/* tx_fifo_errors */
1249		    ifp->if_collisions,	/* collisions */
1250		    0UL,		/* tx_carrier_errors +
1251					 * tx_aborted_errors +
1252					 * tx_window_errors +
1253					 * tx_heartbeat_errors */
1254		    0UL);		/* tx_compressed */
1255	}
1256	IFNET_RUNLOCK();
1257	CURVNET_RESTORE();
1258
1259	return (0);
1260}
1261
1262/*
1263 * Filler function for proc/sys/kernel/osrelease
1264 */
1265static int
1266linprocfs_doosrelease(PFS_FILL_ARGS)
1267{
1268	char osrelease[LINUX_MAX_UTSNAME];
1269
1270	linux_get_osrelease(td, osrelease);
1271	sbuf_printf(sb, "%s\n", osrelease);
1272
1273	return (0);
1274}
1275
1276/*
1277 * Filler function for proc/sys/kernel/ostype
1278 */
1279static int
1280linprocfs_doostype(PFS_FILL_ARGS)
1281{
1282	char osname[LINUX_MAX_UTSNAME];
1283
1284	linux_get_osname(td, osname);
1285	sbuf_printf(sb, "%s\n", osname);
1286
1287	return (0);
1288}
1289
1290/*
1291 * Filler function for proc/sys/kernel/version
1292 */
1293static int
1294linprocfs_doosbuild(PFS_FILL_ARGS)
1295{
1296
1297	linprocfs_osbuild(td, sb);
1298	sbuf_cat(sb, "\n");
1299	return (0);
1300}
1301
1302/*
1303 * Filler function for proc/sys/kernel/msgmni
1304 */
1305static int
1306linprocfs_domsgmni(PFS_FILL_ARGS)
1307{
1308
1309	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1310	return (0);
1311}
1312
1313/*
1314 * Filler function for proc/sys/kernel/pid_max
1315 */
1316static int
1317linprocfs_dopid_max(PFS_FILL_ARGS)
1318{
1319
1320	sbuf_printf(sb, "%i\n", PID_MAX);
1321	return (0);
1322}
1323
1324/*
1325 * Filler function for proc/sys/kernel/sem
1326 */
1327static int
1328linprocfs_dosem(PFS_FILL_ARGS)
1329{
1330
1331	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1332	    seminfo.semopm, seminfo.semmni);
1333	return (0);
1334}
1335
1336/*
1337 * Filler function for proc/scsi/device_info
1338 */
1339static int
1340linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1341{
1342
1343	return (0);
1344}
1345
1346/*
1347 * Filler function for proc/scsi/scsi
1348 */
1349static int
1350linprocfs_doscsiscsi(PFS_FILL_ARGS)
1351{
1352
1353	return (0);
1354}
1355
1356extern struct cdevsw *cdevsw[];
1357
1358/*
1359 * Filler function for proc/devices
1360 */
1361static int
1362linprocfs_dodevices(PFS_FILL_ARGS)
1363{
1364	char *char_devices;
1365	sbuf_printf(sb, "Character devices:\n");
1366
1367	char_devices = linux_get_char_devices();
1368	sbuf_printf(sb, "%s", char_devices);
1369	linux_free_get_char_devices(char_devices);
1370
1371	sbuf_printf(sb, "\nBlock devices:\n");
1372
1373	return (0);
1374}
1375
1376/*
1377 * Filler function for proc/cmdline
1378 */
1379static int
1380linprocfs_docmdline(PFS_FILL_ARGS)
1381{
1382
1383	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1384	sbuf_printf(sb, " ro root=302\n");
1385	return (0);
1386}
1387
1388/*
1389 * Filler function for proc/filesystems
1390 */
1391static int
1392linprocfs_dofilesystems(PFS_FILL_ARGS)
1393{
1394	struct vfsconf *vfsp;
1395
1396	mtx_lock(&Giant);
1397	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1398		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1399			sbuf_printf(sb, "nodev");
1400		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1401	}
1402	mtx_unlock(&Giant);
1403	return(0);
1404}
1405
1406#if 0
1407/*
1408 * Filler function for proc/modules
1409 */
1410static int
1411linprocfs_domodules(PFS_FILL_ARGS)
1412{
1413	struct linker_file *lf;
1414
1415	TAILQ_FOREACH(lf, &linker_files, link) {
1416		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1417		    (unsigned long)lf->size, lf->refs);
1418	}
1419	return (0);
1420}
1421#endif
1422
1423/*
1424 * Filler function for proc/pid/fd
1425 */
1426static int
1427linprocfs_dofdescfs(PFS_FILL_ARGS)
1428{
1429
1430	if (p == curproc)
1431		sbuf_printf(sb, "/dev/fd");
1432	else
1433		sbuf_printf(sb, "unknown");
1434	return (0);
1435}
1436
1437/*
1438 * Constructor
1439 */
1440static int
1441linprocfs_init(PFS_INIT_ARGS)
1442{
1443	struct pfs_node *root;
1444	struct pfs_node *dir;
1445
1446	root = pi->pi_root;
1447
1448	/* /proc/... */
1449	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1450	    NULL, NULL, NULL, PFS_RD);
1451	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1452	    NULL, NULL, NULL, PFS_RD);
1453	pfs_create_file(root, "devices", &linprocfs_dodevices,
1454	    NULL, NULL, NULL, PFS_RD);
1455	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1456	    NULL, NULL, NULL, PFS_RD);
1457	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1458	    NULL, NULL, NULL, PFS_RD);
1459	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1460	    NULL, NULL, NULL, PFS_RD);
1461#if 0
1462	pfs_create_file(root, "modules", &linprocfs_domodules,
1463	    NULL, NULL, NULL, PFS_RD);
1464#endif
1465	pfs_create_file(root, "mounts", &linprocfs_domtab,
1466	    NULL, NULL, NULL, PFS_RD);
1467	pfs_create_file(root, "mtab", &linprocfs_domtab,
1468	    NULL, NULL, NULL, PFS_RD);
1469	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1470	    NULL, NULL, NULL, PFS_RD);
1471	pfs_create_link(root, "self", &procfs_docurproc,
1472	    NULL, NULL, NULL, 0);
1473	pfs_create_file(root, "stat", &linprocfs_dostat,
1474	    NULL, NULL, NULL, PFS_RD);
1475	pfs_create_file(root, "uptime", &linprocfs_douptime,
1476	    NULL, NULL, NULL, PFS_RD);
1477	pfs_create_file(root, "version", &linprocfs_doversion,
1478	    NULL, NULL, NULL, PFS_RD);
1479
1480	/* /proc/net/... */
1481	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1482	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1483	    NULL, NULL, NULL, PFS_RD);
1484
1485	/* /proc/<pid>/... */
1486	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1487	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1488	    NULL, NULL, NULL, PFS_RD);
1489	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1490	    NULL, NULL, NULL, 0);
1491	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1492	    NULL, NULL, NULL, PFS_RD);
1493	pfs_create_link(dir, "exe", &procfs_doprocfile,
1494	    NULL, &procfs_notsystem, NULL, 0);
1495	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1496	    NULL, NULL, NULL, PFS_RD);
1497	pfs_create_file(dir, "mem", &procfs_doprocmem,
1498	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1499	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1500	    NULL, NULL, NULL, 0);
1501	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1502	    NULL, NULL, NULL, PFS_RD);
1503	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1504	    NULL, NULL, NULL, PFS_RD);
1505	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1506	    NULL, NULL, NULL, PFS_RD);
1507	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1508	    NULL, NULL, NULL, 0);
1509
1510	/* /proc/scsi/... */
1511	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1512	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1513	    NULL, NULL, NULL, PFS_RD);
1514	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1515	    NULL, NULL, NULL, PFS_RD);
1516
1517	/* /proc/sys/... */
1518	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1519	/* /proc/sys/kernel/... */
1520	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1521	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1522	    NULL, NULL, NULL, PFS_RD);
1523	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1524	    NULL, NULL, NULL, PFS_RD);
1525	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1526	    NULL, NULL, NULL, PFS_RD);
1527	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1528	    NULL, NULL, NULL, PFS_RD);
1529	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1530	    NULL, NULL, NULL, PFS_RD);
1531	pfs_create_file(dir, "sem", &linprocfs_dosem,
1532	    NULL, NULL, NULL, PFS_RD);
1533
1534	return (0);
1535}
1536
1537/*
1538 * Destructor
1539 */
1540static int
1541linprocfs_uninit(PFS_INIT_ARGS)
1542{
1543
1544	/* nothing to do, pseudofs will GC */
1545	return (0);
1546}
1547
1548PSEUDOFS(linprocfs, 1);
1549MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1550MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1551MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1552MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1553