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