linprocfs.c revision 299221
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 299221 2016-05-07 19:05:39Z 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/resource.h>
67#include <sys/sbuf.h>
68#include <sys/sem.h>
69#include <sys/smp.h>
70#include <sys/socket.h>
71#include <sys/sysctl.h>
72#include <sys/sysent.h>
73#include <sys/systm.h>
74#include <sys/time.h>
75#include <sys/tty.h>
76#include <sys/user.h>
77#include <sys/uuid.h>
78#include <sys/vmmeter.h>
79#include <sys/vnode.h>
80#include <sys/bus.h>
81
82#include <net/if.h>
83#include <net/if_types.h>
84
85#include <vm/vm.h>
86#include <vm/vm_extern.h>
87#include <vm/pmap.h>
88#include <vm/vm_map.h>
89#include <vm/vm_param.h>
90#include <vm/vm_object.h>
91#include <vm/swap_pager.h>
92
93#include <machine/clock.h>
94
95#include <geom/geom.h>
96#include <geom/geom_int.h>
97
98#if defined(__i386__) || defined(__amd64__)
99#include <machine/cputypes.h>
100#include <machine/md_var.h>
101#endif /* __i386__ || __amd64__ */
102
103#include <compat/linux/linux.h>
104#include <compat/linux/linux_mib.h>
105#include <compat/linux/linux_misc.h>
106#include <compat/linux/linux_util.h>
107#include <fs/pseudofs/pseudofs.h>
108#include <fs/procfs/procfs.h>
109
110/*
111 * Various conversion macros
112 */
113#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to jiffies */
114#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))	/* ticks to centiseconds */
115#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
116#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
117#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
118#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
119#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
120#define TV2J(x)	((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
121
122/**
123 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
124 *
125 * The linux procfs state field displays one of the characters RSDZTW to
126 * denote running, sleeping in an interruptible wait, waiting in an
127 * uninterruptible disk sleep, a zombie process, process is being traced
128 * or stopped, or process is paging respectively.
129 *
130 * Our struct kinfo_proc contains the variable ki_stat which contains a
131 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
132 *
133 * This character array is used with ki_stati-1 as an index and tries to
134 * map our states to suitable linux states.
135 */
136static char linux_state[] = "RRSTZDD";
137
138/*
139 * Filler function for proc/meminfo
140 */
141static int
142linprocfs_domeminfo(PFS_FILL_ARGS)
143{
144	unsigned long memtotal;		/* total memory in bytes */
145	unsigned long memused;		/* used memory in bytes */
146	unsigned long memfree;		/* free memory in bytes */
147	unsigned long memshared;	/* shared memory ??? */
148	unsigned long buffers, cached;	/* buffer / cache memory ??? */
149	unsigned long long swaptotal;	/* total swap space in bytes */
150	unsigned long long swapused;	/* used swap space in bytes */
151	unsigned long long swapfree;	/* free swap space in bytes */
152	vm_object_t object;
153	int i, j;
154
155	memtotal = physmem * PAGE_SIZE;
156	/*
157	 * The correct thing here would be:
158	 *
159	memfree = cnt.v_free_count * PAGE_SIZE;
160	memused = memtotal - memfree;
161	 *
162	 * but it might mislead linux binaries into thinking there
163	 * is very little memory left, so we cheat and tell them that
164	 * all memory that isn't wired down is free.
165	 */
166	memused = cnt.v_wire_count * PAGE_SIZE;
167	memfree = memtotal - memused;
168	swap_pager_status(&i, &j);
169	swaptotal = (unsigned long long)i * PAGE_SIZE;
170	swapused = (unsigned long long)j * PAGE_SIZE;
171	swapfree = swaptotal - swapused;
172	memshared = 0;
173	mtx_lock(&vm_object_list_mtx);
174	TAILQ_FOREACH(object, &vm_object_list, object_list)
175		if (object->shadow_count > 1)
176			memshared += object->resident_page_count;
177	mtx_unlock(&vm_object_list_mtx);
178	memshared *= PAGE_SIZE;
179	/*
180	 * We'd love to be able to write:
181	 *
182	buffers = bufspace;
183	 *
184	 * but bufspace is internal to vfs_bio.c and we don't feel
185	 * like unstaticizing it just for linprocfs's sake.
186	 */
187	buffers = 0;
188	cached = cnt.v_cache_count * PAGE_SIZE;
189
190	sbuf_printf(sb,
191	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
192	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
193	    "Swap: %llu %llu %llu\n"
194	    "MemTotal: %9lu kB\n"
195	    "MemFree:  %9lu kB\n"
196	    "MemShared:%9lu kB\n"
197	    "Buffers:  %9lu kB\n"
198	    "Cached:   %9lu kB\n"
199	    "SwapTotal:%9llu kB\n"
200	    "SwapFree: %9llu kB\n",
201	    memtotal, memused, memfree, memshared, buffers, cached,
202	    swaptotal, swapused, swapfree,
203	    B2K(memtotal), B2K(memfree),
204	    B2K(memshared), B2K(buffers), B2K(cached),
205	    B2K(swaptotal), B2K(swapfree));
206
207	return (0);
208}
209
210#if defined(__i386__) || defined(__amd64__)
211/*
212 * Filler function for proc/cpuinfo (i386 & amd64 version)
213 */
214static int
215linprocfs_docpuinfo(PFS_FILL_ARGS)
216{
217	int hw_model[2];
218	char model[128];
219	uint64_t freq;
220	size_t size;
221	int class, fqmhz, fqkhz;
222	int i;
223
224	/*
225	 * We default the flags to include all non-conflicting flags,
226	 * and the Intel versions of conflicting flags.
227	 */
228	static char *flags[] = {
229		"fpu",	    "vme",     "de",	   "pse",      "tsc",
230		"msr",	    "pae",     "mce",	   "cx8",      "apic",
231		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
232		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
233		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
234		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
235		"3dnowext", "3dnow"
236	};
237
238	switch (cpu_class) {
239#ifdef __i386__
240	case CPUCLASS_286:
241		class = 2;
242		break;
243	case CPUCLASS_386:
244		class = 3;
245		break;
246	case CPUCLASS_486:
247		class = 4;
248		break;
249	case CPUCLASS_586:
250		class = 5;
251		break;
252	case CPUCLASS_686:
253		class = 6;
254		break;
255	default:
256		class = 0;
257		break;
258#else /* __amd64__ */
259	default:
260		class = 15;
261		break;
262#endif
263	}
264
265	hw_model[0] = CTL_HW;
266	hw_model[1] = HW_MODEL;
267	model[0] = '\0';
268	size = sizeof(model);
269	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
270		strcpy(model, "unknown");
271	for (i = 0; i < mp_ncpus; ++i) {
272		sbuf_printf(sb,
273		    "processor\t: %d\n"
274		    "vendor_id\t: %.20s\n"
275		    "cpu family\t: %u\n"
276		    "model\t\t: %u\n"
277		    "model name\t: %s\n"
278		    "stepping\t: %u\n\n",
279		    i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
280		    CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
281		/* XXX per-cpu vendor / class / model / id? */
282	}
283
284	sbuf_cat(sb, "flags\t\t:");
285
286#ifdef __i386__
287	switch (cpu_vendor_id) {
288	case CPU_VENDOR_AMD:
289		if (class < 6)
290			flags[16] = "fcmov";
291		break;
292	case CPU_VENDOR_CYRIX:
293		flags[24] = "cxmmx";
294		break;
295	}
296#endif
297
298	for (i = 0; i < 32; i++)
299		if (cpu_feature & (1 << i))
300			sbuf_printf(sb, " %s", flags[i]);
301	sbuf_cat(sb, "\n");
302	freq = atomic_load_acq_64(&tsc_freq);
303	if (freq != 0) {
304		fqmhz = (freq + 4999) / 1000000;
305		fqkhz = ((freq + 4999) / 10000) % 100;
306		sbuf_printf(sb,
307		    "cpu MHz\t\t: %d.%02d\n"
308		    "bogomips\t: %d.%02d\n",
309		    fqmhz, fqkhz, fqmhz, fqkhz);
310	}
311
312	return (0);
313}
314#endif /* __i386__ || __amd64__ */
315
316/*
317 * Filler function for proc/mtab
318 *
319 * This file doesn't exist in Linux' procfs, but is included here so
320 * users can symlink /compat/linux/etc/mtab to /proc/mtab
321 */
322static int
323linprocfs_domtab(PFS_FILL_ARGS)
324{
325	struct nameidata nd;
326	struct mount *mp;
327	const char *lep;
328	char *dlep, *flep, *mntto, *mntfrom, *fstype;
329	size_t lep_len;
330	int error;
331
332	/* resolve symlinks etc. in the emulation tree prefix */
333	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
334	flep = NULL;
335	error = namei(&nd);
336	lep = linux_emul_path;
337	if (error == 0) {
338		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
339			lep = dlep;
340		vrele(nd.ni_vp);
341	}
342	lep_len = strlen(lep);
343
344	mtx_lock(&mountlist_mtx);
345	error = 0;
346	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
347		/* determine device name */
348		mntfrom = mp->mnt_stat.f_mntfromname;
349
350		/* determine mount point */
351		mntto = mp->mnt_stat.f_mntonname;
352		if (strncmp(mntto, lep, lep_len) == 0 &&
353		    mntto[lep_len] == '/')
354			mntto += lep_len;
355
356		/* determine fs type */
357		fstype = mp->mnt_stat.f_fstypename;
358		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
359			mntfrom = fstype = "proc";
360		else if (strcmp(fstype, "procfs") == 0)
361			continue;
362
363		if (strcmp(fstype, "linsysfs") == 0) {
364			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
365			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
366		} else {
367			/* For Linux msdosfs is called vfat */
368			if (strcmp(fstype, "msdosfs") == 0)
369				fstype = "vfat";
370			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
371			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
372		}
373#define ADD_OPTION(opt, name) \
374	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
375		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
376		ADD_OPTION(MNT_NOEXEC,		"noexec");
377		ADD_OPTION(MNT_NOSUID,		"nosuid");
378		ADD_OPTION(MNT_UNION,		"union");
379		ADD_OPTION(MNT_ASYNC,		"async");
380		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
381		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
382		ADD_OPTION(MNT_NOATIME,		"noatime");
383#undef ADD_OPTION
384		/* a real Linux mtab will also show NFS options */
385		sbuf_printf(sb, " 0 0\n");
386	}
387	mtx_unlock(&mountlist_mtx);
388	free(flep, M_TEMP);
389	return (error);
390}
391
392/*
393 * Filler function for proc/partitions
394 */
395static int
396linprocfs_dopartitions(PFS_FILL_ARGS)
397{
398	struct g_class *cp;
399	struct g_geom *gp;
400	struct g_provider *pp;
401	int major, minor;
402
403	g_topology_lock();
404	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
405	    "ruse wio wmerge wsect wuse running use aveq\n");
406
407	LIST_FOREACH(cp, &g_classes, class) {
408		if (strcmp(cp->name, "DISK") == 0 ||
409		    strcmp(cp->name, "PART") == 0)
410			LIST_FOREACH(gp, &cp->geom, geom) {
411				LIST_FOREACH(pp, &gp->provider, provider) {
412					if (linux_driver_get_major_minor(
413					    pp->name, &major, &minor) != 0) {
414						major = 0;
415						minor = 0;
416					}
417					sbuf_printf(sb, "%d %d %lld %s "
418					    "%d %d %d %d %d "
419					     "%d %d %d %d %d %d\n",
420					     major, minor,
421					     (long long)pp->mediasize, pp->name,
422					     0, 0, 0, 0, 0,
423					     0, 0, 0, 0, 0, 0);
424				}
425			}
426	}
427	g_topology_unlock();
428
429	return (0);
430}
431
432
433/*
434 * Filler function for proc/stat
435 */
436static int
437linprocfs_dostat(PFS_FILL_ARGS)
438{
439	struct pcpu *pcpu;
440	long cp_time[CPUSTATES];
441	long *cp;
442	int i;
443
444	read_cpu_time(cp_time);
445	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
446	    T2J(cp_time[CP_USER]),
447	    T2J(cp_time[CP_NICE]),
448	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
449	    T2J(cp_time[CP_IDLE]));
450	CPU_FOREACH(i) {
451		pcpu = pcpu_find(i);
452		cp = pcpu->pc_cp_time;
453		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
454		    T2J(cp[CP_USER]),
455		    T2J(cp[CP_NICE]),
456		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
457		    T2J(cp[CP_IDLE]));
458	}
459	sbuf_printf(sb,
460	    "disk 0 0 0 0\n"
461	    "page %u %u\n"
462	    "swap %u %u\n"
463	    "intr %u\n"
464	    "ctxt %u\n"
465	    "btime %lld\n",
466	    cnt.v_vnodepgsin,
467	    cnt.v_vnodepgsout,
468	    cnt.v_swappgsin,
469	    cnt.v_swappgsout,
470	    cnt.v_intr,
471	    cnt.v_swtch,
472	    (long long)boottime.tv_sec);
473	return (0);
474}
475
476static int
477linprocfs_doswaps(PFS_FILL_ARGS)
478{
479	struct xswdev xsw;
480	uintmax_t total, used;
481	int n;
482	char devname[SPECNAMELEN + 1];
483
484	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
485	mtx_lock(&Giant);
486	for (n = 0; ; n++) {
487		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
488			break;
489		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
490		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
491
492		/*
493		 * The space and not tab after the device name is on
494		 * purpose.  Linux does so.
495		 */
496		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
497		    devname, total, used);
498	}
499	mtx_unlock(&Giant);
500	return (0);
501}
502
503/*
504 * Filler function for proc/uptime
505 */
506static int
507linprocfs_douptime(PFS_FILL_ARGS)
508{
509	long cp_time[CPUSTATES];
510	struct timeval tv;
511
512	getmicrouptime(&tv);
513	read_cpu_time(cp_time);
514	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
515	    (long long)tv.tv_sec, tv.tv_usec / 10000,
516	    T2S(cp_time[CP_IDLE] / mp_ncpus),
517	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
518	return (0);
519}
520
521/*
522 * Get OS build date
523 */
524static void
525linprocfs_osbuild(struct thread *td, struct sbuf *sb)
526{
527#if 0
528	char osbuild[256];
529	char *cp1, *cp2;
530
531	strncpy(osbuild, version, 256);
532	osbuild[255] = '\0';
533	cp1 = strstr(osbuild, "\n");
534	cp2 = strstr(osbuild, ":");
535	if (cp1 && cp2) {
536		*cp1 = *cp2 = '\0';
537		cp1 = strstr(osbuild, "#");
538	} else
539		cp1 = NULL;
540	if (cp1)
541		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
542	else
543#endif
544		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
545}
546
547/*
548 * Get OS builder
549 */
550static void
551linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
552{
553#if 0
554	char builder[256];
555	char *cp;
556
557	cp = strstr(version, "\n    ");
558	if (cp) {
559		strncpy(builder, cp + 5, 256);
560		builder[255] = '\0';
561		cp = strstr(builder, ":");
562		if (cp)
563			*cp = '\0';
564	}
565	if (cp)
566		sbuf_cat(sb, builder);
567	else
568#endif
569		sbuf_cat(sb, "des@freebsd.org");
570}
571
572/*
573 * Filler function for proc/version
574 */
575static int
576linprocfs_doversion(PFS_FILL_ARGS)
577{
578	char osname[LINUX_MAX_UTSNAME];
579	char osrelease[LINUX_MAX_UTSNAME];
580
581	linux_get_osname(td, osname);
582	linux_get_osrelease(td, osrelease);
583	sbuf_printf(sb, "%s version %s (", osname, osrelease);
584	linprocfs_osbuilder(td, sb);
585	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
586	linprocfs_osbuild(td, sb);
587	sbuf_cat(sb, "\n");
588
589	return (0);
590}
591
592/*
593 * Filler function for proc/loadavg
594 */
595static int
596linprocfs_doloadavg(PFS_FILL_ARGS)
597{
598
599	sbuf_printf(sb,
600	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
601	    (int)(averunnable.ldavg[0] / averunnable.fscale),
602	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
603	    (int)(averunnable.ldavg[1] / averunnable.fscale),
604	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
605	    (int)(averunnable.ldavg[2] / averunnable.fscale),
606	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
607	    1,				/* number of running tasks */
608	    nprocs,			/* number of tasks */
609	    lastpid			/* the last pid */
610	);
611	return (0);
612}
613
614/*
615 * Filler function for proc/pid/stat
616 */
617static int
618linprocfs_doprocstat(PFS_FILL_ARGS)
619{
620	struct kinfo_proc kp;
621	char state;
622	static int ratelimit = 0;
623	vm_offset_t startcode, startdata;
624
625	PROC_LOCK(p);
626	fill_kinfo_proc(p, &kp);
627	if (p->p_vmspace) {
628	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
629	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
630	} else {
631	   startcode = 0;
632	   startdata = 0;
633	};
634	sbuf_printf(sb, "%d", p->p_pid);
635#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
636	PS_ADD("comm",		"(%s)",	p->p_comm);
637	if (kp.ki_stat > sizeof(linux_state)) {
638		state = 'R';
639
640		if (ratelimit == 0) {
641			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
642			    kp.ki_stat, sizeof(linux_state));
643			++ratelimit;
644		}
645	} else
646		state = linux_state[kp.ki_stat - 1];
647	PS_ADD("state",		"%c",	state);
648	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
649	PS_ADD("pgrp",		"%d",	p->p_pgid);
650	PS_ADD("session",	"%d",	p->p_session->s_sid);
651	PROC_UNLOCK(p);
652	PS_ADD("tty",		"%d",	kp.ki_tdev);
653	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
654	PS_ADD("flags",		"%u",	0); /* XXX */
655	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
656	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
657	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
658	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
659	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
660	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
661	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
662	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
663	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
664	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
665	PS_ADD("0",		"%d",	0); /* removed field */
666	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
667	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
668	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
669	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
670	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
671	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
672	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
673	PS_ADD("startstack",	"%u",	0); /* XXX */
674	PS_ADD("kstkesp",	"%u",	0); /* XXX */
675	PS_ADD("kstkeip",	"%u",	0); /* XXX */
676	PS_ADD("signal",	"%u",	0); /* XXX */
677	PS_ADD("blocked",	"%u",	0); /* XXX */
678	PS_ADD("sigignore",	"%u",	0); /* XXX */
679	PS_ADD("sigcatch",	"%u",	0); /* XXX */
680	PS_ADD("wchan",		"%u",	0); /* XXX */
681	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
682	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
683	PS_ADD("exitsignal",	"%d",	0); /* XXX */
684	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
685	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
686	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
687#undef PS_ADD
688	sbuf_putc(sb, '\n');
689
690	return (0);
691}
692
693/*
694 * Filler function for proc/pid/statm
695 */
696static int
697linprocfs_doprocstatm(PFS_FILL_ARGS)
698{
699	struct kinfo_proc kp;
700	segsz_t lsize;
701
702	PROC_LOCK(p);
703	fill_kinfo_proc(p, &kp);
704	PROC_UNLOCK(p);
705
706	/*
707	 * See comments in linprocfs_doprocstatus() regarding the
708	 * computation of lsize.
709	 */
710	/* size resident share trs drs lrs dt */
711	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
712	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
713	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
714	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
715	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
716	lsize = B2P(kp.ki_size) - kp.ki_dsize -
717	    kp.ki_ssize - kp.ki_tsize - 1;
718	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
719	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
720
721	return (0);
722}
723
724/*
725 * Filler function for proc/pid/status
726 */
727static int
728linprocfs_doprocstatus(PFS_FILL_ARGS)
729{
730	struct kinfo_proc kp;
731	char *state;
732	segsz_t lsize;
733	struct thread *td2;
734	struct sigacts *ps;
735	l_sigset_t siglist, sigignore, sigcatch;
736	int i;
737
738	PROC_LOCK(p);
739	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
740
741	if (P_SHOULDSTOP(p)) {
742		state = "T (stopped)";
743	} else {
744		switch(p->p_state) {
745		case PRS_NEW:
746			state = "I (idle)";
747			break;
748		case PRS_NORMAL:
749			if (p->p_flag & P_WEXIT) {
750				state = "X (exiting)";
751				break;
752			}
753			switch(td2->td_state) {
754			case TDS_INHIBITED:
755				state = "S (sleeping)";
756				break;
757			case TDS_RUNQ:
758			case TDS_RUNNING:
759				state = "R (running)";
760				break;
761			default:
762				state = "? (unknown)";
763				break;
764			}
765			break;
766		case PRS_ZOMBIE:
767			state = "Z (zombie)";
768			break;
769		default:
770			state = "? (unknown)";
771			break;
772		}
773	}
774
775	fill_kinfo_proc(p, &kp);
776	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
777	sbuf_printf(sb, "State:\t%s\n",		state);
778
779	/*
780	 * Credentials
781	 */
782	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
783	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
784						p->p_pptr->p_pid : 0);
785	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
786						p->p_ucred->cr_uid,
787						p->p_ucred->cr_svuid,
788						/* FreeBSD doesn't have fsuid */
789						p->p_ucred->cr_uid);
790	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
791						p->p_ucred->cr_gid,
792						p->p_ucred->cr_svgid,
793						/* FreeBSD doesn't have fsgid */
794						p->p_ucred->cr_gid);
795	sbuf_cat(sb, "Groups:\t");
796	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
797		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
798	PROC_UNLOCK(p);
799	sbuf_putc(sb, '\n');
800
801	/*
802	 * Memory
803	 *
804	 * While our approximation of VmLib may not be accurate (I
805	 * don't know of a simple way to verify it, and I'm not sure
806	 * it has much meaning anyway), I believe it's good enough.
807	 *
808	 * The same code that could (I think) accurately compute VmLib
809	 * could also compute VmLck, but I don't really care enough to
810	 * implement it. Submissions are welcome.
811	 */
812	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
813	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
814	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
815	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
816	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
817	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
818	lsize = B2P(kp.ki_size) - kp.ki_dsize -
819	    kp.ki_ssize - kp.ki_tsize - 1;
820	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
821
822	/*
823	 * Signal masks
824	 */
825	PROC_LOCK(p);
826	bsd_to_linux_sigset(&p->p_siglist, &siglist);
827	ps = p->p_sigacts;
828	mtx_lock(&ps->ps_mtx);
829	bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
830	bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
831	mtx_unlock(&ps->ps_mtx);
832	PROC_UNLOCK(p);
833
834	sbuf_printf(sb, "SigPnd:\t%016jx\n",	siglist.__mask);
835	/*
836	 * XXX. SigBlk - target thread's signal mask, td_sigmask.
837	 * To implement SigBlk pseudofs should support proc/tid dir entries.
838	 */
839	sbuf_printf(sb, "SigBlk:\t%016x\n",	0);
840	sbuf_printf(sb, "SigIgn:\t%016jx\n",	sigignore.__mask);
841	sbuf_printf(sb, "SigCgt:\t%016jx\n",	sigcatch.__mask);
842
843	/*
844	 * Linux also prints the capability masks, but we don't have
845	 * capabilities yet, and when we do get them they're likely to
846	 * be meaningless to Linux programs, so we lie. XXX
847	 */
848	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
849	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
850	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
851
852	return (0);
853}
854
855
856/*
857 * Filler function for proc/pid/cwd
858 */
859static int
860linprocfs_doproccwd(PFS_FILL_ARGS)
861{
862	struct filedesc *fdp;
863	struct vnode *vp;
864	char *fullpath = "unknown";
865	char *freepath = NULL;
866
867	fdp = p->p_fd;
868	FILEDESC_SLOCK(fdp);
869	vp = fdp->fd_cdir;
870	if (vp != NULL)
871		VREF(vp);
872	FILEDESC_SUNLOCK(fdp);
873	vn_fullpath(td, vp, &fullpath, &freepath);
874	if (vp != NULL)
875		vrele(vp);
876	sbuf_printf(sb, "%s", fullpath);
877	if (freepath)
878		free(freepath, M_TEMP);
879	return (0);
880}
881
882/*
883 * Filler function for proc/pid/root
884 */
885static int
886linprocfs_doprocroot(PFS_FILL_ARGS)
887{
888	struct filedesc *fdp;
889	struct vnode *vp;
890	char *fullpath = "unknown";
891	char *freepath = NULL;
892
893	fdp = p->p_fd;
894	FILEDESC_SLOCK(fdp);
895	vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
896	if (vp != NULL)
897		VREF(vp);
898	FILEDESC_SUNLOCK(fdp);
899	vn_fullpath(td, vp, &fullpath, &freepath);
900	if (vp != NULL)
901		vrele(vp);
902	sbuf_printf(sb, "%s", fullpath);
903	if (freepath)
904		free(freepath, M_TEMP);
905	return (0);
906}
907
908/*
909 * Filler function for proc/pid/cmdline
910 */
911static int
912linprocfs_doproccmdline(PFS_FILL_ARGS)
913{
914	int ret;
915
916	PROC_LOCK(p);
917	if ((ret = p_cansee(td, p)) != 0) {
918		PROC_UNLOCK(p);
919		return (ret);
920	}
921
922	/*
923	 * Mimic linux behavior and pass only processes with usermode
924	 * address space as valid.  Return zero silently otherwize.
925	 */
926	if (p->p_vmspace == &vmspace0) {
927		PROC_UNLOCK(p);
928		return (0);
929	}
930	if (p->p_args != NULL) {
931		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
932		PROC_UNLOCK(p);
933		return (0);
934	}
935
936	if ((p->p_flag & P_SYSTEM) != 0) {
937		PROC_UNLOCK(p);
938		return (0);
939	}
940
941	PROC_UNLOCK(p);
942
943	ret = proc_getargv(td, p, sb);
944	return (ret);
945}
946
947/*
948 * Filler function for proc/pid/environ
949 */
950static int
951linprocfs_doprocenviron(PFS_FILL_ARGS)
952{
953
954	/*
955	 * Mimic linux behavior and pass only processes with usermode
956	 * address space as valid.  Return zero silently otherwize.
957	 */
958	if (p->p_vmspace == &vmspace0)
959		return (0);
960
961	return (proc_getenvv(td, p, sb));
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 * Filler function for proc/pid/limits
1356 */
1357static const struct linux_rlimit_ident {
1358	const char	*desc;
1359	const char	*unit;
1360	unsigned int	rlim_id;
1361} linux_rlimits_ident[] = {
1362	{ "Max cpu time",	"seconds",	RLIMIT_CPU },
1363	{ "Max file size", 	"bytes",	RLIMIT_FSIZE },
1364	{ "Max data size",	"bytes", 	RLIMIT_DATA },
1365	{ "Max stack size",	"bytes", 	RLIMIT_STACK },
1366	{ "Max core file size",  "bytes",	RLIMIT_CORE },
1367	{ "Max resident set",	"bytes",	RLIMIT_RSS },
1368	{ "Max processes",	"processes",	RLIMIT_NPROC },
1369	{ "Max open files",	"files",	RLIMIT_NOFILE },
1370	{ "Max locked memory",	"bytes",	RLIMIT_MEMLOCK },
1371	{ "Max address space",	"bytes",	RLIMIT_AS },
1372	{ "Max file locks",	"locks",	LINUX_RLIMIT_LOCKS },
1373	{ "Max pending signals", "signals",	LINUX_RLIMIT_SIGPENDING },
1374	{ "Max msgqueue size",	"bytes",	LINUX_RLIMIT_MSGQUEUE },
1375	{ "Max nice priority", 		"",	LINUX_RLIMIT_NICE },
1376	{ "Max realtime priority",	"",	LINUX_RLIMIT_RTPRIO },
1377	{ "Max realtime timeout",	"us",	LINUX_RLIMIT_RTTIME },
1378	{ 0, 0, 0 }
1379};
1380
1381static int
1382linprocfs_doproclimits(PFS_FILL_ARGS)
1383{
1384	const struct linux_rlimit_ident *li;
1385	struct plimit *limp;
1386	struct rlimit rl;
1387	ssize_t size;
1388	int res, error;
1389
1390	error = 0;
1391
1392	PROC_LOCK(p);
1393	limp = lim_hold(p->p_limit);
1394	PROC_UNLOCK(p);
1395	size = sizeof(res);
1396	sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1397			"Hard Limit", "Units");
1398	for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1399		switch (li->rlim_id)
1400		{
1401		case LINUX_RLIMIT_LOCKS:
1402			/* FALLTHROUGH */
1403		case LINUX_RLIMIT_RTTIME:
1404			rl.rlim_cur = RLIM_INFINITY;
1405			break;
1406		case LINUX_RLIMIT_SIGPENDING:
1407			error = kernel_sysctlbyname(td,
1408			    "kern.sigqueue.max_pending_per_proc",
1409			    &res, &size, 0, 0, 0, 0);
1410			if (error != 0)
1411				goto out;
1412			rl.rlim_cur = res;
1413			rl.rlim_max = res;
1414			break;
1415		case LINUX_RLIMIT_MSGQUEUE:
1416			error = kernel_sysctlbyname(td,
1417			    "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1418			if (error != 0)
1419				goto out;
1420			rl.rlim_cur = res;
1421			rl.rlim_max = res;
1422			break;
1423		case LINUX_RLIMIT_NICE:
1424			/* FALLTHROUGH */
1425		case LINUX_RLIMIT_RTPRIO:
1426			rl.rlim_cur = 0;
1427			rl.rlim_max = 0;
1428			break;
1429		default:
1430			rl = limp->pl_rlimit[li->rlim_id];
1431			break;
1432		}
1433		if (rl.rlim_cur == RLIM_INFINITY)
1434			sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1435			    li->desc, "unlimited", "unlimited", li->unit);
1436		else
1437			sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1438			    li->desc, (unsigned long long)rl.rlim_cur,
1439			    (unsigned long long)rl.rlim_max, li->unit);
1440	}
1441out:
1442	lim_free(limp);
1443	return (error);
1444}
1445
1446/*
1447 * Filler function for proc/sys/kernel/random/uuid
1448 */
1449static int
1450linprocfs_douuid(PFS_FILL_ARGS)
1451{
1452	struct uuid uuid;
1453
1454	kern_uuidgen(&uuid, 1);
1455	sbuf_printf_uuid(sb, &uuid);
1456	sbuf_printf(sb, "\n");
1457	return(0);
1458}
1459
1460/*
1461 * Filler function for proc/pid/auxv
1462 */
1463static int
1464linprocfs_doauxv(PFS_FILL_ARGS)
1465{
1466	struct sbuf *asb;
1467	off_t buflen, resid;
1468	int error;
1469
1470	/*
1471	 * Mimic linux behavior and pass only processes with usermode
1472	 * address space as valid. Return zero silently otherwise.
1473	 */
1474	if (p->p_vmspace == &vmspace0)
1475		return (0);
1476
1477	if (uio->uio_resid == 0)
1478		return (0);
1479	if (uio->uio_offset < 0 || uio->uio_resid < 0)
1480		return (EINVAL);
1481
1482	asb = sbuf_new_auto();
1483	if (asb == NULL)
1484		return (ENOMEM);
1485	error = proc_getauxv(td, p, asb);
1486	if (error == 0)
1487		error = sbuf_finish(asb);
1488
1489	resid = sbuf_len(asb) - uio->uio_offset;
1490	if (resid > uio->uio_resid)
1491		buflen = uio->uio_resid;
1492	else
1493		buflen = resid;
1494	if (buflen > IOSIZE_MAX)
1495		return (EINVAL);
1496	if (buflen > MAXPHYS)
1497		buflen = MAXPHYS;
1498	if (resid <= 0)
1499		return (0);
1500
1501	if (error == 0)
1502		error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1503	sbuf_delete(asb);
1504	return (error);
1505}
1506
1507/*
1508 * Constructor
1509 */
1510static int
1511linprocfs_init(PFS_INIT_ARGS)
1512{
1513	struct pfs_node *root;
1514	struct pfs_node *dir;
1515
1516	root = pi->pi_root;
1517
1518	/* /proc/... */
1519	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1520	    NULL, NULL, NULL, PFS_RD);
1521	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1522	    NULL, NULL, NULL, PFS_RD);
1523	pfs_create_file(root, "devices", &linprocfs_dodevices,
1524	    NULL, NULL, NULL, PFS_RD);
1525	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1526	    NULL, NULL, NULL, PFS_RD);
1527	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1528	    NULL, NULL, NULL, PFS_RD);
1529	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1530	    NULL, NULL, NULL, PFS_RD);
1531#if 0
1532	pfs_create_file(root, "modules", &linprocfs_domodules,
1533	    NULL, NULL, NULL, PFS_RD);
1534#endif
1535	pfs_create_file(root, "mounts", &linprocfs_domtab,
1536	    NULL, NULL, NULL, PFS_RD);
1537	pfs_create_file(root, "mtab", &linprocfs_domtab,
1538	    NULL, NULL, NULL, PFS_RD);
1539	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1540	    NULL, NULL, NULL, PFS_RD);
1541	pfs_create_link(root, "self", &procfs_docurproc,
1542	    NULL, NULL, NULL, 0);
1543	pfs_create_file(root, "stat", &linprocfs_dostat,
1544	    NULL, NULL, NULL, PFS_RD);
1545	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1546	    NULL, NULL, NULL, PFS_RD);
1547	pfs_create_file(root, "uptime", &linprocfs_douptime,
1548	    NULL, NULL, NULL, PFS_RD);
1549	pfs_create_file(root, "version", &linprocfs_doversion,
1550	    NULL, NULL, NULL, PFS_RD);
1551
1552	/* /proc/net/... */
1553	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1554	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1555	    NULL, NULL, NULL, PFS_RD);
1556
1557	/* /proc/<pid>/... */
1558	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1559	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1560	    NULL, NULL, NULL, PFS_RD);
1561	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1562	    NULL, NULL, NULL, 0);
1563	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1564	    NULL, &procfs_candebug, NULL, PFS_RD);
1565	pfs_create_link(dir, "exe", &procfs_doprocfile,
1566	    NULL, &procfs_notsystem, NULL, 0);
1567	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1568	    NULL, NULL, NULL, PFS_RD);
1569	pfs_create_file(dir, "mem", &procfs_doprocmem,
1570	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1571	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1572	    NULL, NULL, NULL, 0);
1573	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1574	    NULL, NULL, NULL, PFS_RD);
1575	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1576	    NULL, NULL, NULL, PFS_RD);
1577	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1578	    NULL, NULL, NULL, PFS_RD);
1579	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1580	    NULL, NULL, NULL, 0);
1581	pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1582	    NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1583	pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1584	    NULL, NULL, NULL, PFS_RD);
1585
1586	/* /proc/scsi/... */
1587	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1588	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1589	    NULL, NULL, NULL, PFS_RD);
1590	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1591	    NULL, NULL, NULL, PFS_RD);
1592
1593	/* /proc/sys/... */
1594	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1595	/* /proc/sys/kernel/... */
1596	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1597	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1598	    NULL, NULL, NULL, PFS_RD);
1599	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1600	    NULL, NULL, NULL, PFS_RD);
1601	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1602	    NULL, NULL, NULL, PFS_RD);
1603	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1604	    NULL, NULL, NULL, PFS_RD);
1605	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1606	    NULL, NULL, NULL, PFS_RD);
1607	pfs_create_file(dir, "sem", &linprocfs_dosem,
1608	    NULL, NULL, NULL, PFS_RD);
1609
1610	/* /proc/sys/kernel/random/... */
1611	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1612	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1613	    NULL, NULL, NULL, PFS_RD);
1614
1615	return (0);
1616}
1617
1618/*
1619 * Destructor
1620 */
1621static int
1622linprocfs_uninit(PFS_INIT_ARGS)
1623{
1624
1625	/* nothing to do, pseudofs will GC */
1626	return (0);
1627}
1628
1629PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1630#if defined(__amd64__)
1631MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1632#else
1633MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1634#endif
1635MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1636MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1637MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1638