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