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