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