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