xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision f856af0466c076beef4ea9b15d088e1119a945b8)
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 
466 	PROC_LOCK(p);
467 	fill_kinfo_proc(p, &kp);
468 	sbuf_printf(sb, "%d", p->p_pid);
469 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
470 	PS_ADD("comm",		"(%s)",	p->p_comm);
471 	KASSERT(kp.ki_stat <= sizeof(linux_state),
472 		("linprocfs: don't know how to handle unknown FreeBSD state"));
473 	PS_ADD("state",		"%c",	linux_state[kp.ki_stat - 1]);
474 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
475 	PS_ADD("pgrp",		"%d",	p->p_pgid);
476 	PS_ADD("session",	"%d",	p->p_session->s_sid);
477 	PROC_UNLOCK(p);
478 	PS_ADD("tty",		"%d",	0); /* XXX */
479 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
480 	PS_ADD("flags",		"%u",	0); /* XXX */
481 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
482 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
483 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
484 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
485 	PS_ADD("utime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_utime)));
486 	PS_ADD("stime",		"%ld",	T2J(tvtohz(&kp.ki_rusage.ru_stime)));
487 	PS_ADD("cutime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
488 	PS_ADD("cstime",	"%ld",	T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
489 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
490 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
491 	PS_ADD("0",		"%d",	0); /* removed field */
492 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
493 	/* XXX: starttime is not right, it is the _same_ for _every_ process.
494 	   It should be the number of jiffies between system boot and process
495 	   start. */
496 	PS_ADD("starttime",	"%lu",	T2J(tvtohz(&kp.ki_start)));
497 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
498 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
499 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
500 	PS_ADD("startcode",	"%u",	(unsigned)0);
501 	PS_ADD("endcode",	"%u",	0); /* XXX */
502 	PS_ADD("startstack",	"%u",	0); /* XXX */
503 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
504 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
505 	PS_ADD("signal",	"%u",	0); /* XXX */
506 	PS_ADD("blocked",	"%u",	0); /* XXX */
507 	PS_ADD("sigignore",	"%u",	0); /* XXX */
508 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
509 	PS_ADD("wchan",		"%u",	0); /* XXX */
510 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
511 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
512 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
513 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
514 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
515 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
516 #undef PS_ADD
517 	sbuf_putc(sb, '\n');
518 
519 	return (0);
520 }
521 
522 /*
523  * Filler function for proc/pid/statm
524  */
525 static int
526 linprocfs_doprocstatm(PFS_FILL_ARGS)
527 {
528 	struct kinfo_proc kp;
529 	segsz_t lsize;
530 
531 	PROC_LOCK(p);
532 	fill_kinfo_proc(p, &kp);
533 	PROC_UNLOCK(p);
534 
535 	/*
536 	 * See comments in linprocfs_doprocstatus() regarding the
537 	 * computation of lsize.
538 	 */
539 	/* size resident share trs drs lrs dt */
540 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
541 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
542 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
543 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
544 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
545 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
546 	    kp.ki_ssize - kp.ki_tsize - 1;
547 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
548 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
549 
550 	return (0);
551 }
552 
553 /*
554  * Filler function for proc/pid/status
555  */
556 static int
557 linprocfs_doprocstatus(PFS_FILL_ARGS)
558 {
559 	struct kinfo_proc kp;
560 	char *state;
561 	segsz_t lsize;
562 	struct thread *td2;
563 	struct sigacts *ps;
564 	int i;
565 
566 	PROC_LOCK(p);
567 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
568 
569 	if (P_SHOULDSTOP(p)) {
570 		state = "T (stopped)";
571 	} else {
572 		mtx_lock_spin(&sched_lock);
573 		switch(p->p_state) {
574 		case PRS_NEW:
575 			state = "I (idle)";
576 			break;
577 		case PRS_NORMAL:
578 			if (p->p_flag & P_WEXIT) {
579 				state = "X (exiting)";
580 				break;
581 			}
582 			switch(td2->td_state) {
583 			case TDS_INHIBITED:
584 				state = "S (sleeping)";
585 				break;
586 			case TDS_RUNQ:
587 			case TDS_RUNNING:
588 				state = "R (running)";
589 				break;
590 			default:
591 				state = "? (unknown)";
592 				break;
593 			}
594 			break;
595 		case PRS_ZOMBIE:
596 			state = "Z (zombie)";
597 			break;
598 		default:
599 			state = "? (unknown)";
600 			break;
601 		}
602 		mtx_unlock_spin(&sched_lock);
603 	}
604 
605 	fill_kinfo_proc(p, &kp);
606 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
607 	sbuf_printf(sb, "State:\t%s\n",		state);
608 
609 	/*
610 	 * Credentials
611 	 */
612 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
613 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
614 						p->p_pptr->p_pid : 0);
615 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
616 						p->p_ucred->cr_uid,
617 						p->p_ucred->cr_svuid,
618 						/* FreeBSD doesn't have fsuid */
619 						p->p_ucred->cr_uid);
620 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
621 						p->p_ucred->cr_gid,
622 						p->p_ucred->cr_svgid,
623 						/* FreeBSD doesn't have fsgid */
624 						p->p_ucred->cr_gid);
625 	sbuf_cat(sb, "Groups:\t");
626 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
627 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
628 	PROC_UNLOCK(p);
629 	sbuf_putc(sb, '\n');
630 
631 	/*
632 	 * Memory
633 	 *
634 	 * While our approximation of VmLib may not be accurate (I
635 	 * don't know of a simple way to verify it, and I'm not sure
636 	 * it has much meaning anyway), I believe it's good enough.
637 	 *
638 	 * The same code that could (I think) accurately compute VmLib
639 	 * could also compute VmLck, but I don't really care enough to
640 	 * implement it. Submissions are welcome.
641 	 */
642 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
643 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
644 	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
645 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
646 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
647 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
648 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
649 	    kp.ki_ssize - kp.ki_tsize - 1;
650 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
651 
652 	/*
653 	 * Signal masks
654 	 *
655 	 * We support up to 128 signals, while Linux supports 32,
656 	 * but we only define 32 (the same 32 as Linux, to boot), so
657 	 * just show the lower 32 bits of each mask. XXX hack.
658 	 *
659 	 * NB: on certain platforms (Sparc at least) Linux actually
660 	 * supports 64 signals, but this code is a long way from
661 	 * running on anything but i386, so ignore that for now.
662 	 */
663 	PROC_LOCK(p);
664 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
665 	/*
666 	 * I can't seem to find out where the signal mask is in
667 	 * relation to struct proc, so SigBlk is left unimplemented.
668 	 */
669 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
670 	ps = p->p_sigacts;
671 	mtx_lock(&ps->ps_mtx);
672 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
673 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
674 	mtx_unlock(&ps->ps_mtx);
675 	PROC_UNLOCK(p);
676 
677 	/*
678 	 * Linux also prints the capability masks, but we don't have
679 	 * capabilities yet, and when we do get them they're likely to
680 	 * be meaningless to Linux programs, so we lie. XXX
681 	 */
682 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
683 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
684 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
685 
686 	return (0);
687 }
688 
689 
690 /*
691  * Filler function for proc/pid/cwd
692  */
693 static int
694 linprocfs_doproccwd(PFS_FILL_ARGS)
695 {
696 	char *fullpath = "unknown";
697 	char *freepath = NULL;
698 
699 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
700 	sbuf_printf(sb, "%s", fullpath);
701 	if (freepath)
702 		free(freepath, M_TEMP);
703 	return (0);
704 }
705 
706 /*
707  * Filler function for proc/pid/root
708  */
709 static int
710 linprocfs_doprocroot(PFS_FILL_ARGS)
711 {
712 	struct vnode *rvp;
713 	char *fullpath = "unknown";
714 	char *freepath = NULL;
715 
716 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
717 	vn_fullpath(td, rvp, &fullpath, &freepath);
718 	sbuf_printf(sb, "%s", fullpath);
719 	if (freepath)
720 		free(freepath, M_TEMP);
721 	return (0);
722 }
723 
724 /*
725  * Filler function for proc/pid/cmdline
726  */
727 static int
728 linprocfs_doproccmdline(PFS_FILL_ARGS)
729 {
730 	struct ps_strings pstr;
731 	char **ps_argvstr;
732 	int error, i;
733 
734 	/*
735 	 * If we are using the ps/cmdline caching, use that.  Otherwise
736 	 * revert back to the old way which only implements full cmdline
737 	 * for the currept process and just p->p_comm for all other
738 	 * processes.
739 	 * Note that if the argv is no longer available, we deliberately
740 	 * don't fall back on p->p_comm or return an error: the authentic
741 	 * Linux behaviour is to return zero-length in this case.
742 	 */
743 
744 	PROC_LOCK(p);
745 	if (p->p_args && p_cansee(td, p) == 0) {
746 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
747 		PROC_UNLOCK(p);
748 	} else if (p != td->td_proc) {
749 		PROC_UNLOCK(p);
750 		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
751 	} else {
752 		PROC_UNLOCK(p);
753 		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
754 		    sizeof(pstr));
755 		if (error)
756 			return (error);
757 		if (pstr.ps_nargvstr > ARG_MAX)
758 			return (E2BIG);
759 		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
760 		    M_TEMP, M_WAITOK);
761 		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
762 		    pstr.ps_nargvstr * sizeof(char *));
763 		if (error) {
764 			free(ps_argvstr, M_TEMP);
765 			return (error);
766 		}
767 		for (i = 0; i < pstr.ps_nargvstr; i++) {
768 			sbuf_copyin(sb, ps_argvstr[i], 0);
769 			sbuf_printf(sb, "%c", '\0');
770 		}
771 		free(ps_argvstr, M_TEMP);
772 	}
773 
774 	return (0);
775 }
776 
777 /*
778  * Filler function for proc/pid/environ
779  */
780 static int
781 linprocfs_doprocenviron(PFS_FILL_ARGS)
782 {
783 	sbuf_printf(sb, "doprocenviron\n%c", '\0');
784 
785 	return (0);
786 }
787 
788 /*
789  * Filler function for proc/pid/maps
790  */
791 static int
792 linprocfs_doprocmaps(PFS_FILL_ARGS)
793 {
794 	char mebuffer[512];
795 	vm_map_t map = &p->p_vmspace->vm_map;
796 	vm_map_entry_t entry;
797 	vm_object_t obj, tobj, lobj;
798 	vm_ooffset_t off = 0;
799 	char *name = "", *freename = NULL;
800 	size_t len;
801 	ino_t ino;
802 	int ref_count, shadow_count, flags;
803 	int error;
804 	struct vnode *vp;
805 	struct vattr vat;
806 	int locked;
807 
808 	PROC_LOCK(p);
809 	error = p_candebug(td, p);
810 	PROC_UNLOCK(p);
811 	if (error)
812 		return (error);
813 
814 	if (uio->uio_rw != UIO_READ)
815 		return (EOPNOTSUPP);
816 
817 	if (uio->uio_offset != 0)
818 		return (0);
819 
820 	error = 0;
821 	if (map != &curthread->td_proc->p_vmspace->vm_map)
822 		vm_map_lock_read(map);
823         for (entry = map->header.next;
824 	    ((uio->uio_resid > 0) && (entry != &map->header));
825 	    entry = entry->next) {
826 		name = "";
827 		freename = NULL;
828 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
829 			continue;
830 		obj = entry->object.vm_object;
831 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
832 			lobj = tobj;
833 		ino = 0;
834 		if (lobj) {
835 			VM_OBJECT_LOCK(lobj);
836 			off = IDX_TO_OFF(lobj->size);
837 			if (lobj->type == OBJT_VNODE) {
838 				vp = lobj->handle;
839 				if (vp)
840 					vref(vp);
841 			}
842 			else
843 				vp = NULL;
844 			flags = obj->flags;
845 			ref_count = obj->ref_count;
846 			shadow_count = obj->shadow_count;
847 			VM_OBJECT_UNLOCK(lobj);
848 			if (vp) {
849 				vn_fullpath(td, vp, &name, &freename);
850 				locked = VFS_LOCK_GIANT(vp->v_mount);
851 				vn_lock(vp, LK_SHARED | LK_RETRY, td);
852 				VOP_GETATTR(vp, &vat, td->td_ucred, td);
853 				ino = vat.va_fileid;
854 				vput(vp);
855 				VFS_UNLOCK_GIANT(locked);
856 			}
857 		} else {
858 			flags = 0;
859 			ref_count = 0;
860 			shadow_count = 0;
861 		}
862 
863 		/*
864 	     	 * format:
865 		 *  start, end, access, offset, major, minor, inode, name.
866 		 */
867 		snprintf(mebuffer, sizeof mebuffer,
868 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
869 		    (u_long)entry->start, (u_long)entry->end,
870 		    (entry->protection & VM_PROT_READ)?"r":"-",
871 		    (entry->protection & VM_PROT_WRITE)?"w":"-",
872 		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
873 		    "p",
874 		    (u_long)off,
875 		    0,
876 		    0,
877 		    (u_long)ino,
878 		    *name ? "     " : "",
879 		    name
880 		    );
881 		if (freename)
882 			free(freename, M_TEMP);
883 		len = strlen(mebuffer);
884 		if (len > uio->uio_resid)
885 			len = uio->uio_resid; /*
886 					       * XXX We should probably return
887 					       * EFBIG here, as in procfs.
888 					       */
889 		error = uiomove(mebuffer, len, uio);
890 		if (error)
891 			break;
892 	}
893 	if (map != &curthread->td_proc->p_vmspace->vm_map)
894 		vm_map_unlock_read(map);
895 
896 	return (error);
897 }
898 
899 /*
900  * Filler function for proc/net/dev
901  */
902 static int
903 linprocfs_donetdev(PFS_FILL_ARGS)
904 {
905 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
906 	struct ifnet *ifp;
907 
908 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
909 	    "Inter-", "   Receive", "  Transmit", " face",
910 	    "bytes    packets errs drop fifo frame compressed",
911 	    "bytes    packets errs drop fifo frame compressed");
912 
913 	IFNET_RLOCK();
914 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
915 		linux_ifname(ifp, ifname, sizeof ifname);
916 			sbuf_printf(sb, "%6.6s:", ifname);
917 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
918 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
919 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
920 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
921 	}
922 	IFNET_RUNLOCK();
923 
924 	return (0);
925 }
926 
927 /*
928  * Filler function for proc/sys/kernel/msgmni
929  */
930 static int
931 linprocfs_domsgmni(PFS_FILL_ARGS)
932 {
933 	int msgmni;
934 	size_t size;
935 
936 	size = sizeof(msgmni);
937 	if (kernel_sysctlbyname(td, "kern.ipc.msgmni", &msgmni, &size,
938 	    0, 0, 0, 0) != 0)
939 		msgmni = 0;
940 	sbuf_printf(sb, "%i\n", msgmni);
941 
942 	return (0);
943 }
944 
945 /*
946  * Filler function for proc/sys/kernel/pid_max
947  */
948 static int
949 linprocfs_dopid_max(PFS_FILL_ARGS)
950 {
951 
952 	sbuf_printf(sb, "%i\n", PID_MAX);
953 
954 	return (0);
955 }
956 
957 /*
958  * Filler function for proc/sys/kernel/sem
959  */
960 static int
961 linprocfs_dosem(PFS_FILL_ARGS)
962 {
963 	int semmsl, semmns, semopm, semmni;
964 	size_t size;
965 
966 	/* Field 1: SEMMSL */
967 	size = sizeof(semmsl);
968 	if (kernel_sysctlbyname(td, "kern.ipc.semmsl", &semmsl, &size,
969 	    0, 0, 0, 0) != 0)
970 		semmsl = 0;
971 
972 	/* Field 2: SEMMNS */
973 	size = sizeof(semmns);
974 	if (kernel_sysctlbyname(td, "kern.ipc.semmns", &semmns, &size,
975 	    0, 0, 0, 0) != 0)
976 		semmns = 0;
977 
978 	/* Field 3: SEMOPM */
979 	size = sizeof(semopm);
980 	if (kernel_sysctlbyname(td, "kern.ipc.semopm", &semopm, &size,
981 	    0, 0, 0, 0) != 0)
982 		semopm = 0;
983 
984 	/* Field 4: SEMMNI */
985 	size = sizeof(semmni);
986 	if (kernel_sysctlbyname(td, "kern.ipc.semmni", &semmni, &size,
987 	    0, 0, 0, 0) != 0)
988 		semmni = 0;
989 
990 	sbuf_printf(sb, "%i %i %i %i\n", semmsl, semmns, semopm, semmni);
991 
992 	return (0);
993 }
994 
995 /*
996  * Filler function for proc/scsi/device_info
997  */
998 static int
999 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1000 {
1001 	return (0);
1002 }
1003 
1004 /*
1005  * Filler function for proc/scsi/scsi
1006  */
1007 static int
1008 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1009 {
1010 	return (0);
1011 }
1012 
1013 extern struct cdevsw *cdevsw[];
1014 
1015 /*
1016  * Filler function for proc/devices
1017  */
1018 static int
1019 linprocfs_dodevices(PFS_FILL_ARGS)
1020 {
1021 	char *char_devices;
1022 	sbuf_printf(sb, "Character devices:\n");
1023 
1024 	char_devices = linux_get_char_devices();
1025 	sbuf_printf(sb, "%s", char_devices);
1026 	linux_free_get_char_devices(char_devices);
1027 
1028 	sbuf_printf(sb, "\nBlock devices:\n");
1029 
1030 	return (0);
1031 }
1032 
1033 /*
1034  * Filler function for proc/cmdline
1035  */
1036 static int
1037 linprocfs_docmdline(PFS_FILL_ARGS)
1038 {
1039 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1040 	sbuf_printf(sb, " ro root=302\n");
1041 	return (0);
1042 }
1043 
1044 #if 0
1045 /*
1046  * Filler function for proc/modules
1047  */
1048 static int
1049 linprocfs_domodules(PFS_FILL_ARGS)
1050 {
1051 	struct linker_file *lf;
1052 
1053 	TAILQ_FOREACH(lf, &linker_files, link) {
1054 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1055 		    (unsigned long)lf->size, lf->refs);
1056 	}
1057 	return (0);
1058 }
1059 #endif
1060 
1061 /*
1062  * Constructor
1063  */
1064 static int
1065 linprocfs_init(PFS_INIT_ARGS)
1066 {
1067 	struct pfs_node *root;
1068 	struct pfs_node *dir;
1069 
1070 	root = pi->pi_root;
1071 
1072 	/* /proc/... */
1073 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1074 	    NULL, NULL, PFS_RD);
1075 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1076 	    NULL, NULL, PFS_RD);
1077 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1078 	    NULL, NULL, PFS_RD);
1079 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1080 	    NULL, NULL, PFS_RD);
1081 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1082 	    NULL, NULL, PFS_RD);
1083 #if 0
1084 	pfs_create_file(root, "modules", &linprocfs_domodules,
1085 	    NULL, NULL, PFS_RD);
1086 #endif
1087 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1088 	    NULL, NULL, PFS_RD);
1089 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1090 	    NULL, NULL, PFS_RD);
1091 	pfs_create_link(root, "self", &procfs_docurproc,
1092 	    NULL, NULL, 0);
1093 	pfs_create_file(root, "stat", &linprocfs_dostat,
1094 	    NULL, NULL, PFS_RD);
1095 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1096 	    NULL, NULL, PFS_RD);
1097 	pfs_create_file(root, "version", &linprocfs_doversion,
1098 	    NULL, NULL, PFS_RD);
1099 
1100 	/* /proc/net/... */
1101 	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1102 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1103 	    NULL, NULL, PFS_RD);
1104 
1105 	/* /proc/<pid>/... */
1106 	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1107 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1108 	    NULL, NULL, PFS_RD);
1109 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1110 	    NULL, NULL, 0);
1111 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1112 	    NULL, NULL, PFS_RD);
1113 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1114 	    NULL, &procfs_notsystem, 0);
1115 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1116 	    NULL, NULL, PFS_RD);
1117 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1118 	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1119 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1120 	    NULL, NULL, 0);
1121 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1122 	    NULL, NULL, PFS_RD);
1123 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1124 	    NULL, NULL, PFS_RD);
1125 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1126 	    NULL, NULL, PFS_RD);
1127 
1128 	/* /proc/scsi/... */
1129 	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1130 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1131 	    NULL, NULL, PFS_RD);
1132 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1133 	    NULL, NULL, PFS_RD);
1134 
1135 	/* /proc/sys/... */
1136 	dir = pfs_create_dir(root, "sys", NULL, NULL, 0);
1137 	/* /proc/sys/kernel/... */
1138 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0);
1139 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1140 	    NULL, NULL, PFS_RD);
1141 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1142 	    NULL, NULL, PFS_RD);
1143 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1144 	    NULL, NULL, PFS_RD);
1145 
1146 	return (0);
1147 }
1148 
1149 /*
1150  * Destructor
1151  */
1152 static int
1153 linprocfs_uninit(PFS_INIT_ARGS)
1154 {
1155 
1156 	/* nothing to do, pseudofs will GC */
1157 	return (0);
1158 }
1159 
1160 PSEUDOFS(linprocfs, 1);
1161 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1162 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1163