xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision b19bfd3db5bfc58eea0b07f19d1e93a9904ccd3a)
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 <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/blist.h>
48 #include <sys/conf.h>
49 #include <sys/exec.h>
50 #include <sys/filedesc.h>
51 #include <sys/jail.h>
52 #include <sys/kernel.h>
53 #include <sys/linker.h>
54 #include <sys/lock.h>
55 #include <sys/malloc.h>
56 #include <sys/mount.h>
57 #include <sys/mutex.h>
58 #include <sys/namei.h>
59 #include <sys/proc.h>
60 #include <sys/resourcevar.h>
61 #include <sys/sbuf.h>
62 #include <sys/smp.h>
63 #include <sys/socket.h>
64 #include <sys/sysctl.h>
65 #include <sys/systm.h>
66 #include <sys/tty.h>
67 #include <sys/user.h>
68 #include <sys/vmmeter.h>
69 #include <sys/vnode.h>
70 
71 #include <net/if.h>
72 
73 #include <vm/vm.h>
74 #include <vm/pmap.h>
75 #include <vm/vm_map.h>
76 #include <vm/vm_param.h>
77 #include <vm/vm_object.h>
78 #include <vm/swap_pager.h>
79 
80 #include <machine/clock.h>
81 
82 #if defined(__i386__) || defined(__amd64__)
83 #include <machine/cputypes.h>
84 #include <machine/md_var.h>
85 #endif /* __i386__ || __amd64__ */
86 
87 #include "opt_compat.h"
88 #ifdef COMPAT_LINUX32				/* XXX */
89 #include <machine/../linux32/linux.h>
90 #else
91 #include <machine/../linux/linux.h>
92 #endif
93 #include <compat/linux/linux_ioctl.h>
94 #include <compat/linux/linux_mib.h>
95 #include <compat/linux/linux_util.h>
96 #include <fs/pseudofs/pseudofs.h>
97 #include <fs/procfs/procfs.h>
98 
99 /*
100  * Various conversion macros
101  */
102 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz))	/* ticks to jiffies */
103 #define T2S(x) ((x) / (stathz ? stathz : hz))		/* ticks to seconds */
104 #define B2K(x) ((x) >> 10)				/* bytes to kbytes */
105 #define B2P(x) ((x) >> PAGE_SHIFT)			/* bytes to pages */
106 #define P2B(x) ((x) << PAGE_SHIFT)			/* pages to bytes */
107 #define P2K(x) ((x) << (PAGE_SHIFT - 10))		/* pages to kbytes */
108 
109 /*
110  * Filler function for proc/meminfo
111  */
112 static int
113 linprocfs_domeminfo(PFS_FILL_ARGS)
114 {
115 	unsigned long memtotal;		/* total memory in bytes */
116 	unsigned long memused;		/* used memory in bytes */
117 	unsigned long memfree;		/* free memory in bytes */
118 	unsigned long memshared;	/* shared memory ??? */
119 	unsigned long buffers, cached;	/* buffer / cache memory ??? */
120 	unsigned long long swaptotal;	/* total swap space in bytes */
121 	unsigned long long swapused;	/* used swap space in bytes */
122 	unsigned long long swapfree;	/* free swap space in bytes */
123 	vm_object_t object;
124 	int i, j;
125 
126 	memtotal = physmem * PAGE_SIZE;
127 	/*
128 	 * The correct thing here would be:
129 	 *
130 	memfree = cnt.v_free_count * PAGE_SIZE;
131 	memused = memtotal - memfree;
132 	 *
133 	 * but it might mislead linux binaries into thinking there
134 	 * is very little memory left, so we cheat and tell them that
135 	 * all memory that isn't wired down is free.
136 	 */
137 	memused = cnt.v_wire_count * PAGE_SIZE;
138 	memfree = memtotal - memused;
139 	swap_pager_status(&i, &j);
140 	swaptotal = (unsigned long long)i * PAGE_SIZE;
141 	swapused = (unsigned long long)j * PAGE_SIZE;
142 	swapfree = swaptotal - swapused;
143 	memshared = 0;
144 	mtx_lock(&vm_object_list_mtx);
145 	TAILQ_FOREACH(object, &vm_object_list, object_list)
146 		if (object->shadow_count > 1)
147 			memshared += object->resident_page_count;
148 	mtx_unlock(&vm_object_list_mtx);
149 	memshared *= PAGE_SIZE;
150 	/*
151 	 * We'd love to be able to write:
152 	 *
153 	buffers = bufspace;
154 	 *
155 	 * but bufspace is internal to vfs_bio.c and we don't feel
156 	 * like unstaticizing it just for linprocfs's sake.
157 	 */
158 	buffers = 0;
159 	cached = cnt.v_cache_count * PAGE_SIZE;
160 
161 	sbuf_printf(sb,
162 	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
163 	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
164 	    "Swap: %llu %llu %llu\n"
165 	    "MemTotal: %9lu kB\n"
166 	    "MemFree:  %9lu kB\n"
167 	    "MemShared:%9lu kB\n"
168 	    "Buffers:  %9lu kB\n"
169 	    "Cached:   %9lu kB\n"
170 	    "SwapTotal:%9llu kB\n"
171 	    "SwapFree: %9llu kB\n",
172 	    memtotal, memused, memfree, memshared, buffers, cached,
173 	    swaptotal, swapused, swapfree,
174 	    B2K(memtotal), B2K(memfree),
175 	    B2K(memshared), B2K(buffers), B2K(cached),
176 	    B2K(swaptotal), B2K(swapfree));
177 
178 	return (0);
179 }
180 
181 #if defined(__i386__) || defined(__amd64__)
182 /*
183  * Filler function for proc/cpuinfo (i386 & amd64 version)
184  */
185 static int
186 linprocfs_docpuinfo(PFS_FILL_ARGS)
187 {
188 	int class, fqmhz, fqkhz;
189 	int i;
190 
191 	/*
192 	 * We default the flags to include all non-conflicting flags,
193 	 * and the Intel versions of conflicting flags.
194 	 */
195 	static char *flags[] = {
196 		"fpu",	    "vme",     "de",	   "pse",      "tsc",
197 		"msr",	    "pae",     "mce",	   "cx8",      "apic",
198 		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
199 		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
200 		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
201 		"xmm",	    "b26",     "b27",	   "b28",      "b29",
202 		"3dnowext", "3dnow"
203 	};
204 
205 	switch (cpu_class) {
206 #ifdef __i386__
207 	case CPUCLASS_286:
208 		class = 2;
209 		break;
210 	case CPUCLASS_386:
211 		class = 3;
212 		break;
213 	case CPUCLASS_486:
214 		class = 4;
215 		break;
216 	case CPUCLASS_586:
217 		class = 5;
218 		break;
219 	case CPUCLASS_686:
220 		class = 6;
221 		break;
222 	default:
223 		class = 0;
224 		break;
225 #else /* __amd64__ */
226 	default:
227 		class = 15;
228 		break;
229 #endif
230 	}
231 
232 	for (i = 0; i < mp_ncpus; ++i) {
233 		sbuf_printf(sb,
234 		    "processor\t: %d\n"
235 		    "vendor_id\t: %.20s\n"
236 		    "cpu family\t: %d\n"
237 		    "model\t\t: %d\n"
238 		    "stepping\t: %d\n",
239 		    i, cpu_vendor, class, cpu, cpu_id & 0xf);
240 		/* XXX per-cpu vendor / class / id? */
241 	}
242 
243 	sbuf_cat(sb,
244 	    "flags\t\t:");
245 
246 	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
247 		flags[16] = "fcmov";
248 	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
249 		flags[24] = "cxmmx";
250 	}
251 
252 	for (i = 0; i < 32; i++)
253 		if (cpu_feature & (1 << i))
254 			sbuf_printf(sb, " %s", flags[i]);
255 	sbuf_cat(sb, "\n");
256 	if (class >= 5) {
257 		fqmhz = (tsc_freq + 4999) / 1000000;
258 		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
259 		sbuf_printf(sb,
260 		    "cpu MHz\t\t: %d.%02d\n"
261 		    "bogomips\t: %d.%02d\n",
262 		    fqmhz, fqkhz, fqmhz, fqkhz);
263 	}
264 
265 	return (0);
266 }
267 #endif /* __i386__ || __amd64__ */
268 
269 /*
270  * Filler function for proc/mtab
271  *
272  * This file doesn't exist in Linux' procfs, but is included here so
273  * users can symlink /compat/linux/etc/mtab to /proc/mtab
274  */
275 static int
276 linprocfs_domtab(PFS_FILL_ARGS)
277 {
278 	struct nameidata nd;
279 	struct mount *mp;
280 	const char *lep;
281 	char *dlep, *flep, *mntto, *mntfrom, *fstype;
282 	size_t lep_len;
283 	int error;
284 
285 	/* resolve symlinks etc. in the emulation tree prefix */
286 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
287 	flep = NULL;
288 	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
289 		lep = linux_emul_path;
290 	else
291 		lep = dlep;
292 	lep_len = strlen(lep);
293 
294 	mtx_lock(&mountlist_mtx);
295 	error = 0;
296 	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
297 		/* determine device name */
298 		mntfrom = mp->mnt_stat.f_mntfromname;
299 
300 		/* determine mount point */
301 		mntto = mp->mnt_stat.f_mntonname;
302 		if (strncmp(mntto, lep, lep_len) == 0 &&
303 		    mntto[lep_len] == '/')
304 			mntto += lep_len;
305 
306 		/* determine fs type */
307 		fstype = mp->mnt_stat.f_fstypename;
308 		if (strcmp(fstype, pn->pn_info->pi_name) == 0)
309 			mntfrom = fstype = "proc";
310 		else if (strcmp(fstype, "procfs") == 0)
311 			continue;
312 
313 		if (strcmp(fstype, "linsysfs") == 0) {
314 			sbuf_printf(sb, "/sys %s sysfs %s", mntto,
315 			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
316 		} else {
317 			sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
318 			    mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
319 		}
320 #define ADD_OPTION(opt, name) \
321 	if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
322 		ADD_OPTION(MNT_SYNCHRONOUS,	"sync");
323 		ADD_OPTION(MNT_NOEXEC,		"noexec");
324 		ADD_OPTION(MNT_NOSUID,		"nosuid");
325 		ADD_OPTION(MNT_UNION,		"union");
326 		ADD_OPTION(MNT_ASYNC,		"async");
327 		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
328 		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
329 		ADD_OPTION(MNT_NOATIME,		"noatime");
330 #undef ADD_OPTION
331 		/* a real Linux mtab will also show NFS options */
332 		sbuf_printf(sb, " 0 0\n");
333 	}
334 	mtx_unlock(&mountlist_mtx);
335 	if (flep != NULL)
336 		free(flep, M_TEMP);
337 	return (error);
338 }
339 
340 /*
341  * Filler function for proc/stat
342  */
343 static int
344 linprocfs_dostat(PFS_FILL_ARGS)
345 {
346 	int i;
347 
348 	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
349 	    T2J(cp_time[CP_USER]),
350 	    T2J(cp_time[CP_NICE]),
351 	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
352 	    T2J(cp_time[CP_IDLE]));
353 	for (i = 0; i < mp_ncpus; ++i)
354 		sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
355 		    T2J(cp_time[CP_USER]) / mp_ncpus,
356 		    T2J(cp_time[CP_NICE]) / mp_ncpus,
357 		    T2J(cp_time[CP_SYS]) / mp_ncpus,
358 		    T2J(cp_time[CP_IDLE]) / mp_ncpus);
359 	sbuf_printf(sb,
360 	    "disk 0 0 0 0\n"
361 	    "page %u %u\n"
362 	    "swap %u %u\n"
363 	    "intr %u\n"
364 	    "ctxt %u\n"
365 	    "btime %lld\n",
366 	    cnt.v_vnodepgsin,
367 	    cnt.v_vnodepgsout,
368 	    cnt.v_swappgsin,
369 	    cnt.v_swappgsout,
370 	    cnt.v_intr,
371 	    cnt.v_swtch,
372 	    (long long)boottime.tv_sec);
373 	return (0);
374 }
375 
376 /*
377  * Filler function for proc/uptime
378  */
379 static int
380 linprocfs_douptime(PFS_FILL_ARGS)
381 {
382 	struct timeval tv;
383 
384 	getmicrouptime(&tv);
385 	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
386 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
387 	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
388 	return (0);
389 }
390 
391 /*
392  * Filler function for proc/version
393  */
394 static int
395 linprocfs_doversion(PFS_FILL_ARGS)
396 {
397 	char osname[LINUX_MAX_UTSNAME];
398 	char osrelease[LINUX_MAX_UTSNAME];
399 
400 	linux_get_osname(td, osname);
401 	linux_get_osrelease(td, osrelease);
402 
403 	sbuf_printf(sb,
404 	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
405 	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
406 	return (0);
407 }
408 
409 /*
410  * Filler function for proc/loadavg
411  */
412 static int
413 linprocfs_doloadavg(PFS_FILL_ARGS)
414 {
415 	sbuf_printf(sb,
416 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
417 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
418 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
419 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
420 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
421 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
422 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
423 	    1,				/* number of running tasks */
424 	    nprocs,			/* number of tasks */
425 	    lastpid			/* the last pid */
426 	);
427 
428 	return (0);
429 }
430 
431 /*
432  * Filler function for proc/pid/stat
433  */
434 static int
435 linprocfs_doprocstat(PFS_FILL_ARGS)
436 {
437 	struct kinfo_proc kp;
438 
439 	PROC_LOCK(p);
440 	fill_kinfo_proc(p, &kp);
441 	sbuf_printf(sb, "%d", p->p_pid);
442 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
443 	PS_ADD("comm",		"(%s)",	p->p_comm);
444 	PS_ADD("statr",		"%c",	'0'); /* XXX */
445 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
446 	PS_ADD("pgrp",		"%d",	p->p_pgid);
447 	PS_ADD("session",	"%d",	p->p_session->s_sid);
448 	PROC_UNLOCK(p);
449 	PS_ADD("tty",		"%d",	0); /* XXX */
450 	PS_ADD("tpgid",		"%d",	0); /* XXX */
451 	PS_ADD("flags",		"%u",	0); /* XXX */
452 	PS_ADD("minflt",	"%u",	0); /* XXX */
453 	PS_ADD("cminflt",	"%u",	0); /* XXX */
454 	PS_ADD("majflt",	"%u",	0); /* XXX */
455 	PS_ADD("cminflt",	"%u",	0); /* XXX */
456 	PS_ADD("utime",		"%d",	0); /* XXX */
457 	PS_ADD("stime",		"%d",	0); /* XXX */
458 	PS_ADD("cutime",	"%d",	0); /* XXX */
459 	PS_ADD("cstime",	"%d",	0); /* XXX */
460 	PS_ADD("counter",	"%d",	0); /* XXX */
461 	PS_ADD("priority",	"%d",	0); /* XXX */
462 	PS_ADD("timeout",	"%u",	0); /* XXX */
463 	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
464 	PS_ADD("starttime",	"%d",	0); /* XXX */
465 	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
466 	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
467 	PS_ADD("rlim",		"%u",	0); /* XXX */
468 	PS_ADD("startcode",	"%u",	(unsigned)0);
469 	PS_ADD("endcode",	"%u",	0); /* XXX */
470 	PS_ADD("startstack",	"%u",	0); /* XXX */
471 	PS_ADD("esp",		"%u",	0); /* XXX */
472 	PS_ADD("eip",		"%u",	0); /* XXX */
473 	PS_ADD("signal",	"%d",	0); /* XXX */
474 	PS_ADD("blocked",	"%d",	0); /* XXX */
475 	PS_ADD("sigignore",	"%d",	0); /* XXX */
476 	PS_ADD("sigcatch",	"%d",	0); /* XXX */
477 	PS_ADD("wchan",		"%u",	0); /* XXX */
478 	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
479 	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
480 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
481 	PS_ADD("processor",	"%d",	0); /* XXX */
482 #undef PS_ADD
483 	sbuf_putc(sb, '\n');
484 
485 	return (0);
486 }
487 
488 /*
489  * Filler function for proc/pid/statm
490  */
491 static int
492 linprocfs_doprocstatm(PFS_FILL_ARGS)
493 {
494 	struct kinfo_proc kp;
495 	segsz_t lsize;
496 
497 	PROC_LOCK(p);
498 	fill_kinfo_proc(p, &kp);
499 	PROC_UNLOCK(p);
500 
501 	/*
502 	 * See comments in linprocfs_doprocstatus() regarding the
503 	 * computation of lsize.
504 	 */
505 	/* size resident share trs drs lrs dt */
506 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
507 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
508 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
509 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
510 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
511 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
512 	    kp.ki_ssize - kp.ki_tsize - 1;
513 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
514 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
515 
516 	return (0);
517 }
518 
519 /*
520  * Filler function for proc/pid/status
521  */
522 static int
523 linprocfs_doprocstatus(PFS_FILL_ARGS)
524 {
525 	struct kinfo_proc kp;
526 	char *state;
527 	segsz_t lsize;
528 	struct thread *td2;
529 	struct sigacts *ps;
530 	int i;
531 
532 	PROC_LOCK(p);
533 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
534 
535 	if (P_SHOULDSTOP(p)) {
536 		state = "T (stopped)";
537 	} else {
538 		mtx_lock_spin(&sched_lock);
539 		switch(p->p_state) {
540 		case PRS_NEW:
541 			state = "I (idle)";
542 			break;
543 		case PRS_NORMAL:
544 			if (p->p_flag & P_WEXIT) {
545 				state = "X (exiting)";
546 				break;
547 			}
548 			switch(td2->td_state) {
549 			case TDS_INHIBITED:
550 				state = "S (sleeping)";
551 				break;
552 			case TDS_RUNQ:
553 			case TDS_RUNNING:
554 				state = "R (running)";
555 				break;
556 			default:
557 				state = "? (unknown)";
558 				break;
559 			}
560 			break;
561 		case PRS_ZOMBIE:
562 			state = "Z (zombie)";
563 			break;
564 		default:
565 			state = "? (unknown)";
566 			break;
567 		}
568 		mtx_unlock_spin(&sched_lock);
569 	}
570 
571 	fill_kinfo_proc(p, &kp);
572 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
573 	sbuf_printf(sb, "State:\t%s\n",		state);
574 
575 	/*
576 	 * Credentials
577 	 */
578 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
579 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
580 						p->p_pptr->p_pid : 0);
581 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
582 						p->p_ucred->cr_uid,
583 						p->p_ucred->cr_svuid,
584 						/* FreeBSD doesn't have fsuid */
585 						p->p_ucred->cr_uid);
586 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
587 						p->p_ucred->cr_gid,
588 						p->p_ucred->cr_svgid,
589 						/* FreeBSD doesn't have fsgid */
590 						p->p_ucred->cr_gid);
591 	sbuf_cat(sb, "Groups:\t");
592 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
593 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
594 	PROC_UNLOCK(p);
595 	sbuf_putc(sb, '\n');
596 
597 	/*
598 	 * Memory
599 	 *
600 	 * While our approximation of VmLib may not be accurate (I
601 	 * don't know of a simple way to verify it, and I'm not sure
602 	 * it has much meaning anyway), I believe it's good enough.
603 	 *
604 	 * The same code that could (I think) accurately compute VmLib
605 	 * could also compute VmLck, but I don't really care enough to
606 	 * implement it. Submissions are welcome.
607 	 */
608 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
609 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
610 	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
611 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
612 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
613 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
614 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
615 	    kp.ki_ssize - kp.ki_tsize - 1;
616 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
617 
618 	/*
619 	 * Signal masks
620 	 *
621 	 * We support up to 128 signals, while Linux supports 32,
622 	 * but we only define 32 (the same 32 as Linux, to boot), so
623 	 * just show the lower 32 bits of each mask. XXX hack.
624 	 *
625 	 * NB: on certain platforms (Sparc at least) Linux actually
626 	 * supports 64 signals, but this code is a long way from
627 	 * running on anything but i386, so ignore that for now.
628 	 */
629 	PROC_LOCK(p);
630 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
631 	/*
632 	 * I can't seem to find out where the signal mask is in
633 	 * relation to struct proc, so SigBlk is left unimplemented.
634 	 */
635 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
636 	ps = p->p_sigacts;
637 	mtx_lock(&ps->ps_mtx);
638 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
639 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
640 	mtx_unlock(&ps->ps_mtx);
641 	PROC_UNLOCK(p);
642 
643 	/*
644 	 * Linux also prints the capability masks, but we don't have
645 	 * capabilities yet, and when we do get them they're likely to
646 	 * be meaningless to Linux programs, so we lie. XXX
647 	 */
648 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
649 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
650 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
651 
652 	return (0);
653 }
654 
655 
656 /*
657  * Filler function for proc/pid/cwd
658  */
659 static int
660 linprocfs_doproccwd(PFS_FILL_ARGS)
661 {
662 	char *fullpath = "unknown";
663 	char *freepath = NULL;
664 
665 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
666 	sbuf_printf(sb, "%s", fullpath);
667 	if (freepath)
668 		free(freepath, M_TEMP);
669 	return (0);
670 }
671 
672 /*
673  * Filler function for proc/pid/root
674  */
675 static int
676 linprocfs_doprocroot(PFS_FILL_ARGS)
677 {
678 	struct vnode *rvp;
679 	char *fullpath = "unknown";
680 	char *freepath = NULL;
681 
682 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
683 	vn_fullpath(td, rvp, &fullpath, &freepath);
684 	sbuf_printf(sb, "%s", fullpath);
685 	if (freepath)
686 		free(freepath, M_TEMP);
687 	return (0);
688 }
689 
690 /*
691  * Filler function for proc/pid/cmdline
692  */
693 static int
694 linprocfs_doproccmdline(PFS_FILL_ARGS)
695 {
696 	struct ps_strings pstr;
697 	char **ps_argvstr;
698 	int error, i;
699 
700 	/*
701 	 * If we are using the ps/cmdline caching, use that.  Otherwise
702 	 * revert back to the old way which only implements full cmdline
703 	 * for the currept process and just p->p_comm for all other
704 	 * processes.
705 	 * Note that if the argv is no longer available, we deliberately
706 	 * don't fall back on p->p_comm or return an error: the authentic
707 	 * Linux behaviour is to return zero-length in this case.
708 	 */
709 
710 	PROC_LOCK(p);
711 	if (p->p_args && p_cansee(td, p) == 0) {
712 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
713 		PROC_UNLOCK(p);
714 	} else if (p != td->td_proc) {
715 		PROC_UNLOCK(p);
716 		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
717 	} else {
718 		PROC_UNLOCK(p);
719 		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
720 		    sizeof(pstr));
721 		if (error)
722 			return (error);
723 		if (pstr.ps_nargvstr > ARG_MAX)
724 			return (E2BIG);
725 		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
726 		    M_TEMP, M_WAITOK);
727 		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
728 		    pstr.ps_nargvstr * sizeof(char *));
729 		if (error) {
730 			free(ps_argvstr, M_TEMP);
731 			return (error);
732 		}
733 		for (i = 0; i < pstr.ps_nargvstr; i++) {
734 			sbuf_copyin(sb, ps_argvstr[i], 0);
735 			sbuf_printf(sb, "%c", '\0');
736 		}
737 		free(ps_argvstr, M_TEMP);
738 	}
739 
740 	return (0);
741 }
742 
743 /*
744  * Filler function for proc/pid/environ
745  */
746 static int
747 linprocfs_doprocenviron(PFS_FILL_ARGS)
748 {
749 	sbuf_printf(sb, "doprocenviron\n%c", '\0');
750 
751 	return (0);
752 }
753 
754 /*
755  * Filler function for proc/pid/maps
756  */
757 static int
758 linprocfs_doprocmaps(PFS_FILL_ARGS)
759 {
760 	char mebuffer[512];
761 	vm_map_t map = &p->p_vmspace->vm_map;
762 	vm_map_entry_t entry;
763 	vm_object_t obj, tobj, lobj;
764 	vm_ooffset_t off = 0;
765 	char *name = "", *freename = NULL;
766 	size_t len;
767 	ino_t ino;
768 	int ref_count, shadow_count, flags;
769 	int error;
770 	struct vnode *vp;
771 	struct vattr vat;
772 
773 	PROC_LOCK(p);
774 	error = p_candebug(td, p);
775 	PROC_UNLOCK(p);
776 	if (error)
777 		return (error);
778 
779 	if (uio->uio_rw != UIO_READ)
780 		return (EOPNOTSUPP);
781 
782 	if (uio->uio_offset != 0)
783 		return (0);
784 
785 	error = 0;
786 	if (map != &curthread->td_proc->p_vmspace->vm_map)
787 		vm_map_lock_read(map);
788         for (entry = map->header.next;
789 	    ((uio->uio_resid > 0) && (entry != &map->header));
790 	    entry = entry->next) {
791 		name = "";
792 		freename = NULL;
793 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
794 			continue;
795 		obj = entry->object.vm_object;
796 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
797 			lobj = tobj;
798 		ino = 0;
799 		if (lobj) {
800 			vp = lobj->handle;
801 			VM_OBJECT_LOCK(lobj);
802 			off = IDX_TO_OFF(lobj->size);
803 			if (lobj->type == OBJT_VNODE && lobj->handle) {
804 				vn_fullpath(td, vp, &name, &freename);
805 				VOP_GETATTR(vp, &vat, td->td_ucred, td);
806 				ino = vat.va_fileid;
807 			}
808 			flags = obj->flags;
809 			ref_count = obj->ref_count;
810 			shadow_count = obj->shadow_count;
811 			VM_OBJECT_UNLOCK(lobj);
812 		} else {
813 			flags = 0;
814 			ref_count = 0;
815 			shadow_count = 0;
816 		}
817 
818 		/*
819 	     	 * format:
820 		 *  start, end, access, offset, major, minor, inode, name.
821 		 */
822 		snprintf(mebuffer, sizeof mebuffer,
823 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
824 		    (u_long)entry->start, (u_long)entry->end,
825 		    (entry->protection & VM_PROT_READ)?"r":"-",
826 		    (entry->protection & VM_PROT_WRITE)?"w":"-",
827 		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
828 		    "p",
829 		    (u_long)off,
830 		    0,
831 		    0,
832 		    (u_long)ino,
833 		    *name ? "     " : "",
834 		    name
835 		    );
836 		if (freename)
837 			free(freename, M_TEMP);
838 		len = strlen(mebuffer);
839 		if (len > uio->uio_resid)
840 			len = uio->uio_resid; /*
841 					       * XXX We should probably return
842 					       * EFBIG here, as in procfs.
843 					       */
844 		error = uiomove(mebuffer, len, uio);
845 		if (error)
846 			break;
847 	}
848 	if (map != &curthread->td_proc->p_vmspace->vm_map)
849 		vm_map_unlock_read(map);
850 
851 	return (error);
852 }
853 
854 /*
855  * Filler function for proc/net/dev
856  */
857 static int
858 linprocfs_donetdev(PFS_FILL_ARGS)
859 {
860 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
861 	struct ifnet *ifp;
862 
863 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
864 	    "Inter-", "   Receive", "  Transmit", " face",
865 	    "bytes    packets errs drop fifo frame compressed",
866 	    "bytes    packets errs drop fifo frame compressed");
867 
868 	IFNET_RLOCK();
869 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
870 		linux_ifname(ifp, ifname, sizeof ifname);
871 			sbuf_printf(sb, "%6.6s:", ifname);
872 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
873 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
874 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
875 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
876 	}
877 	IFNET_RUNLOCK();
878 
879 	return (0);
880 }
881 
882 /*
883  * Filler function for proc/scsi/device_info
884  */
885 static int
886 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
887 {
888 	return (0);
889 }
890 
891 /*
892  * Filler function for proc/scsi/scsi
893  */
894 static int
895 linprocfs_doscsiscsi(PFS_FILL_ARGS)
896 {
897 	return (0);
898 }
899 
900 extern struct cdevsw *cdevsw[];
901 
902 /*
903  * Filler function for proc/devices
904  */
905 static int
906 linprocfs_dodevices(PFS_FILL_ARGS)
907 {
908 	char *char_devices;
909 	sbuf_printf(sb, "Character devices:\n");
910 
911 	char_devices = linux_get_char_devices();
912 	sbuf_printf(sb, "%s", char_devices);
913 	linux_free_get_char_devices(char_devices);
914 
915 	sbuf_printf(sb, "\nBlock devices:\n");
916 
917 	return (0);
918 }
919 
920 /*
921  * Filler function for proc/cmdline
922  */
923 static int
924 linprocfs_docmdline(PFS_FILL_ARGS)
925 {
926 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
927 	sbuf_printf(sb, " ro root=302\n");
928 	return (0);
929 }
930 
931 #if 0
932 /*
933  * Filler function for proc/modules
934  */
935 static int
936 linprocfs_domodules(PFS_FILL_ARGS)
937 {
938 	struct linker_file *lf;
939 
940 	TAILQ_FOREACH(lf, &linker_files, link) {
941 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
942 		    (unsigned long)lf->size, lf->refs);
943 	}
944 	return (0);
945 }
946 #endif
947 
948 /*
949  * Constructor
950  */
951 static int
952 linprocfs_init(PFS_INIT_ARGS)
953 {
954 	struct pfs_node *root;
955 	struct pfs_node *dir;
956 
957 	root = pi->pi_root;
958 
959 	/* /proc/... */
960 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
961 	    NULL, NULL, PFS_RD);
962 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
963 	    NULL, NULL, PFS_RD);
964 	pfs_create_file(root, "devices", &linprocfs_dodevices,
965 	    NULL, NULL, PFS_RD);
966 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
967 	    NULL, NULL, PFS_RD);
968 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
969 	    NULL, NULL, PFS_RD);
970 #if 0
971 	pfs_create_file(root, "modules", &linprocfs_domodules,
972 	    NULL, NULL, PFS_RD);
973 #endif
974 	pfs_create_file(root, "mounts", &linprocfs_domtab,
975 	    NULL, NULL, PFS_RD);
976 	pfs_create_file(root, "mtab", &linprocfs_domtab,
977 	    NULL, NULL, PFS_RD);
978 	pfs_create_link(root, "self", &procfs_docurproc,
979 	    NULL, NULL, 0);
980 	pfs_create_file(root, "stat", &linprocfs_dostat,
981 	    NULL, NULL, PFS_RD);
982 	pfs_create_file(root, "uptime", &linprocfs_douptime,
983 	    NULL, NULL, PFS_RD);
984 	pfs_create_file(root, "version", &linprocfs_doversion,
985 	    NULL, NULL, PFS_RD);
986 
987 	/* /proc/net/... */
988 	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
989 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
990 	    NULL, NULL, PFS_RD);
991 
992 	/* /proc/<pid>/... */
993 	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
994 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
995 	    NULL, NULL, PFS_RD);
996 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
997 	    NULL, NULL, 0);
998 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
999 	    NULL, NULL, PFS_RD);
1000 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1001 	    NULL, &procfs_notsystem, 0);
1002 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1003 	    NULL, NULL, PFS_RD);
1004 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1005 	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1006 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1007 	    NULL, NULL, 0);
1008 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1009 	    NULL, NULL, PFS_RD);
1010 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1011 	    NULL, NULL, PFS_RD);
1012 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1013 	    NULL, NULL, PFS_RD);
1014 
1015 	/* /proc/scsi/... */
1016 	dir = pfs_create_dir(root, "scsi", NULL, NULL, 0);
1017 	pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1018 	    NULL, NULL, PFS_RD);
1019 	pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1020 	    NULL, NULL, PFS_RD);
1021 	return (0);
1022 }
1023 
1024 /*
1025  * Destructor
1026  */
1027 static int
1028 linprocfs_uninit(PFS_INIT_ARGS)
1029 {
1030 
1031 	/* nothing to do, pseudofs will GC */
1032 	return (0);
1033 }
1034 
1035 PSEUDOFS(linprocfs, 1);
1036 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1037 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1038