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