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