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