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