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