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