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