linprocfs.c revision 293576
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 293576 2016-01-09 17:30:10Z 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	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 * Filler function for proc/pid/auxv
1369 */
1370static int
1371linprocfs_doauxv(PFS_FILL_ARGS)
1372{
1373	struct sbuf *asb;
1374	off_t buflen, resid;
1375	int error;
1376
1377	/*
1378	 * Mimic linux behavior and pass only processes with usermode
1379	 * address space as valid. Return zero silently otherwise.
1380	 */
1381	if (p->p_vmspace == &vmspace0)
1382		return (0);
1383
1384	if (uio->uio_resid == 0)
1385		return (0);
1386	if (uio->uio_offset < 0 || uio->uio_resid < 0)
1387		return (EINVAL);
1388
1389	asb = sbuf_new_auto();
1390	if (asb == NULL)
1391		return (ENOMEM);
1392	error = proc_getauxv(td, p, asb);
1393	if (error == 0)
1394		error = sbuf_finish(asb);
1395
1396	resid = sbuf_len(asb) - uio->uio_offset;
1397	if (resid > uio->uio_resid)
1398		buflen = uio->uio_resid;
1399	else
1400		buflen = resid;
1401	if (buflen > IOSIZE_MAX)
1402		return (EINVAL);
1403	if (buflen > MAXPHYS)
1404		buflen = MAXPHYS;
1405	if (resid <= 0)
1406		return (0);
1407
1408	if (error == 0)
1409		error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1410	sbuf_delete(asb);
1411	return (error);
1412}
1413
1414/*
1415 * Constructor
1416 */
1417static int
1418linprocfs_init(PFS_INIT_ARGS)
1419{
1420	struct pfs_node *root;
1421	struct pfs_node *dir;
1422
1423	root = pi->pi_root;
1424
1425	/* /proc/... */
1426	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1427	    NULL, NULL, NULL, PFS_RD);
1428	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1429	    NULL, NULL, NULL, PFS_RD);
1430	pfs_create_file(root, "devices", &linprocfs_dodevices,
1431	    NULL, NULL, NULL, PFS_RD);
1432	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1433	    NULL, NULL, NULL, PFS_RD);
1434	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1435	    NULL, NULL, NULL, PFS_RD);
1436	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1437	    NULL, NULL, NULL, PFS_RD);
1438#if 0
1439	pfs_create_file(root, "modules", &linprocfs_domodules,
1440	    NULL, NULL, NULL, PFS_RD);
1441#endif
1442	pfs_create_file(root, "mounts", &linprocfs_domtab,
1443	    NULL, NULL, NULL, PFS_RD);
1444	pfs_create_file(root, "mtab", &linprocfs_domtab,
1445	    NULL, NULL, NULL, PFS_RD);
1446	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1447	    NULL, NULL, NULL, PFS_RD);
1448	pfs_create_link(root, "self", &procfs_docurproc,
1449	    NULL, NULL, NULL, 0);
1450	pfs_create_file(root, "stat", &linprocfs_dostat,
1451	    NULL, NULL, NULL, PFS_RD);
1452	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1453	    NULL, NULL, NULL, PFS_RD);
1454	pfs_create_file(root, "uptime", &linprocfs_douptime,
1455	    NULL, NULL, NULL, PFS_RD);
1456	pfs_create_file(root, "version", &linprocfs_doversion,
1457	    NULL, NULL, NULL, PFS_RD);
1458
1459	/* /proc/net/... */
1460	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1461	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1462	    NULL, NULL, NULL, PFS_RD);
1463
1464	/* /proc/<pid>/... */
1465	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1466	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1467	    NULL, NULL, NULL, PFS_RD);
1468	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1469	    NULL, NULL, NULL, 0);
1470	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1471	    NULL, NULL, NULL, PFS_RD);
1472	pfs_create_link(dir, "exe", &procfs_doprocfile,
1473	    NULL, &procfs_notsystem, NULL, 0);
1474	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1475	    NULL, NULL, NULL, PFS_RD);
1476	pfs_create_file(dir, "mem", &procfs_doprocmem,
1477	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1478	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1479	    NULL, NULL, NULL, 0);
1480	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1481	    NULL, NULL, NULL, PFS_RD);
1482	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1483	    NULL, NULL, NULL, PFS_RD);
1484	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1485	    NULL, NULL, NULL, PFS_RD);
1486	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1487	    NULL, NULL, NULL, 0);
1488	pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1489	    NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1490
1491	/* /proc/scsi/... */
1492	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1493	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1494	    NULL, NULL, NULL, PFS_RD);
1495	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1496	    NULL, NULL, NULL, PFS_RD);
1497
1498	/* /proc/sys/... */
1499	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1500	/* /proc/sys/kernel/... */
1501	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1502	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1503	    NULL, NULL, NULL, PFS_RD);
1504	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1505	    NULL, NULL, NULL, PFS_RD);
1506	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1507	    NULL, NULL, NULL, PFS_RD);
1508	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1509	    NULL, NULL, NULL, PFS_RD);
1510	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1511	    NULL, NULL, NULL, PFS_RD);
1512	pfs_create_file(dir, "sem", &linprocfs_dosem,
1513	    NULL, NULL, NULL, PFS_RD);
1514
1515	/* /proc/sys/kernel/random/... */
1516	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1517	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1518	    NULL, NULL, NULL, PFS_RD);
1519
1520	return (0);
1521}
1522
1523/*
1524 * Destructor
1525 */
1526static int
1527linprocfs_uninit(PFS_INIT_ARGS)
1528{
1529
1530	/* nothing to do, pseudofs will GC */
1531	return (0);
1532}
1533
1534PSEUDOFS(linprocfs, 1, 0);
1535#if defined(__amd64__)
1536MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1537#else
1538MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1539#endif
1540MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1541MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1542MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1543