linprocfs.c revision 304843
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/11/sys/compat/linprocfs/linprocfs.c 304843 2016-08-26 10:04:10Z kib $");
44
45#include <sys/param.h>
46#include <sys/queue.h>
47#include <sys/blist.h>
48#include <sys/conf.h>
49#include <sys/exec.h>
50#include <sys/fcntl.h>
51#include <sys/filedesc.h>
52#include <sys/jail.h>
53#include <sys/kernel.h>
54#include <sys/limits.h>
55#include <sys/linker.h>
56#include <sys/lock.h>
57#include <sys/malloc.h>
58#include <sys/msg.h>
59#include <sys/mutex.h>
60#include <sys/namei.h>
61#include <sys/proc.h>
62#include <sys/ptrace.h>
63#include <sys/resourcevar.h>
64#include <sys/resource.h>
65#include <sys/sbuf.h>
66#include <sys/sem.h>
67#include <sys/smp.h>
68#include <sys/socket.h>
69#include <sys/syscallsubr.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_var.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 = vm_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 = vm_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 = vm_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	const char *lep;
327	char *dlep, *flep, *mntto, *mntfrom, *fstype;
328	size_t lep_len;
329	int error;
330	struct statfs *buf, *sp;
331	size_t count;
332
333	/* resolve symlinks etc. in the emulation tree prefix */
334	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
335	flep = NULL;
336	error = namei(&nd);
337	lep = linux_emul_path;
338	if (error == 0) {
339		if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
340			lep = dlep;
341		vrele(nd.ni_vp);
342	}
343	lep_len = strlen(lep);
344
345	buf = NULL;
346	error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
347	    UIO_SYSSPACE, MNT_WAIT);
348	if (error != 0) {
349		free(buf, M_TEMP);
350		free(flep, M_TEMP);
351		return (error);
352	}
353
354	for (sp = buf; count > 0; sp++, count--) {
355		/* determine device name */
356		mntfrom = sp->f_mntfromname;
357
358		/* determine mount point */
359		mntto = sp->f_mntonname;
360		if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
361			mntto += lep_len;
362
363		/* determine fs type */
364		fstype = sp->f_fstypename;
365		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
366			mntfrom = fstype = "proc";
367		else if (strcmp(fstype, "procfs") == 0)
368			continue;
369
370		if (strcmp(fstype, "linsysfs") == 0) {
371			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
372			    sp->f_flags & MNT_RDONLY ? "ro" : "rw");
373		} else {
374			/* For Linux msdosfs is called vfat */
375			if (strcmp(fstype, "msdosfs") == 0)
376				fstype = "vfat";
377			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
378			    sp->f_flags & MNT_RDONLY ? "ro" : "rw");
379		}
380#define ADD_OPTION(opt, name) \
381	if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
382		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
383		ADD_OPTION(MNT_NOEXEC,		"noexec");
384		ADD_OPTION(MNT_NOSUID,		"nosuid");
385		ADD_OPTION(MNT_UNION,		"union");
386		ADD_OPTION(MNT_ASYNC,		"async");
387		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
388		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
389		ADD_OPTION(MNT_NOATIME,		"noatime");
390#undef ADD_OPTION
391		/* a real Linux mtab will also show NFS options */
392		sbuf_printf(sb, " 0 0\n");
393	}
394
395	free(buf, M_TEMP);
396	free(flep, M_TEMP);
397	return (error);
398}
399
400/*
401 * Filler function for proc/partitions
402 */
403static int
404linprocfs_dopartitions(PFS_FILL_ARGS)
405{
406	struct g_class *cp;
407	struct g_geom *gp;
408	struct g_provider *pp;
409	int major, minor;
410
411	g_topology_lock();
412	sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
413	    "ruse wio wmerge wsect wuse running use aveq\n");
414
415	LIST_FOREACH(cp, &g_classes, class) {
416		if (strcmp(cp->name, "DISK") == 0 ||
417		    strcmp(cp->name, "PART") == 0)
418			LIST_FOREACH(gp, &cp->geom, geom) {
419				LIST_FOREACH(pp, &gp->provider, provider) {
420					if (linux_driver_get_major_minor(
421					    pp->name, &major, &minor) != 0) {
422						major = 0;
423						minor = 0;
424					}
425					sbuf_printf(sb, "%d %d %lld %s "
426					    "%d %d %d %d %d "
427					     "%d %d %d %d %d %d\n",
428					     major, minor,
429					     (long long)pp->mediasize, pp->name,
430					     0, 0, 0, 0, 0,
431					     0, 0, 0, 0, 0, 0);
432				}
433			}
434	}
435	g_topology_unlock();
436
437	return (0);
438}
439
440
441/*
442 * Filler function for proc/stat
443 */
444static int
445linprocfs_dostat(PFS_FILL_ARGS)
446{
447	struct pcpu *pcpu;
448	long cp_time[CPUSTATES];
449	long *cp;
450	struct timeval boottime;
451	int i;
452
453	read_cpu_time(cp_time);
454	getboottime(&boottime);
455	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
456	    T2J(cp_time[CP_USER]),
457	    T2J(cp_time[CP_NICE]),
458	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
459	    T2J(cp_time[CP_IDLE]));
460	CPU_FOREACH(i) {
461		pcpu = pcpu_find(i);
462		cp = pcpu->pc_cp_time;
463		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
464		    T2J(cp[CP_USER]),
465		    T2J(cp[CP_NICE]),
466		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
467		    T2J(cp[CP_IDLE]));
468	}
469	sbuf_printf(sb,
470	    "disk 0 0 0 0\n"
471	    "page %u %u\n"
472	    "swap %u %u\n"
473	    "intr %u\n"
474	    "ctxt %u\n"
475	    "btime %lld\n",
476	    vm_cnt.v_vnodepgsin,
477	    vm_cnt.v_vnodepgsout,
478	    vm_cnt.v_swappgsin,
479	    vm_cnt.v_swappgsout,
480	    vm_cnt.v_intr,
481	    vm_cnt.v_swtch,
482	    (long long)boottime.tv_sec);
483	return (0);
484}
485
486static int
487linprocfs_doswaps(PFS_FILL_ARGS)
488{
489	struct xswdev xsw;
490	uintmax_t total, used;
491	int n;
492	char devname[SPECNAMELEN + 1];
493
494	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
495	for (n = 0; ; n++) {
496		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
497			break;
498		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
499		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
500
501		/*
502		 * The space and not tab after the device name is on
503		 * purpose.  Linux does so.
504		 */
505		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
506		    devname, total, used);
507	}
508	return (0);
509}
510
511/*
512 * Filler function for proc/uptime
513 */
514static int
515linprocfs_douptime(PFS_FILL_ARGS)
516{
517	long cp_time[CPUSTATES];
518	struct timeval tv;
519
520	getmicrouptime(&tv);
521	read_cpu_time(cp_time);
522	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
523	    (long long)tv.tv_sec, tv.tv_usec / 10000,
524	    T2S(cp_time[CP_IDLE] / mp_ncpus),
525	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
526	return (0);
527}
528
529/*
530 * Get OS build date
531 */
532static void
533linprocfs_osbuild(struct thread *td, struct sbuf *sb)
534{
535#if 0
536	char osbuild[256];
537	char *cp1, *cp2;
538
539	strncpy(osbuild, version, 256);
540	osbuild[255] = '\0';
541	cp1 = strstr(osbuild, "\n");
542	cp2 = strstr(osbuild, ":");
543	if (cp1 && cp2) {
544		*cp1 = *cp2 = '\0';
545		cp1 = strstr(osbuild, "#");
546	} else
547		cp1 = NULL;
548	if (cp1)
549		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
550	else
551#endif
552		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
553}
554
555/*
556 * Get OS builder
557 */
558static void
559linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
560{
561#if 0
562	char builder[256];
563	char *cp;
564
565	cp = strstr(version, "\n    ");
566	if (cp) {
567		strncpy(builder, cp + 5, 256);
568		builder[255] = '\0';
569		cp = strstr(builder, ":");
570		if (cp)
571			*cp = '\0';
572	}
573	if (cp)
574		sbuf_cat(sb, builder);
575	else
576#endif
577		sbuf_cat(sb, "des@freebsd.org");
578}
579
580/*
581 * Filler function for proc/version
582 */
583static int
584linprocfs_doversion(PFS_FILL_ARGS)
585{
586	char osname[LINUX_MAX_UTSNAME];
587	char osrelease[LINUX_MAX_UTSNAME];
588
589	linux_get_osname(td, osname);
590	linux_get_osrelease(td, osrelease);
591	sbuf_printf(sb, "%s version %s (", osname, osrelease);
592	linprocfs_osbuilder(td, sb);
593	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
594	linprocfs_osbuild(td, sb);
595	sbuf_cat(sb, "\n");
596
597	return (0);
598}
599
600/*
601 * Filler function for proc/loadavg
602 */
603static int
604linprocfs_doloadavg(PFS_FILL_ARGS)
605{
606
607	sbuf_printf(sb,
608	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
609	    (int)(averunnable.ldavg[0] / averunnable.fscale),
610	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
611	    (int)(averunnable.ldavg[1] / averunnable.fscale),
612	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
613	    (int)(averunnable.ldavg[2] / averunnable.fscale),
614	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
615	    1,				/* number of running tasks */
616	    nprocs,			/* number of tasks */
617	    lastpid			/* the last pid */
618	);
619	return (0);
620}
621
622/*
623 * Filler function for proc/pid/stat
624 */
625static int
626linprocfs_doprocstat(PFS_FILL_ARGS)
627{
628	struct kinfo_proc kp;
629	struct timeval boottime;
630	char state;
631	static int ratelimit = 0;
632	vm_offset_t startcode, startdata;
633
634	getboottime(&boottime);
635	sx_slock(&proctree_lock);
636	PROC_LOCK(p);
637	fill_kinfo_proc(p, &kp);
638	sx_sunlock(&proctree_lock);
639	if (p->p_vmspace) {
640	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
641	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
642	} else {
643	   startcode = 0;
644	   startdata = 0;
645	}
646	sbuf_printf(sb, "%d", p->p_pid);
647#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
648	PS_ADD("comm",		"(%s)",	p->p_comm);
649	if (kp.ki_stat > sizeof(linux_state)) {
650		state = 'R';
651
652		if (ratelimit == 0) {
653			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
654			    kp.ki_stat, sizeof(linux_state));
655			++ratelimit;
656		}
657	} else
658		state = linux_state[kp.ki_stat - 1];
659	PS_ADD("state",		"%c",	state);
660	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
661	PS_ADD("pgrp",		"%d",	p->p_pgid);
662	PS_ADD("session",	"%d",	p->p_session->s_sid);
663	PROC_UNLOCK(p);
664	PS_ADD("tty",		"%ju",	(uintmax_t)kp.ki_tdev);
665	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
666	PS_ADD("flags",		"%u",	0); /* XXX */
667	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
668	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
669	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
670	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
671	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
672	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
673	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
674	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
675	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
676	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
677	PS_ADD("0",		"%d",	0); /* removed field */
678	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
679	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
680	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
681	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
682	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
683	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
684	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
685	PS_ADD("startstack",	"%u",	0); /* XXX */
686	PS_ADD("kstkesp",	"%u",	0); /* XXX */
687	PS_ADD("kstkeip",	"%u",	0); /* XXX */
688	PS_ADD("signal",	"%u",	0); /* XXX */
689	PS_ADD("blocked",	"%u",	0); /* XXX */
690	PS_ADD("sigignore",	"%u",	0); /* XXX */
691	PS_ADD("sigcatch",	"%u",	0); /* XXX */
692	PS_ADD("wchan",		"%u",	0); /* XXX */
693	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
694	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
695	PS_ADD("exitsignal",	"%d",	0); /* XXX */
696	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
697	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
698	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
699#undef PS_ADD
700	sbuf_putc(sb, '\n');
701
702	return (0);
703}
704
705/*
706 * Filler function for proc/pid/statm
707 */
708static int
709linprocfs_doprocstatm(PFS_FILL_ARGS)
710{
711	struct kinfo_proc kp;
712	segsz_t lsize;
713
714	sx_slock(&proctree_lock);
715	PROC_LOCK(p);
716	fill_kinfo_proc(p, &kp);
717	PROC_UNLOCK(p);
718	sx_sunlock(&proctree_lock);
719
720	/*
721	 * See comments in linprocfs_doprocstatus() regarding the
722	 * computation of lsize.
723	 */
724	/* size resident share trs drs lrs dt */
725	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
726	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
727	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
728	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
729	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
730	lsize = B2P(kp.ki_size) - kp.ki_dsize -
731	    kp.ki_ssize - kp.ki_tsize - 1;
732	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
733	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
734
735	return (0);
736}
737
738/*
739 * Filler function for proc/pid/status
740 */
741static int
742linprocfs_doprocstatus(PFS_FILL_ARGS)
743{
744	struct kinfo_proc kp;
745	char *state;
746	segsz_t lsize;
747	struct thread *td2;
748	struct sigacts *ps;
749	l_sigset_t siglist, sigignore, sigcatch;
750	int i;
751
752	sx_slock(&proctree_lock);
753	PROC_LOCK(p);
754	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
755
756	if (P_SHOULDSTOP(p)) {
757		state = "T (stopped)";
758	} else {
759		switch(p->p_state) {
760		case PRS_NEW:
761			state = "I (idle)";
762			break;
763		case PRS_NORMAL:
764			if (p->p_flag & P_WEXIT) {
765				state = "X (exiting)";
766				break;
767			}
768			switch(td2->td_state) {
769			case TDS_INHIBITED:
770				state = "S (sleeping)";
771				break;
772			case TDS_RUNQ:
773			case TDS_RUNNING:
774				state = "R (running)";
775				break;
776			default:
777				state = "? (unknown)";
778				break;
779			}
780			break;
781		case PRS_ZOMBIE:
782			state = "Z (zombie)";
783			break;
784		default:
785			state = "? (unknown)";
786			break;
787		}
788	}
789
790	fill_kinfo_proc(p, &kp);
791	sx_sunlock(&proctree_lock);
792
793	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
794	sbuf_printf(sb, "State:\t%s\n",		state);
795
796	/*
797	 * Credentials
798	 */
799	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
800	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
801						p->p_pptr->p_pid : 0);
802	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
803						p->p_ucred->cr_uid,
804						p->p_ucred->cr_svuid,
805						/* FreeBSD doesn't have fsuid */
806						p->p_ucred->cr_uid);
807	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
808						p->p_ucred->cr_gid,
809						p->p_ucred->cr_svgid,
810						/* FreeBSD doesn't have fsgid */
811						p->p_ucred->cr_gid);
812	sbuf_cat(sb, "Groups:\t");
813	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
814		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
815	PROC_UNLOCK(p);
816	sbuf_putc(sb, '\n');
817
818	/*
819	 * Memory
820	 *
821	 * While our approximation of VmLib may not be accurate (I
822	 * don't know of a simple way to verify it, and I'm not sure
823	 * it has much meaning anyway), I believe it's good enough.
824	 *
825	 * The same code that could (I think) accurately compute VmLib
826	 * could also compute VmLck, but I don't really care enough to
827	 * implement it. Submissions are welcome.
828	 */
829	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
830	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
831	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
832	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
833	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
834	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
835	lsize = B2P(kp.ki_size) - kp.ki_dsize -
836	    kp.ki_ssize - kp.ki_tsize - 1;
837	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
838
839	/*
840	 * Signal masks
841	 */
842	PROC_LOCK(p);
843	bsd_to_linux_sigset(&p->p_siglist, &siglist);
844	ps = p->p_sigacts;
845	mtx_lock(&ps->ps_mtx);
846	bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
847	bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
848	mtx_unlock(&ps->ps_mtx);
849	PROC_UNLOCK(p);
850
851	sbuf_printf(sb, "SigPnd:\t%016jx\n",	siglist.__mask);
852	/*
853	 * XXX. SigBlk - target thread's signal mask, td_sigmask.
854	 * To implement SigBlk pseudofs should support proc/tid dir entries.
855	 */
856	sbuf_printf(sb, "SigBlk:\t%016x\n",	0);
857	sbuf_printf(sb, "SigIgn:\t%016jx\n",	sigignore.__mask);
858	sbuf_printf(sb, "SigCgt:\t%016jx\n",	sigcatch.__mask);
859
860	/*
861	 * Linux also prints the capability masks, but we don't have
862	 * capabilities yet, and when we do get them they're likely to
863	 * be meaningless to Linux programs, so we lie. XXX
864	 */
865	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
866	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
867	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
868
869	return (0);
870}
871
872
873/*
874 * Filler function for proc/pid/cwd
875 */
876static int
877linprocfs_doproccwd(PFS_FILL_ARGS)
878{
879	struct filedesc *fdp;
880	struct vnode *vp;
881	char *fullpath = "unknown";
882	char *freepath = NULL;
883
884	fdp = p->p_fd;
885	FILEDESC_SLOCK(fdp);
886	vp = fdp->fd_cdir;
887	if (vp != NULL)
888		VREF(vp);
889	FILEDESC_SUNLOCK(fdp);
890	vn_fullpath(td, vp, &fullpath, &freepath);
891	if (vp != NULL)
892		vrele(vp);
893	sbuf_printf(sb, "%s", fullpath);
894	if (freepath)
895		free(freepath, M_TEMP);
896	return (0);
897}
898
899/*
900 * Filler function for proc/pid/root
901 */
902static int
903linprocfs_doprocroot(PFS_FILL_ARGS)
904{
905	struct filedesc *fdp;
906	struct vnode *vp;
907	char *fullpath = "unknown";
908	char *freepath = NULL;
909
910	fdp = p->p_fd;
911	FILEDESC_SLOCK(fdp);
912	vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
913	if (vp != NULL)
914		VREF(vp);
915	FILEDESC_SUNLOCK(fdp);
916	vn_fullpath(td, vp, &fullpath, &freepath);
917	if (vp != NULL)
918		vrele(vp);
919	sbuf_printf(sb, "%s", fullpath);
920	if (freepath)
921		free(freepath, M_TEMP);
922	return (0);
923}
924
925/*
926 * Filler function for proc/pid/cmdline
927 */
928static int
929linprocfs_doproccmdline(PFS_FILL_ARGS)
930{
931	int ret;
932
933	PROC_LOCK(p);
934	if ((ret = p_cansee(td, p)) != 0) {
935		PROC_UNLOCK(p);
936		return (ret);
937	}
938
939	/*
940	 * Mimic linux behavior and pass only processes with usermode
941	 * address space as valid.  Return zero silently otherwize.
942	 */
943	if (p->p_vmspace == &vmspace0) {
944		PROC_UNLOCK(p);
945		return (0);
946	}
947	if (p->p_args != NULL) {
948		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
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_getargv(td, p, sb);
961	return (ret);
962}
963
964/*
965 * Filler function for proc/pid/environ
966 */
967static int
968linprocfs_doprocenviron(PFS_FILL_ARGS)
969{
970
971	/*
972	 * Mimic linux behavior and pass only processes with usermode
973	 * address space as valid.  Return zero silently otherwize.
974	 */
975	if (p->p_vmspace == &vmspace0)
976		return (0);
977
978	return (proc_getenvv(td, p, sb));
979}
980
981static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
982static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
983static char vdso_str[] = "      [vdso]";
984static char stack_str[] = "      [stack]";
985
986/*
987 * Filler function for proc/pid/maps
988 */
989static int
990linprocfs_doprocmaps(PFS_FILL_ARGS)
991{
992	struct vmspace *vm;
993	vm_map_t map;
994	vm_map_entry_t entry, tmp_entry;
995	vm_object_t obj, tobj, lobj;
996	vm_offset_t e_start, e_end;
997	vm_ooffset_t off = 0;
998	vm_prot_t e_prot;
999	unsigned int last_timestamp;
1000	char *name = "", *freename = NULL;
1001	const char *l_map_str;
1002	ino_t ino;
1003	int ref_count, shadow_count, flags;
1004	int error;
1005	struct vnode *vp;
1006	struct vattr vat;
1007
1008	PROC_LOCK(p);
1009	error = p_candebug(td, p);
1010	PROC_UNLOCK(p);
1011	if (error)
1012		return (error);
1013
1014	if (uio->uio_rw != UIO_READ)
1015		return (EOPNOTSUPP);
1016
1017	error = 0;
1018	vm = vmspace_acquire_ref(p);
1019	if (vm == NULL)
1020		return (ESRCH);
1021
1022	if (SV_CURPROC_FLAG(SV_LP64))
1023		l_map_str = l64_map_str;
1024	else
1025		l_map_str = l32_map_str;
1026	map = &vm->vm_map;
1027	vm_map_lock_read(map);
1028	for (entry = map->header.next; entry != &map->header;
1029	    entry = entry->next) {
1030		name = "";
1031		freename = NULL;
1032		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1033			continue;
1034		e_prot = entry->protection;
1035		e_start = entry->start;
1036		e_end = entry->end;
1037		obj = entry->object.vm_object;
1038		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1039			VM_OBJECT_RLOCK(tobj);
1040			if (lobj != obj)
1041				VM_OBJECT_RUNLOCK(lobj);
1042			lobj = tobj;
1043		}
1044		last_timestamp = map->timestamp;
1045		vm_map_unlock_read(map);
1046		ino = 0;
1047		if (lobj) {
1048			off = IDX_TO_OFF(lobj->size);
1049			vp = vm_object_vnode(lobj);
1050			if (vp != NULL)
1051				vref(vp);
1052			if (lobj != obj)
1053				VM_OBJECT_RUNLOCK(lobj);
1054			flags = obj->flags;
1055			ref_count = obj->ref_count;
1056			shadow_count = obj->shadow_count;
1057			VM_OBJECT_RUNLOCK(obj);
1058			if (vp != NULL) {
1059				vn_fullpath(td, vp, &name, &freename);
1060				vn_lock(vp, LK_SHARED | LK_RETRY);
1061				VOP_GETATTR(vp, &vat, td->td_ucred);
1062				ino = vat.va_fileid;
1063				vput(vp);
1064			} else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1065				if (e_start == p->p_sysent->sv_shared_page_base)
1066					name = vdso_str;
1067				if (e_end == p->p_sysent->sv_usrstack)
1068					name = stack_str;
1069			}
1070		} else {
1071			flags = 0;
1072			ref_count = 0;
1073			shadow_count = 0;
1074		}
1075
1076		/*
1077		 * format:
1078		 *  start, end, access, offset, major, minor, inode, name.
1079		 */
1080		error = sbuf_printf(sb, l_map_str,
1081		    (u_long)e_start, (u_long)e_end,
1082		    (e_prot & VM_PROT_READ)?"r":"-",
1083		    (e_prot & VM_PROT_WRITE)?"w":"-",
1084		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1085		    "p",
1086		    (u_long)off,
1087		    0,
1088		    0,
1089		    (u_long)ino,
1090		    *name ? "     " : "",
1091		    name
1092		    );
1093		if (freename)
1094			free(freename, M_TEMP);
1095		vm_map_lock_read(map);
1096		if (error == -1) {
1097			error = 0;
1098			break;
1099		}
1100		if (last_timestamp != map->timestamp) {
1101			/*
1102			 * Look again for the entry because the map was
1103			 * modified while it was unlocked.  Specifically,
1104			 * the entry may have been clipped, merged, or deleted.
1105			 */
1106			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1107			entry = tmp_entry;
1108		}
1109	}
1110	vm_map_unlock_read(map);
1111	vmspace_free(vm);
1112
1113	return (error);
1114}
1115
1116/*
1117 * Criteria for interface name translation
1118 */
1119#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1120
1121static int
1122linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1123{
1124	struct ifnet *ifscan;
1125	int ethno;
1126
1127	IFNET_RLOCK_ASSERT();
1128
1129	/* Short-circuit non ethernet interfaces */
1130	if (!IFP_IS_ETH(ifp))
1131		return (strlcpy(buffer, ifp->if_xname, buflen));
1132
1133	/* Determine the (relative) unit number for ethernet interfaces */
1134	ethno = 0;
1135	TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1136		if (ifscan == ifp)
1137			return (snprintf(buffer, buflen, "eth%d", ethno));
1138		if (IFP_IS_ETH(ifscan))
1139			ethno++;
1140	}
1141
1142	return (0);
1143}
1144
1145/*
1146 * Filler function for proc/net/dev
1147 */
1148static int
1149linprocfs_donetdev(PFS_FILL_ARGS)
1150{
1151	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1152	struct ifnet *ifp;
1153
1154	sbuf_printf(sb, "%6s|%58s|%s\n"
1155	    "%6s|%58s|%58s\n",
1156	    "Inter-", "   Receive", "  Transmit",
1157	    " face",
1158	    "bytes    packets errs drop fifo frame compressed multicast",
1159	    "bytes    packets errs drop fifo colls carrier compressed");
1160
1161	CURVNET_SET(TD_TO_VNET(curthread));
1162	IFNET_RLOCK();
1163	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1164		linux_ifname(ifp, ifname, sizeof ifname);
1165		sbuf_printf(sb, "%6.6s: ", ifname);
1166		sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1167		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1168		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1169		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1170		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1171							/* rx_missed_errors */
1172		    0UL,				/* rx_fifo_errors */
1173		    0UL,				/* rx_length_errors +
1174							 * rx_over_errors +
1175							 * rx_crc_errors +
1176							 * rx_frame_errors */
1177		    0UL,				/* rx_compressed */
1178		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1179							/* XXX-BZ rx only? */
1180		sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1181		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1182		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1183		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1184		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1185		    0UL,				/* tx_fifo_errors */
1186		    (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1187		    0UL,				/* tx_carrier_errors +
1188							 * tx_aborted_errors +
1189							 * tx_window_errors +
1190							 * tx_heartbeat_errors*/
1191		    0UL);				/* tx_compressed */
1192	}
1193	IFNET_RUNLOCK();
1194	CURVNET_RESTORE();
1195
1196	return (0);
1197}
1198
1199/*
1200 * Filler function for proc/sys/kernel/osrelease
1201 */
1202static int
1203linprocfs_doosrelease(PFS_FILL_ARGS)
1204{
1205	char osrelease[LINUX_MAX_UTSNAME];
1206
1207	linux_get_osrelease(td, osrelease);
1208	sbuf_printf(sb, "%s\n", osrelease);
1209
1210	return (0);
1211}
1212
1213/*
1214 * Filler function for proc/sys/kernel/ostype
1215 */
1216static int
1217linprocfs_doostype(PFS_FILL_ARGS)
1218{
1219	char osname[LINUX_MAX_UTSNAME];
1220
1221	linux_get_osname(td, osname);
1222	sbuf_printf(sb, "%s\n", osname);
1223
1224	return (0);
1225}
1226
1227/*
1228 * Filler function for proc/sys/kernel/version
1229 */
1230static int
1231linprocfs_doosbuild(PFS_FILL_ARGS)
1232{
1233
1234	linprocfs_osbuild(td, sb);
1235	sbuf_cat(sb, "\n");
1236	return (0);
1237}
1238
1239/*
1240 * Filler function for proc/sys/kernel/msgmni
1241 */
1242static int
1243linprocfs_domsgmni(PFS_FILL_ARGS)
1244{
1245
1246	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1247	return (0);
1248}
1249
1250/*
1251 * Filler function for proc/sys/kernel/pid_max
1252 */
1253static int
1254linprocfs_dopid_max(PFS_FILL_ARGS)
1255{
1256
1257	sbuf_printf(sb, "%i\n", PID_MAX);
1258	return (0);
1259}
1260
1261/*
1262 * Filler function for proc/sys/kernel/sem
1263 */
1264static int
1265linprocfs_dosem(PFS_FILL_ARGS)
1266{
1267
1268	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1269	    seminfo.semopm, seminfo.semmni);
1270	return (0);
1271}
1272
1273/*
1274 * Filler function for proc/scsi/device_info
1275 */
1276static int
1277linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1278{
1279
1280	return (0);
1281}
1282
1283/*
1284 * Filler function for proc/scsi/scsi
1285 */
1286static int
1287linprocfs_doscsiscsi(PFS_FILL_ARGS)
1288{
1289
1290	return (0);
1291}
1292
1293/*
1294 * Filler function for proc/devices
1295 */
1296static int
1297linprocfs_dodevices(PFS_FILL_ARGS)
1298{
1299	char *char_devices;
1300	sbuf_printf(sb, "Character devices:\n");
1301
1302	char_devices = linux_get_char_devices();
1303	sbuf_printf(sb, "%s", char_devices);
1304	linux_free_get_char_devices(char_devices);
1305
1306	sbuf_printf(sb, "\nBlock devices:\n");
1307
1308	return (0);
1309}
1310
1311/*
1312 * Filler function for proc/cmdline
1313 */
1314static int
1315linprocfs_docmdline(PFS_FILL_ARGS)
1316{
1317
1318	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1319	sbuf_printf(sb, " ro root=302\n");
1320	return (0);
1321}
1322
1323/*
1324 * Filler function for proc/filesystems
1325 */
1326static int
1327linprocfs_dofilesystems(PFS_FILL_ARGS)
1328{
1329	struct vfsconf *vfsp;
1330
1331	vfsconf_slock();
1332	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1333		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1334			sbuf_printf(sb, "nodev");
1335		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1336	}
1337	vfsconf_sunlock();
1338	return(0);
1339}
1340
1341#if 0
1342/*
1343 * Filler function for proc/modules
1344 */
1345static int
1346linprocfs_domodules(PFS_FILL_ARGS)
1347{
1348	struct linker_file *lf;
1349
1350	TAILQ_FOREACH(lf, &linker_files, link) {
1351		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1352		    (unsigned long)lf->size, lf->refs);
1353	}
1354	return (0);
1355}
1356#endif
1357
1358/*
1359 * Filler function for proc/pid/fd
1360 */
1361static int
1362linprocfs_dofdescfs(PFS_FILL_ARGS)
1363{
1364
1365	if (p == curproc)
1366		sbuf_printf(sb, "/dev/fd");
1367	else
1368		sbuf_printf(sb, "unknown");
1369	return (0);
1370}
1371
1372/*
1373 * Filler function for proc/pid/limits
1374 */
1375static const struct linux_rlimit_ident {
1376	const char	*desc;
1377	const char	*unit;
1378	unsigned int	rlim_id;
1379} linux_rlimits_ident[] = {
1380	{ "Max cpu time",	"seconds",	RLIMIT_CPU },
1381	{ "Max file size", 	"bytes",	RLIMIT_FSIZE },
1382	{ "Max data size",	"bytes", 	RLIMIT_DATA },
1383	{ "Max stack size",	"bytes", 	RLIMIT_STACK },
1384	{ "Max core file size",  "bytes",	RLIMIT_CORE },
1385	{ "Max resident set",	"bytes",	RLIMIT_RSS },
1386	{ "Max processes",	"processes",	RLIMIT_NPROC },
1387	{ "Max open files",	"files",	RLIMIT_NOFILE },
1388	{ "Max locked memory",	"bytes",	RLIMIT_MEMLOCK },
1389	{ "Max address space",	"bytes",	RLIMIT_AS },
1390	{ "Max file locks",	"locks",	LINUX_RLIMIT_LOCKS },
1391	{ "Max pending signals", "signals",	LINUX_RLIMIT_SIGPENDING },
1392	{ "Max msgqueue size",	"bytes",	LINUX_RLIMIT_MSGQUEUE },
1393	{ "Max nice priority", 		"",	LINUX_RLIMIT_NICE },
1394	{ "Max realtime priority",	"",	LINUX_RLIMIT_RTPRIO },
1395	{ "Max realtime timeout",	"us",	LINUX_RLIMIT_RTTIME },
1396	{ 0, 0, 0 }
1397};
1398
1399static int
1400linprocfs_doproclimits(PFS_FILL_ARGS)
1401{
1402	const struct linux_rlimit_ident *li;
1403	struct plimit *limp;
1404	struct rlimit rl;
1405	ssize_t size;
1406	int res, error;
1407
1408	error = 0;
1409
1410	PROC_LOCK(p);
1411	limp = lim_hold(p->p_limit);
1412	PROC_UNLOCK(p);
1413	size = sizeof(res);
1414	sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1415			"Hard Limit", "Units");
1416	for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1417		switch (li->rlim_id)
1418		{
1419		case LINUX_RLIMIT_LOCKS:
1420			/* FALLTHROUGH */
1421		case LINUX_RLIMIT_RTTIME:
1422			rl.rlim_cur = RLIM_INFINITY;
1423			break;
1424		case LINUX_RLIMIT_SIGPENDING:
1425			error = kernel_sysctlbyname(td,
1426			    "kern.sigqueue.max_pending_per_proc",
1427			    &res, &size, 0, 0, 0, 0);
1428			if (error != 0)
1429				goto out;
1430			rl.rlim_cur = res;
1431			rl.rlim_max = res;
1432			break;
1433		case LINUX_RLIMIT_MSGQUEUE:
1434			error = kernel_sysctlbyname(td,
1435			    "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1436			if (error != 0)
1437				goto out;
1438			rl.rlim_cur = res;
1439			rl.rlim_max = res;
1440			break;
1441		case LINUX_RLIMIT_NICE:
1442			/* FALLTHROUGH */
1443		case LINUX_RLIMIT_RTPRIO:
1444			rl.rlim_cur = 0;
1445			rl.rlim_max = 0;
1446			break;
1447		default:
1448			rl = limp->pl_rlimit[li->rlim_id];
1449			break;
1450		}
1451		if (rl.rlim_cur == RLIM_INFINITY)
1452			sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1453			    li->desc, "unlimited", "unlimited", li->unit);
1454		else
1455			sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1456			    li->desc, (unsigned long long)rl.rlim_cur,
1457			    (unsigned long long)rl.rlim_max, li->unit);
1458	}
1459out:
1460	lim_free(limp);
1461	return (error);
1462}
1463
1464/*
1465 * Filler function for proc/sys/kernel/random/uuid
1466 */
1467static int
1468linprocfs_douuid(PFS_FILL_ARGS)
1469{
1470	struct uuid uuid;
1471
1472	kern_uuidgen(&uuid, 1);
1473	sbuf_printf_uuid(sb, &uuid);
1474	sbuf_printf(sb, "\n");
1475	return(0);
1476}
1477
1478/*
1479 * Filler function for proc/pid/auxv
1480 */
1481static int
1482linprocfs_doauxv(PFS_FILL_ARGS)
1483{
1484	struct sbuf *asb;
1485	off_t buflen, resid;
1486	int error;
1487
1488	/*
1489	 * Mimic linux behavior and pass only processes with usermode
1490	 * address space as valid. Return zero silently otherwise.
1491	 */
1492	if (p->p_vmspace == &vmspace0)
1493		return (0);
1494
1495	if (uio->uio_resid == 0)
1496		return (0);
1497	if (uio->uio_offset < 0 || uio->uio_resid < 0)
1498		return (EINVAL);
1499
1500	asb = sbuf_new_auto();
1501	if (asb == NULL)
1502		return (ENOMEM);
1503	error = proc_getauxv(td, p, asb);
1504	if (error == 0)
1505		error = sbuf_finish(asb);
1506
1507	resid = sbuf_len(asb) - uio->uio_offset;
1508	if (resid > uio->uio_resid)
1509		buflen = uio->uio_resid;
1510	else
1511		buflen = resid;
1512	if (buflen > IOSIZE_MAX)
1513		return (EINVAL);
1514	if (buflen > MAXPHYS)
1515		buflen = MAXPHYS;
1516	if (resid <= 0)
1517		return (0);
1518
1519	if (error == 0)
1520		error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1521	sbuf_delete(asb);
1522	return (error);
1523}
1524
1525/*
1526 * Constructor
1527 */
1528static int
1529linprocfs_init(PFS_INIT_ARGS)
1530{
1531	struct pfs_node *root;
1532	struct pfs_node *dir;
1533
1534	root = pi->pi_root;
1535
1536	/* /proc/... */
1537	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1538	    NULL, NULL, NULL, PFS_RD);
1539	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1540	    NULL, NULL, NULL, PFS_RD);
1541	pfs_create_file(root, "devices", &linprocfs_dodevices,
1542	    NULL, NULL, NULL, PFS_RD);
1543	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1544	    NULL, NULL, NULL, PFS_RD);
1545	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1546	    NULL, NULL, NULL, PFS_RD);
1547	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1548	    NULL, NULL, NULL, PFS_RD);
1549#if 0
1550	pfs_create_file(root, "modules", &linprocfs_domodules,
1551	    NULL, NULL, NULL, PFS_RD);
1552#endif
1553	pfs_create_file(root, "mounts", &linprocfs_domtab,
1554	    NULL, NULL, NULL, PFS_RD);
1555	pfs_create_file(root, "mtab", &linprocfs_domtab,
1556	    NULL, NULL, NULL, PFS_RD);
1557	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1558	    NULL, NULL, NULL, PFS_RD);
1559	pfs_create_link(root, "self", &procfs_docurproc,
1560	    NULL, NULL, NULL, 0);
1561	pfs_create_file(root, "stat", &linprocfs_dostat,
1562	    NULL, NULL, NULL, PFS_RD);
1563	pfs_create_file(root, "swaps", &linprocfs_doswaps,
1564	    NULL, NULL, NULL, PFS_RD);
1565	pfs_create_file(root, "uptime", &linprocfs_douptime,
1566	    NULL, NULL, NULL, PFS_RD);
1567	pfs_create_file(root, "version", &linprocfs_doversion,
1568	    NULL, NULL, NULL, PFS_RD);
1569
1570	/* /proc/net/... */
1571	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1572	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1573	    NULL, NULL, NULL, PFS_RD);
1574
1575	/* /proc/<pid>/... */
1576	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1577	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1578	    NULL, NULL, NULL, PFS_RD);
1579	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1580	    NULL, NULL, NULL, 0);
1581	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1582	    NULL, &procfs_candebug, NULL, PFS_RD);
1583	pfs_create_link(dir, "exe", &procfs_doprocfile,
1584	    NULL, &procfs_notsystem, NULL, 0);
1585	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1586	    NULL, NULL, NULL, PFS_RD);
1587	pfs_create_file(dir, "mem", &procfs_doprocmem,
1588	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1589	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1590	    NULL, NULL, NULL, 0);
1591	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1592	    NULL, NULL, NULL, PFS_RD);
1593	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1594	    NULL, NULL, NULL, PFS_RD);
1595	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1596	    NULL, NULL, NULL, PFS_RD);
1597	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1598	    NULL, NULL, NULL, 0);
1599	pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1600	    NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1601	pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1602	    NULL, NULL, NULL, PFS_RD);
1603
1604	/* /proc/scsi/... */
1605	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1606	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1607	    NULL, NULL, NULL, PFS_RD);
1608	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1609	    NULL, NULL, NULL, PFS_RD);
1610
1611	/* /proc/sys/... */
1612	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1613	/* /proc/sys/kernel/... */
1614	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1615	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1616	    NULL, NULL, NULL, PFS_RD);
1617	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1618	    NULL, NULL, NULL, PFS_RD);
1619	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1620	    NULL, NULL, NULL, PFS_RD);
1621	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1622	    NULL, NULL, NULL, PFS_RD);
1623	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1624	    NULL, NULL, NULL, PFS_RD);
1625	pfs_create_file(dir, "sem", &linprocfs_dosem,
1626	    NULL, NULL, NULL, PFS_RD);
1627
1628	/* /proc/sys/kernel/random/... */
1629	dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1630	pfs_create_file(dir, "uuid", &linprocfs_douuid,
1631	    NULL, NULL, NULL, PFS_RD);
1632
1633	return (0);
1634}
1635
1636/*
1637 * Destructor
1638 */
1639static int
1640linprocfs_uninit(PFS_INIT_ARGS)
1641{
1642
1643	/* nothing to do, pseudofs will GC */
1644	return (0);
1645}
1646
1647PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1648#if defined(__amd64__)
1649MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1650#else
1651MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1652#endif
1653MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1654MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1655MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1656