linprocfs.c revision 183600
1/*-
2 * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *	@(#)procfs_status.c	8.4 (Berkeley) 6/15/94
40 */
41
42#include "opt_compat.h"
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 183600 2008-10-04 14:08:16Z kib $");
46
47#include <sys/param.h>
48#include <sys/queue.h>
49#include <sys/blist.h>
50#include <sys/conf.h>
51#include <sys/exec.h>
52#include <sys/fcntl.h>
53#include <sys/filedesc.h>
54#include <sys/jail.h>
55#include <sys/kernel.h>
56#include <sys/linker.h>
57#include <sys/lock.h>
58#include <sys/malloc.h>
59#include <sys/mount.h>
60#include <sys/msg.h>
61#include <sys/mutex.h>
62#include <sys/namei.h>
63#include <sys/proc.h>
64#include <sys/resourcevar.h>
65#include <sys/sbuf.h>
66#include <sys/sem.h>
67#include <sys/smp.h>
68#include <sys/socket.h>
69#include <sys/sysctl.h>
70#include <sys/systm.h>
71#include <sys/time.h>
72#include <sys/tty.h>
73#include <sys/user.h>
74#include <sys/vmmeter.h>
75#include <sys/vnode.h>
76#include <sys/vimage.h>
77
78#include <net/if.h>
79
80#include <vm/vm.h>
81#include <vm/pmap.h>
82#include <vm/vm_map.h>
83#include <vm/vm_param.h>
84#include <vm/vm_object.h>
85#include <vm/swap_pager.h>
86
87#include <machine/clock.h>
88
89#if defined(__i386__) || defined(__amd64__)
90#include <machine/cputypes.h>
91#include <machine/md_var.h>
92#endif /* __i386__ || __amd64__ */
93
94#ifdef COMPAT_LINUX32				/* XXX */
95#include <machine/../linux32/linux.h>
96#else
97#include <machine/../linux/linux.h>
98#endif
99#include <compat/linux/linux_ioctl.h>
100#include <compat/linux/linux_mib.h>
101#include <compat/linux/linux_util.h>
102#include <fs/pseudofs/pseudofs.h>
103#include <fs/procfs/procfs.h>
104
105/*
106 * Various conversion macros
107 */
108#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
109#define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
110#define B2K(x) ((x) >> 10)				/* bytes to kbytes */
111#define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
112#define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
113#define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
114
115/**
116 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
117 *
118 * The linux procfs state field displays one of the characters RSDZTW to
119 * denote running, sleeping in an interruptible wait, waiting in an
120 * uninterruptible disk sleep, a zombie process, process is being traced
121 * or stopped, or process is paging respectively.
122 *
123 * Our struct kinfo_proc contains the variable ki_stat which contains a
124 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
125 *
126 * This character array is used with ki_stati-1 as an index and tries to
127 * map our states to suitable linux states.
128 */
129static char linux_state[] = "RRSTZDD";
130
131/*
132 * Filler function for proc/meminfo
133 */
134static int
135linprocfs_domeminfo(PFS_FILL_ARGS)
136{
137	unsigned long memtotal;		/* total memory in bytes */
138	unsigned long memused;		/* used memory in bytes */
139	unsigned long memfree;		/* free memory in bytes */
140	unsigned long memshared;	/* shared memory ??? */
141	unsigned long buffers, cached;	/* buffer / cache memory ??? */
142	unsigned long long swaptotal;	/* total swap space in bytes */
143	unsigned long long swapused;	/* used swap space in bytes */
144	unsigned long long swapfree;	/* free swap space in bytes */
145	vm_object_t object;
146	int i, j;
147
148	memtotal = physmem * PAGE_SIZE;
149	/*
150	 * The correct thing here would be:
151	 *
152	memfree = cnt.v_free_count * PAGE_SIZE;
153	memused = memtotal - memfree;
154	 *
155	 * but it might mislead linux binaries into thinking there
156	 * is very little memory left, so we cheat and tell them that
157	 * all memory that isn't wired down is free.
158	 */
159	memused = cnt.v_wire_count * PAGE_SIZE;
160	memfree = memtotal - memused;
161	swap_pager_status(&i, &j);
162	swaptotal = (unsigned long long)i * PAGE_SIZE;
163	swapused = (unsigned long long)j * PAGE_SIZE;
164	swapfree = swaptotal - swapused;
165	memshared = 0;
166	mtx_lock(&vm_object_list_mtx);
167	TAILQ_FOREACH(object, &vm_object_list, object_list)
168		if (object->shadow_count > 1)
169			memshared += object->resident_page_count;
170	mtx_unlock(&vm_object_list_mtx);
171	memshared *= PAGE_SIZE;
172	/*
173	 * We'd love to be able to write:
174	 *
175	buffers = bufspace;
176	 *
177	 * but bufspace is internal to vfs_bio.c and we don't feel
178	 * like unstaticizing it just for linprocfs's sake.
179	 */
180	buffers = 0;
181	cached = cnt.v_cache_count * PAGE_SIZE;
182
183	sbuf_printf(sb,
184	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
185	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
186	    "Swap: %llu %llu %llu\n"
187	    "MemTotal: %9lu kB\n"
188	    "MemFree:  %9lu kB\n"
189	    "MemShared:%9lu kB\n"
190	    "Buffers:  %9lu kB\n"
191	    "Cached:   %9lu kB\n"
192	    "SwapTotal:%9llu kB\n"
193	    "SwapFree: %9llu kB\n",
194	    memtotal, memused, memfree, memshared, buffers, cached,
195	    swaptotal, swapused, swapfree,
196	    B2K(memtotal), B2K(memfree),
197	    B2K(memshared), B2K(buffers), B2K(cached),
198	    B2K(swaptotal), B2K(swapfree));
199
200	return (0);
201}
202
203#if defined(__i386__) || defined(__amd64__)
204/*
205 * Filler function for proc/cpuinfo (i386 & amd64 version)
206 */
207static int
208linprocfs_docpuinfo(PFS_FILL_ARGS)
209{
210	int hw_model[2];
211	char model[128];
212	size_t size;
213	int class, fqmhz, fqkhz;
214	int i;
215
216	/*
217	 * We default the flags to include all non-conflicting flags,
218	 * and the Intel versions of conflicting flags.
219	 */
220	static char *flags[] = {
221		"fpu",	    "vme",     "de",	   "pse",      "tsc",
222		"msr",	    "pae",     "mce",	   "cx8",      "apic",
223		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
224		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
225		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
226		"xmm",	    "sse2",    "b27",	   "b28",      "b29",
227		"3dnowext", "3dnow"
228	};
229
230	switch (cpu_class) {
231#ifdef __i386__
232	case CPUCLASS_286:
233		class = 2;
234		break;
235	case CPUCLASS_386:
236		class = 3;
237		break;
238	case CPUCLASS_486:
239		class = 4;
240		break;
241	case CPUCLASS_586:
242		class = 5;
243		break;
244	case CPUCLASS_686:
245		class = 6;
246		break;
247	default:
248		class = 0;
249		break;
250#else /* __amd64__ */
251	default:
252		class = 15;
253		break;
254#endif
255	}
256
257	hw_model[0] = CTL_HW;
258	hw_model[1] = HW_MODEL;
259	model[0] = '\0';
260	size = sizeof(model);
261	if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
262		strcpy(model, "unknown");
263	for (i = 0; i < mp_ncpus; ++i) {
264		sbuf_printf(sb,
265		    "processor\t: %d\n"
266		    "vendor_id\t: %.20s\n"
267		    "cpu family\t: %d\n"
268		    "model\t\t: %d\n"
269		    "model name\t: %s\n"
270		    "stepping\t: %d\n",
271		    i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
272		/* XXX per-cpu vendor / class / model / id? */
273	}
274
275	sbuf_cat(sb,
276	    "flags\t\t:");
277
278	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
279		flags[16] = "fcmov";
280	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
281		flags[24] = "cxmmx";
282	}
283
284	for (i = 0; i < 32; i++)
285		if (cpu_feature & (1 << i))
286			sbuf_printf(sb, " %s", flags[i]);
287	sbuf_cat(sb, "\n");
288	if (class >= 5) {
289		fqmhz = (tsc_freq + 4999) / 1000000;
290		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
291		sbuf_printf(sb,
292		    "cpu MHz\t\t: %d.%02d\n"
293		    "bogomips\t: %d.%02d\n",
294		    fqmhz, fqkhz, fqmhz, fqkhz);
295	}
296
297	return (0);
298}
299#endif /* __i386__ || __amd64__ */
300
301/*
302 * Filler function for proc/mtab
303 *
304 * This file doesn't exist in Linux' procfs, but is included here so
305 * users can symlink /compat/linux/etc/mtab to /proc/mtab
306 */
307static int
308linprocfs_domtab(PFS_FILL_ARGS)
309{
310	struct nameidata nd;
311	struct mount *mp;
312	const char *lep;
313	char *dlep, *flep, *mntto, *mntfrom, *fstype;
314	size_t lep_len;
315	int error;
316
317	/* resolve symlinks etc. in the emulation tree prefix */
318	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
319	flep = NULL;
320	error = namei(&nd);
321	VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
322	if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
323		lep = linux_emul_path;
324	else
325		lep = dlep;
326	lep_len = strlen(lep);
327
328	mtx_lock(&mountlist_mtx);
329	error = 0;
330	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
331		/* determine device name */
332		mntfrom = mp->mnt_stat.f_mntfromname;
333
334		/* determine mount point */
335		mntto = mp->mnt_stat.f_mntonname;
336		if (strncmp(mntto, lep, lep_len) == 0 &&
337		    mntto[lep_len] == '/')
338			mntto += lep_len;
339
340		/* determine fs type */
341		fstype = mp->mnt_stat.f_fstypename;
342		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
343			mntfrom = fstype = "proc";
344		else if (strcmp(fstype, "procfs") == 0)
345			continue;
346
347		if (strcmp(fstype, "linsysfs") == 0) {
348			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
349			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
350		} else {
351			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
352			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
353		}
354#define ADD_OPTION(opt, name) \
355	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
356		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
357		ADD_OPTION(MNT_NOEXEC,		"noexec");
358		ADD_OPTION(MNT_NOSUID,		"nosuid");
359		ADD_OPTION(MNT_UNION,		"union");
360		ADD_OPTION(MNT_ASYNC,		"async");
361		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
362		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
363		ADD_OPTION(MNT_NOATIME,		"noatime");
364#undef ADD_OPTION
365		/* a real Linux mtab will also show NFS options */
366		sbuf_printf(sb, " 0 0\n");
367	}
368	mtx_unlock(&mountlist_mtx);
369	if (flep != NULL)
370		free(flep, M_TEMP);
371	return (error);
372}
373
374/*
375 * Filler function for proc/stat
376 */
377static int
378linprocfs_dostat(PFS_FILL_ARGS)
379{
380	struct pcpu *pcpu;
381	long cp_time[CPUSTATES];
382	long *cp;
383	int i;
384
385	read_cpu_time(cp_time);
386	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
387	    T2J(cp_time[CP_USER]),
388	    T2J(cp_time[CP_NICE]),
389	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
390	    T2J(cp_time[CP_IDLE]));
391	for (i = 0; i <= mp_maxid; ++i) {
392		if (CPU_ABSENT(i))
393			continue;
394		pcpu = pcpu_find(i);
395		cp = pcpu->pc_cp_time;
396		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
397		    T2J(cp[CP_USER]),
398		    T2J(cp[CP_NICE]),
399		    T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
400		    T2J(cp[CP_IDLE]));
401	}
402	sbuf_printf(sb,
403	    "disk 0 0 0 0\n"
404	    "page %u %u\n"
405	    "swap %u %u\n"
406	    "intr %u\n"
407	    "ctxt %u\n"
408	    "btime %lld\n",
409	    cnt.v_vnodepgsin,
410	    cnt.v_vnodepgsout,
411	    cnt.v_swappgsin,
412	    cnt.v_swappgsout,
413	    cnt.v_intr,
414	    cnt.v_swtch,
415	    (long long)boottime.tv_sec);
416	return (0);
417}
418
419/*
420 * Filler function for proc/uptime
421 */
422static int
423linprocfs_douptime(PFS_FILL_ARGS)
424{
425	long cp_time[CPUSTATES];
426	struct timeval tv;
427
428	getmicrouptime(&tv);
429	read_cpu_time(cp_time);
430	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
431	    (long long)tv.tv_sec, tv.tv_usec / 10000,
432	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
433	return (0);
434}
435
436/*
437 * Get OS build date
438 */
439static void
440linprocfs_osbuild(struct thread *td, struct sbuf *sb)
441{
442#if 0
443	char osbuild[256];
444	char *cp1, *cp2;
445
446	strncpy(osbuild, version, 256);
447	osbuild[255] = '\0';
448	cp1 = strstr(osbuild, "\n");
449	cp2 = strstr(osbuild, ":");
450	if (cp1 && cp2) {
451		*cp1 = *cp2 = '\0';
452		cp1 = strstr(osbuild, "#");
453	} else
454		cp1 = NULL;
455	if (cp1)
456		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
457	else
458#endif
459		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
460}
461
462/*
463 * Get OS builder
464 */
465static void
466linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
467{
468#if 0
469	char builder[256];
470	char *cp;
471
472	cp = strstr(version, "\n    ");
473	if (cp) {
474		strncpy(builder, cp + 5, 256);
475		builder[255] = '\0';
476		cp = strstr(builder, ":");
477		if (cp)
478			*cp = '\0';
479	}
480	if (cp)
481		sbuf_cat(sb, builder);
482	else
483#endif
484		sbuf_cat(sb, "des@freebsd.org");
485}
486
487/*
488 * Filler function for proc/version
489 */
490static int
491linprocfs_doversion(PFS_FILL_ARGS)
492{
493	char osname[LINUX_MAX_UTSNAME];
494	char osrelease[LINUX_MAX_UTSNAME];
495
496	linux_get_osname(td, osname);
497	linux_get_osrelease(td, osrelease);
498	sbuf_printf(sb, "%s version %s (", osname, osrelease);
499	linprocfs_osbuilder(td, sb);
500	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
501	linprocfs_osbuild(td, sb);
502	sbuf_cat(sb, "\n");
503
504	return (0);
505}
506
507/*
508 * Filler function for proc/loadavg
509 */
510static int
511linprocfs_doloadavg(PFS_FILL_ARGS)
512{
513
514	sbuf_printf(sb,
515	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
516	    (int)(averunnable.ldavg[0] / averunnable.fscale),
517	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
518	    (int)(averunnable.ldavg[1] / averunnable.fscale),
519	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
520	    (int)(averunnable.ldavg[2] / averunnable.fscale),
521	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
522	    1,				/* number of running tasks */
523	    nprocs,			/* number of tasks */
524	    lastpid			/* the last pid */
525	);
526	return (0);
527}
528
529/*
530 * Filler function for proc/pid/stat
531 */
532static int
533linprocfs_doprocstat(PFS_FILL_ARGS)
534{
535	struct kinfo_proc kp;
536	char state;
537	static int ratelimit = 0;
538
539	PROC_LOCK(p);
540	fill_kinfo_proc(p, &kp);
541	sbuf_printf(sb, "%d", p->p_pid);
542#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
543	PS_ADD("comm",		"(%s)",	p->p_comm);
544	if (kp.ki_stat > sizeof(linux_state)) {
545		state = 'R';
546
547		if (ratelimit == 0) {
548			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
549			    kp.ki_stat, sizeof(linux_state));
550			++ratelimit;
551		}
552	} else
553		state = linux_state[kp.ki_stat - 1];
554	PS_ADD("state",		"%c",	state);
555	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
556	PS_ADD("pgrp",		"%d",	p->p_pgid);
557	PS_ADD("session",	"%d",	p->p_session->s_sid);
558	PROC_UNLOCK(p);
559	PS_ADD("tty",		"%d",	0); /* XXX */
560	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
561	PS_ADD("flags",		"%u",	0); /* XXX */
562	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
563	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
564	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
565	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
566	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
567	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
568	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
569	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
570	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
571	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
572	PS_ADD("0",		"%d",	0); /* removed field */
573	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
574	/* XXX: starttime is not right, it is the _same_ for _every_ process.
575	   It should be the number of jiffies between system boot and process
576	   start. */
577	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
578	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
579	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
580	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
581	PS_ADD("startcode",	"%u",	(unsigned)0);
582	PS_ADD("endcode",	"%u",	0); /* XXX */
583	PS_ADD("startstack",	"%u",	0); /* XXX */
584	PS_ADD("kstkesp",	"%u",	0); /* XXX */
585	PS_ADD("kstkeip",	"%u",	0); /* XXX */
586	PS_ADD("signal",	"%u",	0); /* XXX */
587	PS_ADD("blocked",	"%u",	0); /* XXX */
588	PS_ADD("sigignore",	"%u",	0); /* XXX */
589	PS_ADD("sigcatch",	"%u",	0); /* XXX */
590	PS_ADD("wchan",		"%u",	0); /* XXX */
591	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
592	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
593	PS_ADD("exitsignal",	"%d",	0); /* XXX */
594	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
595	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
596	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
597#undef PS_ADD
598	sbuf_putc(sb, '\n');
599
600	return (0);
601}
602
603/*
604 * Filler function for proc/pid/statm
605 */
606static int
607linprocfs_doprocstatm(PFS_FILL_ARGS)
608{
609	struct kinfo_proc kp;
610	segsz_t lsize;
611
612	PROC_LOCK(p);
613	fill_kinfo_proc(p, &kp);
614	PROC_UNLOCK(p);
615
616	/*
617	 * See comments in linprocfs_doprocstatus() regarding the
618	 * computation of lsize.
619	 */
620	/* size resident share trs drs lrs dt */
621	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
622	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
623	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
624	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
625	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
626	lsize = B2P(kp.ki_size) - kp.ki_dsize -
627	    kp.ki_ssize - kp.ki_tsize - 1;
628	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
629	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
630
631	return (0);
632}
633
634/*
635 * Filler function for proc/pid/status
636 */
637static int
638linprocfs_doprocstatus(PFS_FILL_ARGS)
639{
640	struct kinfo_proc kp;
641	char *state;
642	segsz_t lsize;
643	struct thread *td2;
644	struct sigacts *ps;
645	int i;
646
647	PROC_LOCK(p);
648	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
649
650	if (P_SHOULDSTOP(p)) {
651		state = "T (stopped)";
652	} else {
653		PROC_SLOCK(p);
654		switch(p->p_state) {
655		case PRS_NEW:
656			state = "I (idle)";
657			break;
658		case PRS_NORMAL:
659			if (p->p_flag & P_WEXIT) {
660				state = "X (exiting)";
661				break;
662			}
663			switch(td2->td_state) {
664			case TDS_INHIBITED:
665				state = "S (sleeping)";
666				break;
667			case TDS_RUNQ:
668			case TDS_RUNNING:
669				state = "R (running)";
670				break;
671			default:
672				state = "? (unknown)";
673				break;
674			}
675			break;
676		case PRS_ZOMBIE:
677			state = "Z (zombie)";
678			break;
679		default:
680			state = "? (unknown)";
681			break;
682		}
683		PROC_SUNLOCK(p);
684	}
685
686	fill_kinfo_proc(p, &kp);
687	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
688	sbuf_printf(sb, "State:\t%s\n",		state);
689
690	/*
691	 * Credentials
692	 */
693	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
694	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
695						p->p_pptr->p_pid : 0);
696	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
697						p->p_ucred->cr_uid,
698						p->p_ucred->cr_svuid,
699						/* FreeBSD doesn't have fsuid */
700						p->p_ucred->cr_uid);
701	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
702						p->p_ucred->cr_gid,
703						p->p_ucred->cr_svgid,
704						/* FreeBSD doesn't have fsgid */
705						p->p_ucred->cr_gid);
706	sbuf_cat(sb, "Groups:\t");
707	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
708		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
709	PROC_UNLOCK(p);
710	sbuf_putc(sb, '\n');
711
712	/*
713	 * Memory
714	 *
715	 * While our approximation of VmLib may not be accurate (I
716	 * don't know of a simple way to verify it, and I'm not sure
717	 * it has much meaning anyway), I believe it's good enough.
718	 *
719	 * The same code that could (I think) accurately compute VmLib
720	 * could also compute VmLck, but I don't really care enough to
721	 * implement it. Submissions are welcome.
722	 */
723	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
724	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
725	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
726	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
727	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
728	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
729	lsize = B2P(kp.ki_size) - kp.ki_dsize -
730	    kp.ki_ssize - kp.ki_tsize - 1;
731	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
732
733	/*
734	 * Signal masks
735	 *
736	 * We support up to 128 signals, while Linux supports 32,
737	 * but we only define 32 (the same 32 as Linux, to boot), so
738	 * just show the lower 32 bits of each mask. XXX hack.
739	 *
740	 * NB: on certain platforms (Sparc at least) Linux actually
741	 * supports 64 signals, but this code is a long way from
742	 * running on anything but i386, so ignore that for now.
743	 */
744	PROC_LOCK(p);
745	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
746	/*
747	 * I can't seem to find out where the signal mask is in
748	 * relation to struct proc, so SigBlk is left unimplemented.
749	 */
750	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
751	ps = p->p_sigacts;
752	mtx_lock(&ps->ps_mtx);
753	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
754	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
755	mtx_unlock(&ps->ps_mtx);
756	PROC_UNLOCK(p);
757
758	/*
759	 * Linux also prints the capability masks, but we don't have
760	 * capabilities yet, and when we do get them they're likely to
761	 * be meaningless to Linux programs, so we lie. XXX
762	 */
763	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
764	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
765	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
766
767	return (0);
768}
769
770
771/*
772 * Filler function for proc/pid/cwd
773 */
774static int
775linprocfs_doproccwd(PFS_FILL_ARGS)
776{
777	char *fullpath = "unknown";
778	char *freepath = NULL;
779
780	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
781	sbuf_printf(sb, "%s", fullpath);
782	if (freepath)
783		free(freepath, M_TEMP);
784	return (0);
785}
786
787/*
788 * Filler function for proc/pid/root
789 */
790static int
791linprocfs_doprocroot(PFS_FILL_ARGS)
792{
793	struct vnode *rvp;
794	char *fullpath = "unknown";
795	char *freepath = NULL;
796
797	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
798	vn_fullpath(td, rvp, &fullpath, &freepath);
799	sbuf_printf(sb, "%s", fullpath);
800	if (freepath)
801		free(freepath, M_TEMP);
802	return (0);
803}
804
805/*
806 * Filler function for proc/pid/cmdline
807 */
808static int
809linprocfs_doproccmdline(PFS_FILL_ARGS)
810{
811	struct ps_strings pstr;
812	char **ps_argvstr;
813	int error, i;
814
815	/*
816	 * If we are using the ps/cmdline caching, use that.  Otherwise
817	 * revert back to the old way which only implements full cmdline
818	 * for the currept process and just p->p_comm for all other
819	 * processes.
820	 * Note that if the argv is no longer available, we deliberately
821	 * don't fall back on p->p_comm or return an error: the authentic
822	 * Linux behaviour is to return zero-length in this case.
823	 */
824
825	PROC_LOCK(p);
826	if (p->p_args && p_cansee(td, p) == 0) {
827		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
828		PROC_UNLOCK(p);
829	} else if (p != td->td_proc) {
830		PROC_UNLOCK(p);
831		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
832	} else {
833		PROC_UNLOCK(p);
834		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
835		    sizeof(pstr));
836		if (error)
837			return (error);
838		if (pstr.ps_nargvstr > ARG_MAX)
839			return (E2BIG);
840		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
841		    M_TEMP, M_WAITOK);
842		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
843		    pstr.ps_nargvstr * sizeof(char *));
844		if (error) {
845			free(ps_argvstr, M_TEMP);
846			return (error);
847		}
848		for (i = 0; i < pstr.ps_nargvstr; i++) {
849			sbuf_copyin(sb, ps_argvstr[i], 0);
850			sbuf_printf(sb, "%c", '\0');
851		}
852		free(ps_argvstr, M_TEMP);
853	}
854
855	return (0);
856}
857
858/*
859 * Filler function for proc/pid/environ
860 */
861static int
862linprocfs_doprocenviron(PFS_FILL_ARGS)
863{
864
865	sbuf_printf(sb, "doprocenviron\n%c", '\0');
866	return (0);
867}
868
869/*
870 * Filler function for proc/pid/maps
871 */
872static int
873linprocfs_doprocmaps(PFS_FILL_ARGS)
874{
875	vm_map_t map = &p->p_vmspace->vm_map;
876	vm_map_entry_t entry;
877	vm_object_t obj, tobj, lobj;
878	vm_offset_t saved_end;
879	vm_ooffset_t off = 0;
880	char *name = "", *freename = NULL;
881	ino_t ino;
882	int ref_count, shadow_count, flags;
883	int error;
884	struct vnode *vp;
885	struct vattr vat;
886	int locked;
887
888	PROC_LOCK(p);
889	error = p_candebug(td, p);
890	PROC_UNLOCK(p);
891	if (error)
892		return (error);
893
894	if (uio->uio_rw != UIO_READ)
895		return (EOPNOTSUPP);
896
897	error = 0;
898	vm_map_lock_read(map);
899	for (entry = map->header.next; entry != &map->header;
900	    entry = entry->next) {
901		name = "";
902		freename = NULL;
903		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
904			continue;
905		saved_end = entry->end;
906		obj = entry->object.vm_object;
907		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
908			VM_OBJECT_LOCK(tobj);
909			if (lobj != obj)
910				VM_OBJECT_UNLOCK(lobj);
911			lobj = tobj;
912		}
913		ino = 0;
914		if (lobj) {
915			off = IDX_TO_OFF(lobj->size);
916			if (lobj->type == OBJT_VNODE) {
917				vp = lobj->handle;
918				if (vp)
919					vref(vp);
920			}
921			else
922				vp = NULL;
923			if (lobj != obj)
924				VM_OBJECT_UNLOCK(lobj);
925			flags = obj->flags;
926			ref_count = obj->ref_count;
927			shadow_count = obj->shadow_count;
928			VM_OBJECT_UNLOCK(obj);
929			if (vp) {
930				vn_fullpath(td, vp, &name, &freename);
931				locked = VFS_LOCK_GIANT(vp->v_mount);
932				vn_lock(vp, LK_SHARED | LK_RETRY);
933				VOP_GETATTR(vp, &vat, td->td_ucred);
934				ino = vat.va_fileid;
935				vput(vp);
936				VFS_UNLOCK_GIANT(locked);
937			}
938		} else {
939			flags = 0;
940			ref_count = 0;
941			shadow_count = 0;
942		}
943
944		/*
945		 * format:
946		 *  start, end, access, offset, major, minor, inode, name.
947		 */
948		error = sbuf_printf(sb,
949		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
950		    (u_long)entry->start, (u_long)entry->end,
951		    (entry->protection & VM_PROT_READ)?"r":"-",
952		    (entry->protection & VM_PROT_WRITE)?"w":"-",
953		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
954		    "p",
955		    (u_long)off,
956		    0,
957		    0,
958		    (u_long)ino,
959		    *name ? "     " : "",
960		    name
961		    );
962		if (freename)
963			free(freename, M_TEMP);
964		if (error == -1) {
965			error = 0;
966			break;
967		}
968	}
969	vm_map_unlock_read(map);
970
971	return (error);
972}
973
974/*
975 * Filler function for proc/net/dev
976 */
977static int
978linprocfs_donetdev(PFS_FILL_ARGS)
979{
980	INIT_VNET_NET(TD_TO_VNET(curthread));
981	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
982	struct ifnet *ifp;
983
984	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
985	    "Inter-", "   Receive", "  Transmit", " face",
986	    "bytes    packets errs drop fifo frame compressed",
987	    "bytes    packets errs drop fifo frame compressed");
988
989	IFNET_RLOCK();
990	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
991		linux_ifname(ifp, ifname, sizeof ifname);
992			sbuf_printf(sb, "%6.6s:", ifname);
993		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
994		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
995		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
996		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
997	}
998	IFNET_RUNLOCK();
999
1000	return (0);
1001}
1002
1003/*
1004 * Filler function for proc/sys/kernel/osrelease
1005 */
1006static int
1007linprocfs_doosrelease(PFS_FILL_ARGS)
1008{
1009	char osrelease[LINUX_MAX_UTSNAME];
1010
1011	linux_get_osrelease(td, osrelease);
1012	sbuf_printf(sb, "%s\n", osrelease);
1013
1014	return (0);
1015}
1016
1017/*
1018 * Filler function for proc/sys/kernel/ostype
1019 */
1020static int
1021linprocfs_doostype(PFS_FILL_ARGS)
1022{
1023	char osname[LINUX_MAX_UTSNAME];
1024
1025	linux_get_osname(td, osname);
1026	sbuf_printf(sb, "%s\n", osname);
1027
1028	return (0);
1029}
1030
1031/*
1032 * Filler function for proc/sys/kernel/version
1033 */
1034static int
1035linprocfs_doosbuild(PFS_FILL_ARGS)
1036{
1037
1038	linprocfs_osbuild(td, sb);
1039	sbuf_cat(sb, "\n");
1040	return (0);
1041}
1042
1043/*
1044 * Filler function for proc/sys/kernel/msgmni
1045 */
1046static int
1047linprocfs_domsgmni(PFS_FILL_ARGS)
1048{
1049
1050	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1051	return (0);
1052}
1053
1054/*
1055 * Filler function for proc/sys/kernel/pid_max
1056 */
1057static int
1058linprocfs_dopid_max(PFS_FILL_ARGS)
1059{
1060
1061	sbuf_printf(sb, "%i\n", PID_MAX);
1062	return (0);
1063}
1064
1065/*
1066 * Filler function for proc/sys/kernel/sem
1067 */
1068static int
1069linprocfs_dosem(PFS_FILL_ARGS)
1070{
1071
1072	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1073	    seminfo.semopm, seminfo.semmni);
1074	return (0);
1075}
1076
1077/*
1078 * Filler function for proc/scsi/device_info
1079 */
1080static int
1081linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1082{
1083
1084	return (0);
1085}
1086
1087/*
1088 * Filler function for proc/scsi/scsi
1089 */
1090static int
1091linprocfs_doscsiscsi(PFS_FILL_ARGS)
1092{
1093
1094	return (0);
1095}
1096
1097extern struct cdevsw *cdevsw[];
1098
1099/*
1100 * Filler function for proc/devices
1101 */
1102static int
1103linprocfs_dodevices(PFS_FILL_ARGS)
1104{
1105	char *char_devices;
1106	sbuf_printf(sb, "Character devices:\n");
1107
1108	char_devices = linux_get_char_devices();
1109	sbuf_printf(sb, "%s", char_devices);
1110	linux_free_get_char_devices(char_devices);
1111
1112	sbuf_printf(sb, "\nBlock devices:\n");
1113
1114	return (0);
1115}
1116
1117/*
1118 * Filler function for proc/cmdline
1119 */
1120static int
1121linprocfs_docmdline(PFS_FILL_ARGS)
1122{
1123
1124	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1125	sbuf_printf(sb, " ro root=302\n");
1126	return (0);
1127}
1128
1129#if 0
1130/*
1131 * Filler function for proc/modules
1132 */
1133static int
1134linprocfs_domodules(PFS_FILL_ARGS)
1135{
1136	struct linker_file *lf;
1137
1138	TAILQ_FOREACH(lf, &linker_files, link) {
1139		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1140		    (unsigned long)lf->size, lf->refs);
1141	}
1142	return (0);
1143}
1144#endif
1145
1146/*
1147 * Constructor
1148 */
1149static int
1150linprocfs_init(PFS_INIT_ARGS)
1151{
1152	struct pfs_node *root;
1153	struct pfs_node *dir;
1154
1155	root = pi->pi_root;
1156
1157	/* /proc/... */
1158	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1159	    NULL, NULL, NULL, PFS_RD);
1160	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1161	    NULL, NULL, NULL, PFS_RD);
1162	pfs_create_file(root, "devices", &linprocfs_dodevices,
1163	    NULL, NULL, NULL, PFS_RD);
1164	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1165	    NULL, NULL, NULL, PFS_RD);
1166	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1167	    NULL, NULL, NULL, PFS_RD);
1168#if 0
1169	pfs_create_file(root, "modules", &linprocfs_domodules,
1170	    NULL, NULL, NULL, PFS_RD);
1171#endif
1172	pfs_create_file(root, "mounts", &linprocfs_domtab,
1173	    NULL, NULL, NULL, PFS_RD);
1174	pfs_create_file(root, "mtab", &linprocfs_domtab,
1175	    NULL, NULL, NULL, PFS_RD);
1176	pfs_create_link(root, "self", &procfs_docurproc,
1177	    NULL, NULL, NULL, 0);
1178	pfs_create_file(root, "stat", &linprocfs_dostat,
1179	    NULL, NULL, NULL, PFS_RD);
1180	pfs_create_file(root, "uptime", &linprocfs_douptime,
1181	    NULL, NULL, NULL, PFS_RD);
1182	pfs_create_file(root, "version", &linprocfs_doversion,
1183	    NULL, NULL, NULL, PFS_RD);
1184
1185	/* /proc/net/... */
1186	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1187	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1188	    NULL, NULL, NULL, PFS_RD);
1189
1190	/* /proc/<pid>/... */
1191	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1192	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1193	    NULL, NULL, NULL, PFS_RD);
1194	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1195	    NULL, NULL, NULL, 0);
1196	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1197	    NULL, NULL, NULL, PFS_RD);
1198	pfs_create_link(dir, "exe", &procfs_doprocfile,
1199	    NULL, &procfs_notsystem, NULL, 0);
1200	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1201	    NULL, NULL, NULL, PFS_RD);
1202	pfs_create_file(dir, "mem", &procfs_doprocmem,
1203	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1204	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1205	    NULL, NULL, NULL, 0);
1206	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1207	    NULL, NULL, NULL, PFS_RD);
1208	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1209	    NULL, NULL, NULL, PFS_RD);
1210	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1211	    NULL, NULL, NULL, PFS_RD);
1212
1213	/* /proc/scsi/... */
1214	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1215	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1216	    NULL, NULL, NULL, PFS_RD);
1217	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1218	    NULL, NULL, NULL, PFS_RD);
1219
1220	/* /proc/sys/... */
1221	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1222	/* /proc/sys/kernel/... */
1223	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1224	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1225	    NULL, NULL, NULL, PFS_RD);
1226	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1227	    NULL, NULL, NULL, PFS_RD);
1228	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1229	    NULL, NULL, NULL, PFS_RD);
1230	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1231	    NULL, NULL, NULL, PFS_RD);
1232	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1233	    NULL, NULL, NULL, PFS_RD);
1234	pfs_create_file(dir, "sem", &linprocfs_dosem,
1235	    NULL, NULL, NULL, PFS_RD);
1236
1237	return (0);
1238}
1239
1240/*
1241 * Destructor
1242 */
1243static int
1244linprocfs_uninit(PFS_INIT_ARGS)
1245{
1246
1247	/* nothing to do, pseudofs will GC */
1248	return (0);
1249}
1250
1251PSEUDOFS(linprocfs, 1);
1252MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1253MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1254MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1255MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1256