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