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