xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision 5519971c21c31e49df9b7cea2da25cb9803d2388)
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 /*
506  * Filler function for proc/uptime
507  */
508 static int
509 linprocfs_douptime(PFS_FILL_ARGS)
510 {
511 	long cp_time[CPUSTATES];
512 	struct timeval tv;
513 
514 	getmicrouptime(&tv);
515 	read_cpu_time(cp_time);
516 	sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
517 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
518 	    T2S(cp_time[CP_IDLE] / mp_ncpus),
519 	    T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
520 	return (0);
521 }
522 
523 /*
524  * Get OS build date
525  */
526 static void
527 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
528 {
529 #if 0
530 	char osbuild[256];
531 	char *cp1, *cp2;
532 
533 	strncpy(osbuild, version, 256);
534 	osbuild[255] = '\0';
535 	cp1 = strstr(osbuild, "\n");
536 	cp2 = strstr(osbuild, ":");
537 	if (cp1 && cp2) {
538 		*cp1 = *cp2 = '\0';
539 		cp1 = strstr(osbuild, "#");
540 	} else
541 		cp1 = NULL;
542 	if (cp1)
543 		sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
544 	else
545 #endif
546 		sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
547 }
548 
549 /*
550  * Get OS builder
551  */
552 static void
553 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
554 {
555 #if 0
556 	char builder[256];
557 	char *cp;
558 
559 	cp = strstr(version, "\n    ");
560 	if (cp) {
561 		strncpy(builder, cp + 5, 256);
562 		builder[255] = '\0';
563 		cp = strstr(builder, ":");
564 		if (cp)
565 			*cp = '\0';
566 	}
567 	if (cp)
568 		sbuf_cat(sb, builder);
569 	else
570 #endif
571 		sbuf_cat(sb, "des@freebsd.org");
572 }
573 
574 /*
575  * Filler function for proc/version
576  */
577 static int
578 linprocfs_doversion(PFS_FILL_ARGS)
579 {
580 	char osname[LINUX_MAX_UTSNAME];
581 	char osrelease[LINUX_MAX_UTSNAME];
582 
583 	linux_get_osname(td, osname);
584 	linux_get_osrelease(td, osrelease);
585 	sbuf_printf(sb, "%s version %s (", osname, osrelease);
586 	linprocfs_osbuilder(td, sb);
587 	sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
588 	linprocfs_osbuild(td, sb);
589 	sbuf_cat(sb, "\n");
590 
591 	return (0);
592 }
593 
594 /*
595  * Filler function for proc/loadavg
596  */
597 static int
598 linprocfs_doloadavg(PFS_FILL_ARGS)
599 {
600 
601 	sbuf_printf(sb,
602 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
603 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
604 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
605 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
606 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
607 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
608 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
609 	    1,				/* number of running tasks */
610 	    nprocs,			/* number of tasks */
611 	    lastpid			/* the last pid */
612 	);
613 	return (0);
614 }
615 
616 /*
617  * Filler function for proc/pid/stat
618  */
619 static int
620 linprocfs_doprocstat(PFS_FILL_ARGS)
621 {
622 	struct kinfo_proc kp;
623 	char state;
624 	static int ratelimit = 0;
625 	vm_offset_t startcode, startdata;
626 
627 	PROC_LOCK(p);
628 	fill_kinfo_proc(p, &kp);
629 	if (p->p_vmspace) {
630 	   startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
631 	   startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
632 	} else {
633 	   startcode = 0;
634 	   startdata = 0;
635 	};
636 	sbuf_printf(sb, "%d", p->p_pid);
637 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
638 	PS_ADD("comm",		"(%s)",	p->p_comm);
639 	if (kp.ki_stat > sizeof(linux_state)) {
640 		state = 'R';
641 
642 		if (ratelimit == 0) {
643 			printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
644 			    kp.ki_stat, sizeof(linux_state));
645 			++ratelimit;
646 		}
647 	} else
648 		state = linux_state[kp.ki_stat - 1];
649 	PS_ADD("state",		"%c",	state);
650 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
651 	PS_ADD("pgrp",		"%d",	p->p_pgid);
652 	PS_ADD("session",	"%d",	p->p_session->s_sid);
653 	PROC_UNLOCK(p);
654 	PS_ADD("tty",		"%d",	kp.ki_tdev);
655 	PS_ADD("tpgid",		"%d",	kp.ki_tpgid);
656 	PS_ADD("flags",		"%u",	0); /* XXX */
657 	PS_ADD("minflt",	"%lu",	kp.ki_rusage.ru_minflt);
658 	PS_ADD("cminflt",	"%lu",	kp.ki_rusage_ch.ru_minflt);
659 	PS_ADD("majflt",	"%lu",	kp.ki_rusage.ru_majflt);
660 	PS_ADD("cmajflt",	"%lu",	kp.ki_rusage_ch.ru_majflt);
661 	PS_ADD("utime",		"%ld",	TV2J(&kp.ki_rusage.ru_utime));
662 	PS_ADD("stime",		"%ld",	TV2J(&kp.ki_rusage.ru_stime));
663 	PS_ADD("cutime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_utime));
664 	PS_ADD("cstime",	"%ld",	TV2J(&kp.ki_rusage_ch.ru_stime));
665 	PS_ADD("priority",	"%d",	kp.ki_pri.pri_user);
666 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
667 	PS_ADD("0",		"%d",	0); /* removed field */
668 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
669 	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
670 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
671 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
672 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
673 	PS_ADD("startcode",	"%ju",	(uintmax_t)startcode);
674 	PS_ADD("endcode",	"%ju",	(uintmax_t)startdata);
675 	PS_ADD("startstack",	"%u",	0); /* XXX */
676 	PS_ADD("kstkesp",	"%u",	0); /* XXX */
677 	PS_ADD("kstkeip",	"%u",	0); /* XXX */
678 	PS_ADD("signal",	"%u",	0); /* XXX */
679 	PS_ADD("blocked",	"%u",	0); /* XXX */
680 	PS_ADD("sigignore",	"%u",	0); /* XXX */
681 	PS_ADD("sigcatch",	"%u",	0); /* XXX */
682 	PS_ADD("wchan",		"%u",	0); /* XXX */
683 	PS_ADD("nswap",		"%lu",	kp.ki_rusage.ru_nswap);
684 	PS_ADD("cnswap",	"%lu",	kp.ki_rusage_ch.ru_nswap);
685 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
686 	PS_ADD("processor",	"%u",	kp.ki_lastcpu);
687 	PS_ADD("rt_priority",	"%u",	0); /* XXX */ /* >= 2.5.19 */
688 	PS_ADD("policy",	"%u",	kp.ki_pri.pri_class); /* >= 2.5.19 */
689 #undef PS_ADD
690 	sbuf_putc(sb, '\n');
691 
692 	return (0);
693 }
694 
695 /*
696  * Filler function for proc/pid/statm
697  */
698 static int
699 linprocfs_doprocstatm(PFS_FILL_ARGS)
700 {
701 	struct kinfo_proc kp;
702 	segsz_t lsize;
703 
704 	PROC_LOCK(p);
705 	fill_kinfo_proc(p, &kp);
706 	PROC_UNLOCK(p);
707 
708 	/*
709 	 * See comments in linprocfs_doprocstatus() regarding the
710 	 * computation of lsize.
711 	 */
712 	/* size resident share trs drs lrs dt */
713 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
714 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
715 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
716 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
717 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
718 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
719 	    kp.ki_ssize - kp.ki_tsize - 1;
720 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
721 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
722 
723 	return (0);
724 }
725 
726 /*
727  * Filler function for proc/pid/status
728  */
729 static int
730 linprocfs_doprocstatus(PFS_FILL_ARGS)
731 {
732 	struct kinfo_proc kp;
733 	char *state;
734 	segsz_t lsize;
735 	struct thread *td2;
736 	struct sigacts *ps;
737 	int i;
738 
739 	PROC_LOCK(p);
740 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
741 
742 	if (P_SHOULDSTOP(p)) {
743 		state = "T (stopped)";
744 	} else {
745 		switch(p->p_state) {
746 		case PRS_NEW:
747 			state = "I (idle)";
748 			break;
749 		case PRS_NORMAL:
750 			if (p->p_flag & P_WEXIT) {
751 				state = "X (exiting)";
752 				break;
753 			}
754 			switch(td2->td_state) {
755 			case TDS_INHIBITED:
756 				state = "S (sleeping)";
757 				break;
758 			case TDS_RUNQ:
759 			case TDS_RUNNING:
760 				state = "R (running)";
761 				break;
762 			default:
763 				state = "? (unknown)";
764 				break;
765 			}
766 			break;
767 		case PRS_ZOMBIE:
768 			state = "Z (zombie)";
769 			break;
770 		default:
771 			state = "? (unknown)";
772 			break;
773 		}
774 	}
775 
776 	fill_kinfo_proc(p, &kp);
777 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
778 	sbuf_printf(sb, "State:\t%s\n",		state);
779 
780 	/*
781 	 * Credentials
782 	 */
783 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
784 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
785 						p->p_pptr->p_pid : 0);
786 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
787 						p->p_ucred->cr_uid,
788 						p->p_ucred->cr_svuid,
789 						/* FreeBSD doesn't have fsuid */
790 						p->p_ucred->cr_uid);
791 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
792 						p->p_ucred->cr_gid,
793 						p->p_ucred->cr_svgid,
794 						/* FreeBSD doesn't have fsgid */
795 						p->p_ucred->cr_gid);
796 	sbuf_cat(sb, "Groups:\t");
797 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
798 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
799 	PROC_UNLOCK(p);
800 	sbuf_putc(sb, '\n');
801 
802 	/*
803 	 * Memory
804 	 *
805 	 * While our approximation of VmLib may not be accurate (I
806 	 * don't know of a simple way to verify it, and I'm not sure
807 	 * it has much meaning anyway), I believe it's good enough.
808 	 *
809 	 * The same code that could (I think) accurately compute VmLib
810 	 * could also compute VmLck, but I don't really care enough to
811 	 * implement it. Submissions are welcome.
812 	 */
813 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
814 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
815 	sbuf_printf(sb, "VmRSS:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
816 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
817 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
818 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
819 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
820 	    kp.ki_ssize - kp.ki_tsize - 1;
821 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
822 
823 	/*
824 	 * Signal masks
825 	 *
826 	 * We support up to 128 signals, while Linux supports 32,
827 	 * but we only define 32 (the same 32 as Linux, to boot), so
828 	 * just show the lower 32 bits of each mask. XXX hack.
829 	 *
830 	 * NB: on certain platforms (Sparc at least) Linux actually
831 	 * supports 64 signals, but this code is a long way from
832 	 * running on anything but i386, so ignore that for now.
833 	 */
834 	PROC_LOCK(p);
835 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
836 	/*
837 	 * I can't seem to find out where the signal mask is in
838 	 * relation to struct proc, so SigBlk is left unimplemented.
839 	 */
840 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
841 	ps = p->p_sigacts;
842 	mtx_lock(&ps->ps_mtx);
843 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
844 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
845 	mtx_unlock(&ps->ps_mtx);
846 	PROC_UNLOCK(p);
847 
848 	/*
849 	 * Linux also prints the capability masks, but we don't have
850 	 * capabilities yet, and when we do get them they're likely to
851 	 * be meaningless to Linux programs, so we lie. XXX
852 	 */
853 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
854 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
855 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
856 
857 	return (0);
858 }
859 
860 
861 /*
862  * Filler function for proc/pid/cwd
863  */
864 static int
865 linprocfs_doproccwd(PFS_FILL_ARGS)
866 {
867 	char *fullpath = "unknown";
868 	char *freepath = NULL;
869 
870 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
871 	sbuf_printf(sb, "%s", fullpath);
872 	if (freepath)
873 		free(freepath, M_TEMP);
874 	return (0);
875 }
876 
877 /*
878  * Filler function for proc/pid/root
879  */
880 static int
881 linprocfs_doprocroot(PFS_FILL_ARGS)
882 {
883 	struct vnode *rvp;
884 	char *fullpath = "unknown";
885 	char *freepath = NULL;
886 
887 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
888 	vn_fullpath(td, rvp, &fullpath, &freepath);
889 	sbuf_printf(sb, "%s", fullpath);
890 	if (freepath)
891 		free(freepath, M_TEMP);
892 	return (0);
893 }
894 
895 #define MAX_ARGV_STR	512	/* Max number of argv-like strings */
896 #define UIO_CHUNK_SZ	256	/* Max chunk size (bytes) for uiomove */
897 
898 static int
899 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
900     void (*resolver)(const struct ps_strings, u_long *, int *))
901 {
902 	struct iovec iov;
903 	struct uio tmp_uio;
904 	struct ps_strings pss;
905 	int ret, i, n_elements, elm_len;
906 	u_long addr, pbegin;
907 	char **env_vector, *envp;
908 	char env_string[UIO_CHUNK_SZ];
909 #ifdef COMPAT_FREEBSD32
910 	struct freebsd32_ps_strings pss32;
911 	uint32_t *env_vector32;
912 #endif
913 
914 #define	UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td)	\
915 do {									\
916 	iov.iov_base = (caddr_t)(base);					\
917 	iov.iov_len = (len); 						\
918 	uio.uio_iov = &(iov); 						\
919 	uio.uio_iovcnt = (cnt);	 					\
920 	uio.uio_offset = (off_t)(offset);				\
921 	uio.uio_resid = (sz); 						\
922 	uio.uio_segflg = (flg);						\
923 	uio.uio_rw = (rw); 						\
924 	uio.uio_td = (td);						\
925 } while (0)
926 
927 	env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
928 
929 #ifdef COMPAT_FREEBSD32
930 	env_vector32 = NULL;
931 	if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
932 		env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
933 		    M_TEMP, M_WAITOK);
934 		elm_len = sizeof(int32_t);
935 		envp = (char *)env_vector32;
936 
937 		UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
938 		    (off_t)(p->p_sysent->sv_psstrings),
939 		    sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
940 		ret = proc_rwmem(p, &tmp_uio);
941 		if (ret != 0)
942 			goto done;
943 		pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
944 		pss.ps_nargvstr = pss32.ps_nargvstr;
945 		pss.ps_envstr = PTRIN(pss32.ps_envstr);
946 		pss.ps_nenvstr = pss32.ps_nenvstr;
947 	} else {
948 #endif
949 		elm_len = sizeof(char *);
950 		envp = (char *)env_vector;
951 
952 		UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
953 		    (off_t)(p->p_sysent->sv_psstrings),
954 		    sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
955 		ret = proc_rwmem(p, &tmp_uio);
956 		if (ret != 0)
957 			goto done;
958 #ifdef COMPAT_FREEBSD32
959 	}
960 #endif
961 
962 	/* Get the array address and the number of elements */
963 	resolver(pss, &addr, &n_elements);
964 
965 	/* Consistent with lib/libkvm/kvm_proc.c */
966 	if (n_elements > MAX_ARGV_STR) {
967 		ret = E2BIG;
968 		goto done;
969 	}
970 
971 	UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
972 	    (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
973 	ret = proc_rwmem(p, &tmp_uio);
974 	if (ret != 0)
975 		goto done;
976 #ifdef COMPAT_FREEBSD32
977 	if (env_vector32 != NULL) {
978 		for (i = 0; i < n_elements; i++)
979 			env_vector[i] = PTRIN(env_vector32[i]);
980 	}
981 #endif
982 
983 	/* Now we can iterate through the list of strings */
984 	for (i = 0; i < n_elements; i++) {
985 		pbegin = (vm_offset_t)env_vector[i];
986 		for (;;) {
987 			UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
988 			    1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
989 			ret = proc_rwmem(p, &tmp_uio);
990 			if (ret != 0)
991 				goto done;
992 
993 			if (!strvalid(env_string, UIO_CHUNK_SZ)) {
994 				/*
995 				 * We didn't find the end of the string.
996 				 * Add the string to the buffer and move
997 				 * the pointer.  But do not allow strings
998 				 * of unlimited length.
999 				 */
1000 				sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1001 				if (sbuf_len(sb) >= ARG_MAX) {
1002 					ret = E2BIG;
1003 					goto done;
1004 				}
1005 				pbegin += UIO_CHUNK_SZ;
1006 			} else {
1007 				sbuf_cat(sb, env_string);
1008 				break;
1009 			}
1010 		}
1011 		sbuf_bcat(sb, "", 1);
1012 	}
1013 #undef UIO_HELPER
1014 
1015 done:
1016 	free(env_vector, M_TEMP);
1017 #ifdef COMPAT_FREEBSD32
1018 	free(env_vector32, M_TEMP);
1019 #endif
1020 	return (ret);
1021 }
1022 
1023 static void
1024 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1025 {
1026 
1027 	*addr = (u_long) ps.ps_argvstr;
1028 	*n = ps.ps_nargvstr;
1029 }
1030 
1031 static void
1032 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1033 {
1034 
1035 	*addr = (u_long) ps.ps_envstr;
1036 	*n = ps.ps_nenvstr;
1037 }
1038 
1039 /*
1040  * Filler function for proc/pid/cmdline
1041  */
1042 static int
1043 linprocfs_doproccmdline(PFS_FILL_ARGS)
1044 {
1045 	int ret;
1046 
1047 	PROC_LOCK(p);
1048 	if ((ret = p_cansee(td, p)) != 0) {
1049 		PROC_UNLOCK(p);
1050 		return (ret);
1051 	}
1052 
1053 	/*
1054 	 * Mimic linux behavior and pass only processes with usermode
1055 	 * address space as valid.  Return zero silently otherwize.
1056 	 */
1057 	if (p->p_vmspace == &vmspace0) {
1058 		PROC_UNLOCK(p);
1059 		return (0);
1060 	}
1061 	if (p->p_args != NULL) {
1062 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1063 		PROC_UNLOCK(p);
1064 		return (0);
1065 	}
1066 	PROC_UNLOCK(p);
1067 
1068 	ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1069 	return (ret);
1070 }
1071 
1072 /*
1073  * Filler function for proc/pid/environ
1074  */
1075 static int
1076 linprocfs_doprocenviron(PFS_FILL_ARGS)
1077 {
1078 	int ret;
1079 
1080 	PROC_LOCK(p);
1081 	if ((ret = p_cansee(td, p)) != 0) {
1082 		PROC_UNLOCK(p);
1083 		return (ret);
1084 	}
1085 
1086 	/*
1087 	 * Mimic linux behavior and pass only processes with usermode
1088 	 * address space as valid.  Return zero silently otherwize.
1089 	 */
1090 	if (p->p_vmspace == &vmspace0) {
1091 		PROC_UNLOCK(p);
1092 		return (0);
1093 	}
1094 	PROC_UNLOCK(p);
1095 
1096 	ret = linprocfs_doargv(td, p, sb, ps_string_env);
1097 	return (ret);
1098 }
1099 
1100 /*
1101  * Filler function for proc/pid/maps
1102  */
1103 static int
1104 linprocfs_doprocmaps(PFS_FILL_ARGS)
1105 {
1106 	struct vmspace *vm;
1107 	vm_map_t map;
1108 	vm_map_entry_t entry, tmp_entry;
1109 	vm_object_t obj, tobj, lobj;
1110 	vm_offset_t e_start, e_end;
1111 	vm_ooffset_t off = 0;
1112 	vm_prot_t e_prot;
1113 	unsigned int last_timestamp;
1114 	char *name = "", *freename = NULL;
1115 	ino_t ino;
1116 	int ref_count, shadow_count, flags;
1117 	int error;
1118 	struct vnode *vp;
1119 	struct vattr vat;
1120 	int locked;
1121 
1122 	PROC_LOCK(p);
1123 	error = p_candebug(td, p);
1124 	PROC_UNLOCK(p);
1125 	if (error)
1126 		return (error);
1127 
1128 	if (uio->uio_rw != UIO_READ)
1129 		return (EOPNOTSUPP);
1130 
1131 	error = 0;
1132 	vm = vmspace_acquire_ref(p);
1133 	if (vm == NULL)
1134 		return (ESRCH);
1135 	map = &vm->vm_map;
1136 	vm_map_lock_read(map);
1137 	for (entry = map->header.next; entry != &map->header;
1138 	    entry = entry->next) {
1139 		name = "";
1140 		freename = NULL;
1141 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1142 			continue;
1143 		e_prot = entry->protection;
1144 		e_start = entry->start;
1145 		e_end = entry->end;
1146 		obj = entry->object.vm_object;
1147 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1148 			VM_OBJECT_LOCK(tobj);
1149 			if (lobj != obj)
1150 				VM_OBJECT_UNLOCK(lobj);
1151 			lobj = tobj;
1152 		}
1153 		last_timestamp = map->timestamp;
1154 		vm_map_unlock_read(map);
1155 		ino = 0;
1156 		if (lobj) {
1157 			off = IDX_TO_OFF(lobj->size);
1158 			if (lobj->type == OBJT_VNODE) {
1159 				vp = lobj->handle;
1160 				if (vp)
1161 					vref(vp);
1162 			}
1163 			else
1164 				vp = NULL;
1165 			if (lobj != obj)
1166 				VM_OBJECT_UNLOCK(lobj);
1167 			flags = obj->flags;
1168 			ref_count = obj->ref_count;
1169 			shadow_count = obj->shadow_count;
1170 			VM_OBJECT_UNLOCK(obj);
1171 			if (vp) {
1172 				vn_fullpath(td, vp, &name, &freename);
1173 				locked = VFS_LOCK_GIANT(vp->v_mount);
1174 				vn_lock(vp, LK_SHARED | LK_RETRY);
1175 				VOP_GETATTR(vp, &vat, td->td_ucred);
1176 				ino = vat.va_fileid;
1177 				vput(vp);
1178 				VFS_UNLOCK_GIANT(locked);
1179 			}
1180 		} else {
1181 			flags = 0;
1182 			ref_count = 0;
1183 			shadow_count = 0;
1184 		}
1185 
1186 		/*
1187 		 * format:
1188 		 *  start, end, access, offset, major, minor, inode, name.
1189 		 */
1190 		error = sbuf_printf(sb,
1191 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1192 		    (u_long)e_start, (u_long)e_end,
1193 		    (e_prot & VM_PROT_READ)?"r":"-",
1194 		    (e_prot & VM_PROT_WRITE)?"w":"-",
1195 		    (e_prot & VM_PROT_EXECUTE)?"x":"-",
1196 		    "p",
1197 		    (u_long)off,
1198 		    0,
1199 		    0,
1200 		    (u_long)ino,
1201 		    *name ? "     " : "",
1202 		    name
1203 		    );
1204 		if (freename)
1205 			free(freename, M_TEMP);
1206 		vm_map_lock_read(map);
1207 		if (error == -1) {
1208 			error = 0;
1209 			break;
1210 		}
1211 		if (last_timestamp != map->timestamp) {
1212 			/*
1213 			 * Look again for the entry because the map was
1214 			 * modified while it was unlocked.  Specifically,
1215 			 * the entry may have been clipped, merged, or deleted.
1216 			 */
1217 			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1218 			entry = tmp_entry;
1219 		}
1220 	}
1221 	vm_map_unlock_read(map);
1222 	vmspace_free(vm);
1223 
1224 	return (error);
1225 }
1226 
1227 /*
1228  * Filler function for proc/net/dev
1229  */
1230 static int
1231 linprocfs_donetdev(PFS_FILL_ARGS)
1232 {
1233 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1234 	struct ifnet *ifp;
1235 
1236 	sbuf_printf(sb, "%6s|%58s|%s\n"
1237 	    "%6s|%58s|%58s\n",
1238 	    "Inter-", "   Receive", "  Transmit",
1239 	    " face",
1240 	    "bytes    packets errs drop fifo frame compressed multicast",
1241 	    "bytes    packets errs drop fifo colls carrier compressed");
1242 
1243 	CURVNET_SET(TD_TO_VNET(curthread));
1244 	IFNET_RLOCK();
1245 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1246 		linux_ifname(ifp, ifname, sizeof ifname);
1247 		sbuf_printf(sb, "%6.6s: ", ifname);
1248 		sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1249 		    ifp->if_ibytes,	/* rx_bytes */
1250 		    ifp->if_ipackets,	/* rx_packets */
1251 		    ifp->if_ierrors,	/* rx_errors */
1252 		    ifp->if_iqdrops,	/* rx_dropped +
1253 					 * rx_missed_errors */
1254 		    0UL,		/* rx_fifo_errors */
1255 		    0UL,		/* rx_length_errors +
1256 					 * rx_over_errors +
1257 		    			 * rx_crc_errors +
1258 					 * rx_frame_errors */
1259 		    0UL,		/* rx_compressed */
1260 		    ifp->if_imcasts);	/* multicast, XXX-BZ rx only? */
1261 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1262 		    ifp->if_obytes,	/* tx_bytes */
1263 		    ifp->if_opackets,	/* tx_packets */
1264 		    ifp->if_oerrors,	/* tx_errors */
1265 		    0UL,		/* tx_dropped */
1266 		    0UL,		/* tx_fifo_errors */
1267 		    ifp->if_collisions,	/* collisions */
1268 		    0UL,		/* tx_carrier_errors +
1269 					 * tx_aborted_errors +
1270 					 * tx_window_errors +
1271 					 * tx_heartbeat_errors */
1272 		    0UL);		/* tx_compressed */
1273 	}
1274 	IFNET_RUNLOCK();
1275 	CURVNET_RESTORE();
1276 
1277 	return (0);
1278 }
1279 
1280 /*
1281  * Filler function for proc/sys/kernel/osrelease
1282  */
1283 static int
1284 linprocfs_doosrelease(PFS_FILL_ARGS)
1285 {
1286 	char osrelease[LINUX_MAX_UTSNAME];
1287 
1288 	linux_get_osrelease(td, osrelease);
1289 	sbuf_printf(sb, "%s\n", osrelease);
1290 
1291 	return (0);
1292 }
1293 
1294 /*
1295  * Filler function for proc/sys/kernel/ostype
1296  */
1297 static int
1298 linprocfs_doostype(PFS_FILL_ARGS)
1299 {
1300 	char osname[LINUX_MAX_UTSNAME];
1301 
1302 	linux_get_osname(td, osname);
1303 	sbuf_printf(sb, "%s\n", osname);
1304 
1305 	return (0);
1306 }
1307 
1308 /*
1309  * Filler function for proc/sys/kernel/version
1310  */
1311 static int
1312 linprocfs_doosbuild(PFS_FILL_ARGS)
1313 {
1314 
1315 	linprocfs_osbuild(td, sb);
1316 	sbuf_cat(sb, "\n");
1317 	return (0);
1318 }
1319 
1320 /*
1321  * Filler function for proc/sys/kernel/msgmni
1322  */
1323 static int
1324 linprocfs_domsgmni(PFS_FILL_ARGS)
1325 {
1326 
1327 	sbuf_printf(sb, "%d\n", msginfo.msgmni);
1328 	return (0);
1329 }
1330 
1331 /*
1332  * Filler function for proc/sys/kernel/pid_max
1333  */
1334 static int
1335 linprocfs_dopid_max(PFS_FILL_ARGS)
1336 {
1337 
1338 	sbuf_printf(sb, "%i\n", PID_MAX);
1339 	return (0);
1340 }
1341 
1342 /*
1343  * Filler function for proc/sys/kernel/sem
1344  */
1345 static int
1346 linprocfs_dosem(PFS_FILL_ARGS)
1347 {
1348 
1349 	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1350 	    seminfo.semopm, seminfo.semmni);
1351 	return (0);
1352 }
1353 
1354 /*
1355  * Filler function for proc/scsi/device_info
1356  */
1357 static int
1358 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1359 {
1360 
1361 	return (0);
1362 }
1363 
1364 /*
1365  * Filler function for proc/scsi/scsi
1366  */
1367 static int
1368 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1369 {
1370 
1371 	return (0);
1372 }
1373 
1374 extern struct cdevsw *cdevsw[];
1375 
1376 /*
1377  * Filler function for proc/devices
1378  */
1379 static int
1380 linprocfs_dodevices(PFS_FILL_ARGS)
1381 {
1382 	char *char_devices;
1383 	sbuf_printf(sb, "Character devices:\n");
1384 
1385 	char_devices = linux_get_char_devices();
1386 	sbuf_printf(sb, "%s", char_devices);
1387 	linux_free_get_char_devices(char_devices);
1388 
1389 	sbuf_printf(sb, "\nBlock devices:\n");
1390 
1391 	return (0);
1392 }
1393 
1394 /*
1395  * Filler function for proc/cmdline
1396  */
1397 static int
1398 linprocfs_docmdline(PFS_FILL_ARGS)
1399 {
1400 
1401 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1402 	sbuf_printf(sb, " ro root=302\n");
1403 	return (0);
1404 }
1405 
1406 /*
1407  * Filler function for proc/filesystems
1408  */
1409 static int
1410 linprocfs_dofilesystems(PFS_FILL_ARGS)
1411 {
1412 	struct vfsconf *vfsp;
1413 
1414 	mtx_lock(&Giant);
1415 	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1416 		if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1417 			sbuf_printf(sb, "nodev");
1418 		sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1419 	}
1420 	mtx_unlock(&Giant);
1421 	return(0);
1422 }
1423 
1424 #if 0
1425 /*
1426  * Filler function for proc/modules
1427  */
1428 static int
1429 linprocfs_domodules(PFS_FILL_ARGS)
1430 {
1431 	struct linker_file *lf;
1432 
1433 	TAILQ_FOREACH(lf, &linker_files, link) {
1434 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1435 		    (unsigned long)lf->size, lf->refs);
1436 	}
1437 	return (0);
1438 }
1439 #endif
1440 
1441 /*
1442  * Filler function for proc/pid/fd
1443  */
1444 static int
1445 linprocfs_dofdescfs(PFS_FILL_ARGS)
1446 {
1447 
1448 	if (p == curproc)
1449 		sbuf_printf(sb, "/dev/fd");
1450 	else
1451 		sbuf_printf(sb, "unknown");
1452 	return (0);
1453 }
1454 
1455 /*
1456  * Constructor
1457  */
1458 static int
1459 linprocfs_init(PFS_INIT_ARGS)
1460 {
1461 	struct pfs_node *root;
1462 	struct pfs_node *dir;
1463 
1464 	root = pi->pi_root;
1465 
1466 	/* /proc/... */
1467 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1468 	    NULL, NULL, NULL, PFS_RD);
1469 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1470 	    NULL, NULL, NULL, PFS_RD);
1471 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1472 	    NULL, NULL, NULL, PFS_RD);
1473 	pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1474 	    NULL, NULL, NULL, PFS_RD);
1475 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1476 	    NULL, NULL, NULL, PFS_RD);
1477 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1478 	    NULL, NULL, NULL, PFS_RD);
1479 #if 0
1480 	pfs_create_file(root, "modules", &linprocfs_domodules,
1481 	    NULL, NULL, NULL, PFS_RD);
1482 #endif
1483 	pfs_create_file(root, "mounts", &linprocfs_domtab,
1484 	    NULL, NULL, NULL, PFS_RD);
1485 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1486 	    NULL, NULL, NULL, PFS_RD);
1487 	pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1488 	    NULL, NULL, NULL, PFS_RD);
1489 	pfs_create_link(root, "self", &procfs_docurproc,
1490 	    NULL, NULL, NULL, 0);
1491 	pfs_create_file(root, "stat", &linprocfs_dostat,
1492 	    NULL, NULL, NULL, PFS_RD);
1493 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1494 	    NULL, NULL, NULL, PFS_RD);
1495 	pfs_create_file(root, "version", &linprocfs_doversion,
1496 	    NULL, NULL, NULL, PFS_RD);
1497 
1498 	/* /proc/net/... */
1499 	dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1500 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1501 	    NULL, NULL, NULL, PFS_RD);
1502 
1503 	/* /proc/<pid>/... */
1504 	dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1505 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1506 	    NULL, NULL, NULL, PFS_RD);
1507 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1508 	    NULL, NULL, NULL, 0);
1509 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1510 	    NULL, NULL, NULL, PFS_RD);
1511 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1512 	    NULL, &procfs_notsystem, NULL, 0);
1513 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1514 	    NULL, NULL, NULL, PFS_RD);
1515 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1516 	    &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1517 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1518 	    NULL, NULL, NULL, 0);
1519 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1520 	    NULL, NULL, NULL, PFS_RD);
1521 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1522 	    NULL, NULL, NULL, PFS_RD);
1523 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1524 	    NULL, NULL, NULL, PFS_RD);
1525 	pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1526 	    NULL, NULL, NULL, 0);
1527 
1528 	/* /proc/scsi/... */
1529 	dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1530 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1531 	    NULL, NULL, NULL, PFS_RD);
1532 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1533 	    NULL, NULL, NULL, PFS_RD);
1534 
1535 	/* /proc/sys/... */
1536 	dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1537 	/* /proc/sys/kernel/... */
1538 	dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1539 	pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1540 	    NULL, NULL, NULL, PFS_RD);
1541 	pfs_create_file(dir, "ostype", &linprocfs_doostype,
1542 	    NULL, NULL, NULL, PFS_RD);
1543 	pfs_create_file(dir, "version", &linprocfs_doosbuild,
1544 	    NULL, NULL, NULL, PFS_RD);
1545 	pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1546 	    NULL, NULL, NULL, PFS_RD);
1547 	pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1548 	    NULL, NULL, NULL, PFS_RD);
1549 	pfs_create_file(dir, "sem", &linprocfs_dosem,
1550 	    NULL, NULL, NULL, PFS_RD);
1551 
1552 	return (0);
1553 }
1554 
1555 /*
1556  * Destructor
1557  */
1558 static int
1559 linprocfs_uninit(PFS_INIT_ARGS)
1560 {
1561 
1562 	/* nothing to do, pseudofs will GC */
1563 	return (0);
1564 }
1565 
1566 PSEUDOFS(linprocfs, 1);
1567 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1568 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1569 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1570 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
1571