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