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