linprocfs.c revision 223182
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 223182 2011-06-17 07:30:56Z pluknet $");
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
1053	/*
1054	 * Mimic linux behavior and pass only processes with usermode
1055	 * address space as valid.  Return zero silently otherwize.
1056	 */
1057	if (p->p_vmspace == &vmspace0) {
1058		PROC_UNLOCK(p);
1059		return (0);
1060	}
1061	if (p->p_args != NULL) {
1062		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1063		PROC_UNLOCK(p);
1064		return (0);
1065	}
1066	PROC_UNLOCK(p);
1067
1068	ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1069	return (ret);
1070}
1071
1072/*
1073 * Filler function for proc/pid/environ
1074 */
1075static int
1076linprocfs_doprocenviron(PFS_FILL_ARGS)
1077{
1078	int ret;
1079
1080	PROC_LOCK(p);
1081	if ((ret = p_cansee(td, p)) != 0) {
1082		PROC_UNLOCK(p);
1083		return (ret);
1084	}
1085
1086	/*
1087	 * Mimic linux behavior and pass only processes with usermode
1088	 * address space as valid.  Return zero silently otherwize.
1089	 */
1090	if (p->p_vmspace == &vmspace0) {
1091		PROC_UNLOCK(p);
1092		return (0);
1093	}
1094	PROC_UNLOCK(p);
1095
1096	ret = linprocfs_doargv(td, p, sb, ps_string_env);
1097	return (ret);
1098}
1099
1100/*
1101 * Filler function for proc/pid/maps
1102 */
1103static int
1104linprocfs_doprocmaps(PFS_FILL_ARGS)
1105{
1106	struct vmspace *vm;
1107	vm_map_t map;
1108	vm_map_entry_t entry, tmp_entry;
1109	vm_object_t obj, tobj, lobj;
1110	vm_offset_t e_start, e_end;
1111	vm_ooffset_t off = 0;
1112	vm_prot_t e_prot;
1113	unsigned int last_timestamp;
1114	char *name = "", *freename = NULL;
1115	ino_t ino;
1116	int ref_count, shadow_count, flags;
1117	int error;
1118	struct vnode *vp;
1119	struct vattr vat;
1120	int locked;
1121
1122	PROC_LOCK(p);
1123	error = p_candebug(td, p);
1124	PROC_UNLOCK(p);
1125	if (error)
1126		return (error);
1127
1128	if (uio->uio_rw != UIO_READ)
1129		return (EOPNOTSUPP);
1130
1131	error = 0;
1132	vm = vmspace_acquire_ref(p);
1133	if (vm == NULL)
1134		return (ESRCH);
1135	map = &vm->vm_map;
1136	vm_map_lock_read(map);
1137	for (entry = map->header.next; entry != &map->header;
1138	    entry = entry->next) {
1139		name = "";
1140		freename = NULL;
1141		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1142			continue;
1143		e_prot = entry->protection;
1144		e_start = entry->start;
1145		e_end = entry->end;
1146		obj = entry->object.vm_object;
1147		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1148			VM_OBJECT_LOCK(tobj);
1149			if (lobj != obj)
1150				VM_OBJECT_UNLOCK(lobj);
1151			lobj = tobj;
1152		}
1153		last_timestamp = map->timestamp;
1154		vm_map_unlock_read(map);
1155		ino = 0;
1156		if (lobj) {
1157			off = IDX_TO_OFF(lobj->size);
1158			if (lobj->type == OBJT_VNODE) {
1159				vp = lobj->handle;
1160				if (vp)
1161					vref(vp);
1162			}
1163			else
1164				vp = NULL;
1165			if (lobj != obj)
1166				VM_OBJECT_UNLOCK(lobj);
1167			flags = obj->flags;
1168			ref_count = obj->ref_count;
1169			shadow_count = obj->shadow_count;
1170			VM_OBJECT_UNLOCK(obj);
1171			if (vp) {
1172				vn_fullpath(td, vp, &name, &freename);
1173				locked = VFS_LOCK_GIANT(vp->v_mount);
1174				vn_lock(vp, LK_SHARED | LK_RETRY);
1175				VOP_GETATTR(vp, &vat, td->td_ucred);
1176				ino = vat.va_fileid;
1177				vput(vp);
1178				VFS_UNLOCK_GIANT(locked);
1179			}
1180		} else {
1181			flags = 0;
1182			ref_count = 0;
1183			shadow_count = 0;
1184		}
1185
1186		/*
1187		 * format:
1188		 *  start, end, access, offset, major, minor, inode, name.
1189		 */
1190		error = sbuf_printf(sb,
1191		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1192		    (u_long)e_start, (u_long)e_end,
1193		    (e_prot & VM_PROT_READ)?"r":"-",
1194		    (e_prot & VM_PROT_WRITE)?"w":"-",
1195		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1196		    "p",
1197		    (u_long)off,
1198		    0,
1199		    0,
1200		    (u_long)ino,
1201		    *name ? "     " : "",
1202		    name
1203		    );
1204		if (freename)
1205			free(freename, M_TEMP);
1206		vm_map_lock_read(map);
1207		if (error == -1) {
1208			error = 0;
1209			break;
1210		}
1211		if (last_timestamp != map->timestamp) {
1212			/*
1213			 * Look again for the entry because the map was
1214			 * modified while it was unlocked.  Specifically,
1215			 * the entry may have been clipped, merged, or deleted.
1216			 */
1217			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1218			entry = tmp_entry;
1219		}
1220	}
1221	vm_map_unlock_read(map);
1222	vmspace_free(vm);
1223
1224	return (error);
1225}
1226
1227/*
1228 * Filler function for proc/net/dev
1229 */
1230static int
1231linprocfs_donetdev(PFS_FILL_ARGS)
1232{
1233	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1234	struct ifnet *ifp;
1235
1236	sbuf_printf(sb, "%6s|%58s|%s\n"
1237	    "%6s|%58s|%58s\n",
1238	    "Inter-", "   Receive", "  Transmit",
1239	    " face",
1240	    "bytes    packets errs drop fifo frame compressed multicast",
1241	    "bytes    packets errs drop fifo colls carrier compressed");
1242
1243	CURVNET_SET(TD_TO_VNET(curthread));
1244	IFNET_RLOCK();
1245	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1246		linux_ifname(ifp, ifname, sizeof ifname);
1247		sbuf_printf(sb, "%6.6s: ", ifname);
1248		sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1249		    ifp->if_ibytes,	/* rx_bytes */
1250		    ifp->if_ipackets,	/* rx_packets */
1251		    ifp->if_ierrors,	/* rx_errors */
1252		    ifp->if_iqdrops,	/* rx_dropped +
1253					 * rx_missed_errors */
1254		    0UL,		/* rx_fifo_errors */
1255		    0UL,		/* rx_length_errors +
1256					 * rx_over_errors +
1257		    			 * rx_crc_errors +
1258					 * rx_frame_errors */
1259		    0UL,		/* rx_compressed */
1260		    ifp->if_imcasts);	/* multicast, XXX-BZ rx only? */
1261		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1262		    ifp->if_obytes,	/* tx_bytes */
1263		    ifp->if_opackets,	/* tx_packets */
1264		    ifp->if_oerrors,	/* tx_errors */
1265		    0UL,		/* tx_dropped */
1266		    0UL,		/* tx_fifo_errors */
1267		    ifp->if_collisions,	/* collisions */
1268		    0UL,		/* tx_carrier_errors +
1269					 * tx_aborted_errors +
1270					 * tx_window_errors +
1271					 * tx_heartbeat_errors */
1272		    0UL);		/* tx_compressed */
1273	}
1274	IFNET_RUNLOCK();
1275	CURVNET_RESTORE();
1276
1277	return (0);
1278}
1279
1280/*
1281 * Filler function for proc/sys/kernel/osrelease
1282 */
1283static int
1284linprocfs_doosrelease(PFS_FILL_ARGS)
1285{
1286	char osrelease[LINUX_MAX_UTSNAME];
1287
1288	linux_get_osrelease(td, osrelease);
1289	sbuf_printf(sb, "%s\n", osrelease);
1290
1291	return (0);
1292}
1293
1294/*
1295 * Filler function for proc/sys/kernel/ostype
1296 */
1297static int
1298linprocfs_doostype(PFS_FILL_ARGS)
1299{
1300	char osname[LINUX_MAX_UTSNAME];
1301
1302	linux_get_osname(td, osname);
1303	sbuf_printf(sb, "%s\n", osname);
1304
1305	return (0);
1306}
1307
1308/*
1309 * Filler function for proc/sys/kernel/version
1310 */
1311static int
1312linprocfs_doosbuild(PFS_FILL_ARGS)
1313{
1314
1315	linprocfs_osbuild(td, sb);
1316	sbuf_cat(sb, "\n");
1317	return (0);
1318}
1319
1320/*
1321 * Filler function for proc/sys/kernel/msgmni
1322 */
1323static int
1324linprocfs_domsgmni(PFS_FILL_ARGS)
1325{
1326
1327	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1328	return (0);
1329}
1330
1331/*
1332 * Filler function for proc/sys/kernel/pid_max
1333 */
1334static int
1335linprocfs_dopid_max(PFS_FILL_ARGS)
1336{
1337
1338	sbuf_printf(sb, "%i\n", PID_MAX);
1339	return (0);
1340}
1341
1342/*
1343 * Filler function for proc/sys/kernel/sem
1344 */
1345static int
1346linprocfs_dosem(PFS_FILL_ARGS)
1347{
1348
1349	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1350	    seminfo.semopm, seminfo.semmni);
1351	return (0);
1352}
1353
1354/*
1355 * Filler function for proc/scsi/device_info
1356 */
1357static int
1358linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1359{
1360
1361	return (0);
1362}
1363
1364/*
1365 * Filler function for proc/scsi/scsi
1366 */
1367static int
1368linprocfs_doscsiscsi(PFS_FILL_ARGS)
1369{
1370
1371	return (0);
1372}
1373
1374extern struct cdevsw *cdevsw[];
1375
1376/*
1377 * Filler function for proc/devices
1378 */
1379static int
1380linprocfs_dodevices(PFS_FILL_ARGS)
1381{
1382	char *char_devices;
1383	sbuf_printf(sb, "Character devices:\n");
1384
1385	char_devices = linux_get_char_devices();
1386	sbuf_printf(sb, "%s", char_devices);
1387	linux_free_get_char_devices(char_devices);
1388
1389	sbuf_printf(sb, "\nBlock devices:\n");
1390
1391	return (0);
1392}
1393
1394/*
1395 * Filler function for proc/cmdline
1396 */
1397static int
1398linprocfs_docmdline(PFS_FILL_ARGS)
1399{
1400
1401	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1402	sbuf_printf(sb, " ro root=302\n");
1403	return (0);
1404}
1405
1406/*
1407 * Filler function for proc/filesystems
1408 */
1409static int
1410linprocfs_dofilesystems(PFS_FILL_ARGS)
1411{
1412	struct vfsconf *vfsp;
1413
1414	mtx_lock(&Giant);
1415	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1416		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1417			sbuf_printf(sb, "nodev");
1418		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1419	}
1420	mtx_unlock(&Giant);
1421	return(0);
1422}
1423
1424#if 0
1425/*
1426 * Filler function for proc/modules
1427 */
1428static int
1429linprocfs_domodules(PFS_FILL_ARGS)
1430{
1431	struct linker_file *lf;
1432
1433	TAILQ_FOREACH(lf, &linker_files, link) {
1434		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1435		    (unsigned long)lf->size, lf->refs);
1436	}
1437	return (0);
1438}
1439#endif
1440
1441/*
1442 * Filler function for proc/pid/fd
1443 */
1444static int
1445linprocfs_dofdescfs(PFS_FILL_ARGS)
1446{
1447
1448	if (p == curproc)
1449		sbuf_printf(sb, "/dev/fd");
1450	else
1451		sbuf_printf(sb, "unknown");
1452	return (0);
1453}
1454
1455/*
1456 * Constructor
1457 */
1458static int
1459linprocfs_init(PFS_INIT_ARGS)
1460{
1461	struct pfs_node *root;
1462	struct pfs_node *dir;
1463
1464	root = pi->pi_root;
1465
1466	/* /proc/... */
1467	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1468	    NULL, NULL, NULL, PFS_RD);
1469	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1470	    NULL, NULL, NULL, PFS_RD);
1471	pfs_create_file(root, "devices", &linprocfs_dodevices,
1472	    NULL, NULL, NULL, PFS_RD);
1473	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1474	    NULL, NULL, NULL, PFS_RD);
1475	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1476	    NULL, NULL, NULL, PFS_RD);
1477	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1478	    NULL, NULL, NULL, PFS_RD);
1479#if 0
1480	pfs_create_file(root, "modules", &linprocfs_domodules,
1481	    NULL, NULL, NULL, PFS_RD);
1482#endif
1483	pfs_create_file(root, "mounts", &linprocfs_domtab,
1484	    NULL, NULL, NULL, PFS_RD);
1485	pfs_create_file(root, "mtab", &linprocfs_domtab,
1486	    NULL, NULL, NULL, PFS_RD);
1487	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1488	    NULL, NULL, NULL, PFS_RD);
1489	pfs_create_link(root, "self", &procfs_docurproc,
1490	    NULL, NULL, NULL, 0);
1491	pfs_create_file(root, "stat", &linprocfs_dostat,
1492	    NULL, NULL, NULL, PFS_RD);
1493	pfs_create_file(root, "uptime", &linprocfs_douptime,
1494	    NULL, NULL, NULL, PFS_RD);
1495	pfs_create_file(root, "version", &linprocfs_doversion,
1496	    NULL, NULL, NULL, PFS_RD);
1497
1498	/* /proc/net/... */
1499	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1500	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1501	    NULL, NULL, NULL, PFS_RD);
1502
1503	/* /proc/<pid>/... */
1504	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1505	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1506	    NULL, NULL, NULL, PFS_RD);
1507	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1508	    NULL, NULL, NULL, 0);
1509	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1510	    NULL, NULL, NULL, PFS_RD);
1511	pfs_create_link(dir, "exe", &procfs_doprocfile,
1512	    NULL, &procfs_notsystem, NULL, 0);
1513	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1514	    NULL, NULL, NULL, PFS_RD);
1515	pfs_create_file(dir, "mem", &procfs_doprocmem,
1516	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1517	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1518	    NULL, NULL, NULL, 0);
1519	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1520	    NULL, NULL, NULL, PFS_RD);
1521	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1522	    NULL, NULL, NULL, PFS_RD);
1523	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1524	    NULL, NULL, NULL, PFS_RD);
1525	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1526	    NULL, NULL, NULL, 0);
1527
1528	/* /proc/scsi/... */
1529	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1530	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1531	    NULL, NULL, NULL, PFS_RD);
1532	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1533	    NULL, NULL, NULL, PFS_RD);
1534
1535	/* /proc/sys/... */
1536	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1537	/* /proc/sys/kernel/... */
1538	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1539	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1540	    NULL, NULL, NULL, PFS_RD);
1541	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1542	    NULL, NULL, NULL, PFS_RD);
1543	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1544	    NULL, NULL, NULL, PFS_RD);
1545	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1546	    NULL, NULL, NULL, PFS_RD);
1547	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1548	    NULL, NULL, NULL, PFS_RD);
1549	pfs_create_file(dir, "sem", &linprocfs_dosem,
1550	    NULL, NULL, NULL, PFS_RD);
1551
1552	return (0);
1553}
1554
1555/*
1556 * Destructor
1557 */
1558static int
1559linprocfs_uninit(PFS_INIT_ARGS)
1560{
1561
1562	/* nothing to do, pseudofs will GC */
1563	return (0);
1564}
1565
1566PSEUDOFS(linprocfs, 1);
1567MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1568MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1569MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1570MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1571