xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision cec50dea12481dc578c0805c887ab2097e1c06c5)
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 #if !COMPAT_LINUX32				/* XXX */
96 #include <machine/../linux/linux.h>
97 #else
98 #include <machine/../linux32/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 = i * PAGE_SIZE;
148 	swapused = 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_NODEV,		"nodev");
399 		ADD_OPTION(MNT_UNION,		"union");
400 		ADD_OPTION(MNT_ASYNC,		"async");
401 		ADD_OPTION(MNT_SUIDDIR,		"suiddir");
402 		ADD_OPTION(MNT_NOSYMFOLLOW,	"nosymfollow");
403 		ADD_OPTION(MNT_NOATIME,		"noatime");
404 #undef ADD_OPTION
405 		/* a real Linux mtab will also show NFS options */
406 		sbuf_printf(sb, " 0 0\n");
407 	}
408 	mtx_unlock(&mountlist_mtx);
409 	if (flep != NULL)
410 		free(flep, M_TEMP);
411 	return (error);
412 }
413 
414 /*
415  * Filler function for proc/stat
416  */
417 static int
418 linprocfs_dostat(PFS_FILL_ARGS)
419 {
420 	int i;
421 
422 	sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
423 	    T2J(cp_time[CP_USER]),
424 	    T2J(cp_time[CP_NICE]),
425 	    T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
426 	    T2J(cp_time[CP_IDLE]));
427 	if (mp_ncpus > 1)
428 		for (i = 0; i < mp_ncpus; ++i)
429 			sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
430 			    T2J(cp_time[CP_USER]) / mp_ncpus,
431 			    T2J(cp_time[CP_NICE]) / mp_ncpus,
432 			    T2J(cp_time[CP_SYS]) / mp_ncpus,
433 			    T2J(cp_time[CP_IDLE]) / mp_ncpus);
434 	sbuf_printf(sb,
435 	    "disk 0 0 0 0\n"
436 	    "page %u %u\n"
437 	    "swap %u %u\n"
438 	    "intr %u\n"
439 	    "ctxt %u\n"
440 	    "btime %lld\n",
441 	    cnt.v_vnodepgsin,
442 	    cnt.v_vnodepgsout,
443 	    cnt.v_swappgsin,
444 	    cnt.v_swappgsout,
445 	    cnt.v_intr,
446 	    cnt.v_swtch,
447 	    (long long)boottime.tv_sec);
448 	return (0);
449 }
450 
451 /*
452  * Filler function for proc/uptime
453  */
454 static int
455 linprocfs_douptime(PFS_FILL_ARGS)
456 {
457 	struct timeval tv;
458 
459 	getmicrouptime(&tv);
460 	sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
461 	    (long long)tv.tv_sec, tv.tv_usec / 10000,
462 	    T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
463 	return (0);
464 }
465 
466 /*
467  * Filler function for proc/version
468  */
469 static int
470 linprocfs_doversion(PFS_FILL_ARGS)
471 {
472 	char osname[LINUX_MAX_UTSNAME];
473 	char osrelease[LINUX_MAX_UTSNAME];
474 
475 	linux_get_osname(td, osname);
476 	linux_get_osrelease(td, osrelease);
477 
478 	sbuf_printf(sb,
479 	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
480 	    " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
481 	return (0);
482 }
483 
484 /*
485  * Filler function for proc/loadavg
486  */
487 static int
488 linprocfs_doloadavg(PFS_FILL_ARGS)
489 {
490 	sbuf_printf(sb,
491 	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
492 	    (int)(averunnable.ldavg[0] / averunnable.fscale),
493 	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
494 	    (int)(averunnable.ldavg[1] / averunnable.fscale),
495 	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
496 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
497 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
498 	    1,				/* number of running tasks */
499 	    nprocs,			/* number of tasks */
500 	    lastpid			/* the last pid */
501 	);
502 
503 	return (0);
504 }
505 
506 /*
507  * Filler function for proc/pid/stat
508  */
509 static int
510 linprocfs_doprocstat(PFS_FILL_ARGS)
511 {
512 	struct kinfo_proc kp;
513 
514 	PROC_LOCK(p);
515 	fill_kinfo_proc(p, &kp);
516 	sbuf_printf(sb, "%d", p->p_pid);
517 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
518 	PS_ADD("comm",		"(%s)",	p->p_comm);
519 	PS_ADD("statr",		"%c",	'0'); /* XXX */
520 	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
521 	PS_ADD("pgrp",		"%d",	p->p_pgid);
522 	PS_ADD("session",	"%d",	p->p_session->s_sid);
523 	PROC_UNLOCK(p);
524 	PS_ADD("tty",		"%d",	0); /* XXX */
525 	PS_ADD("tpgid",		"%d",	0); /* XXX */
526 	PS_ADD("flags",		"%u",	0); /* XXX */
527 	PS_ADD("minflt",	"%u",	0); /* XXX */
528 	PS_ADD("cminflt",	"%u",	0); /* XXX */
529 	PS_ADD("majflt",	"%u",	0); /* XXX */
530 	PS_ADD("cminflt",	"%u",	0); /* XXX */
531 	PS_ADD("utime",		"%d",	0); /* XXX */
532 	PS_ADD("stime",		"%d",	0); /* XXX */
533 	PS_ADD("cutime",	"%d",	0); /* XXX */
534 	PS_ADD("cstime",	"%d",	0); /* XXX */
535 	PS_ADD("counter",	"%d",	0); /* XXX */
536 	PS_ADD("priority",	"%d",	0); /* XXX */
537 	PS_ADD("timeout",	"%u",	0); /* XXX */
538 	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
539 	PS_ADD("starttime",	"%d",	0); /* XXX */
540 	PS_ADD("vsize",		"%ju",	(uintmax_t)kp.ki_size);
541 	PS_ADD("rss",		"%ju",	P2K((uintmax_t)kp.ki_rssize));
542 	PS_ADD("rlim",		"%u",	0); /* XXX */
543 	PS_ADD("startcode",	"%u",	(unsigned)0);
544 	PS_ADD("endcode",	"%u",	0); /* XXX */
545 	PS_ADD("startstack",	"%u",	0); /* XXX */
546 	PS_ADD("esp",		"%u",	0); /* XXX */
547 	PS_ADD("eip",		"%u",	0); /* XXX */
548 	PS_ADD("signal",	"%d",	0); /* XXX */
549 	PS_ADD("blocked",	"%d",	0); /* XXX */
550 	PS_ADD("sigignore",	"%d",	0); /* XXX */
551 	PS_ADD("sigcatch",	"%d",	0); /* XXX */
552 	PS_ADD("wchan",		"%u",	0); /* XXX */
553 	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
554 	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
555 	PS_ADD("exitsignal",	"%d",	0); /* XXX */
556 	PS_ADD("processor",	"%d",	0); /* XXX */
557 #undef PS_ADD
558 	sbuf_putc(sb, '\n');
559 
560 	return (0);
561 }
562 
563 /*
564  * Filler function for proc/pid/statm
565  */
566 static int
567 linprocfs_doprocstatm(PFS_FILL_ARGS)
568 {
569 	struct kinfo_proc kp;
570 	segsz_t lsize;
571 
572 	PROC_LOCK(p);
573 	fill_kinfo_proc(p, &kp);
574 	PROC_UNLOCK(p);
575 
576 	/*
577 	 * See comments in linprocfs_doprocstatus() regarding the
578 	 * computation of lsize.
579 	 */
580 	/* size resident share trs drs lrs dt */
581 	sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
582 	sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
583 	sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
584 	sbuf_printf(sb, "%ju ",	(uintmax_t)kp.ki_tsize);
585 	sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
586 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
587 	    kp.ki_ssize - kp.ki_tsize - 1;
588 	sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
589 	sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
590 
591 	return (0);
592 }
593 
594 /*
595  * Filler function for proc/pid/status
596  */
597 static int
598 linprocfs_doprocstatus(PFS_FILL_ARGS)
599 {
600 	struct kinfo_proc kp;
601 	char *state;
602 	segsz_t lsize;
603 	struct thread *td2;
604 	struct sigacts *ps;
605 	int i;
606 
607 	PROC_LOCK(p);
608 	td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
609 
610 	if (P_SHOULDSTOP(p)) {
611 		state = "T (stopped)";
612 	} else {
613 		mtx_lock_spin(&sched_lock);
614 		switch(p->p_state) {
615 		case PRS_NEW:
616 			state = "I (idle)";
617 			break;
618 		case PRS_NORMAL:
619 			if (p->p_flag & P_WEXIT) {
620 				state = "X (exiting)";
621 				break;
622 			}
623 			switch(td2->td_state) {
624 			case TDS_INHIBITED:
625 				state = "S (sleeping)";
626 				break;
627 			case TDS_RUNQ:
628 			case TDS_RUNNING:
629 				state = "R (running)";
630 				break;
631 			default:
632 				state = "? (unknown)";
633 				break;
634 			}
635 			break;
636 		case PRS_ZOMBIE:
637 			state = "Z (zombie)";
638 			break;
639 		default:
640 			state = "? (unknown)";
641 			break;
642 		}
643 		mtx_unlock_spin(&sched_lock);
644 	}
645 
646 	fill_kinfo_proc(p, &kp);
647 	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
648 	sbuf_printf(sb, "State:\t%s\n",		state);
649 
650 	/*
651 	 * Credentials
652 	 */
653 	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
654 	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
655 						p->p_pptr->p_pid : 0);
656 	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
657 						p->p_ucred->cr_uid,
658 						p->p_ucred->cr_svuid,
659 						/* FreeBSD doesn't have fsuid */
660 						p->p_ucred->cr_uid);
661 	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
662 						p->p_ucred->cr_gid,
663 						p->p_ucred->cr_svgid,
664 						/* FreeBSD doesn't have fsgid */
665 						p->p_ucred->cr_gid);
666 	sbuf_cat(sb, "Groups:\t");
667 	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
668 		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
669 	PROC_UNLOCK(p);
670 	sbuf_putc(sb, '\n');
671 
672 	/*
673 	 * Memory
674 	 *
675 	 * While our approximation of VmLib may not be accurate (I
676 	 * don't know of a simple way to verify it, and I'm not sure
677 	 * it has much meaning anyway), I believe it's good enough.
678 	 *
679 	 * The same code that could (I think) accurately compute VmLib
680 	 * could also compute VmLck, but I don't really care enough to
681 	 * implement it. Submissions are welcome.
682 	 */
683 	sbuf_printf(sb, "VmSize:\t%8ju kB\n",	B2K((uintmax_t)kp.ki_size));
684 	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
685 	sbuf_printf(sb, "VmRss:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_rssize));
686 	sbuf_printf(sb, "VmData:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_dsize));
687 	sbuf_printf(sb, "VmStk:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_ssize));
688 	sbuf_printf(sb, "VmExe:\t%8ju kB\n",	P2K((uintmax_t)kp.ki_tsize));
689 	lsize = B2P(kp.ki_size) - kp.ki_dsize -
690 	    kp.ki_ssize - kp.ki_tsize - 1;
691 	sbuf_printf(sb, "VmLib:\t%8ju kB\n",	P2K((uintmax_t)lsize));
692 
693 	/*
694 	 * Signal masks
695 	 *
696 	 * We support up to 128 signals, while Linux supports 32,
697 	 * but we only define 32 (the same 32 as Linux, to boot), so
698 	 * just show the lower 32 bits of each mask. XXX hack.
699 	 *
700 	 * NB: on certain platforms (Sparc at least) Linux actually
701 	 * supports 64 signals, but this code is a long way from
702 	 * running on anything but i386, so ignore that for now.
703 	 */
704 	PROC_LOCK(p);
705 	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
706 	/*
707 	 * I can't seem to find out where the signal mask is in
708 	 * relation to struct proc, so SigBlk is left unimplemented.
709 	 */
710 	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
711 	ps = p->p_sigacts;
712 	mtx_lock(&ps->ps_mtx);
713 	sbuf_printf(sb, "SigIgn:\t%08x\n",	ps->ps_sigignore.__bits[0]);
714 	sbuf_printf(sb, "SigCgt:\t%08x\n",	ps->ps_sigcatch.__bits[0]);
715 	mtx_unlock(&ps->ps_mtx);
716 	PROC_UNLOCK(p);
717 
718 	/*
719 	 * Linux also prints the capability masks, but we don't have
720 	 * capabilities yet, and when we do get them they're likely to
721 	 * be meaningless to Linux programs, so we lie. XXX
722 	 */
723 	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
724 	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
725 	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
726 
727 	return (0);
728 }
729 
730 
731 /*
732  * Filler function for proc/pid/cwd
733  */
734 static int
735 linprocfs_doproccwd(PFS_FILL_ARGS)
736 {
737 	char *fullpath = "unknown";
738 	char *freepath = NULL;
739 
740 	vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
741 	sbuf_printf(sb, "%s", fullpath);
742 	if (freepath)
743 		free(freepath, M_TEMP);
744 	return (0);
745 }
746 
747 /*
748  * Filler function for proc/pid/root
749  */
750 static int
751 linprocfs_doprocroot(PFS_FILL_ARGS)
752 {
753 	struct vnode *rvp;
754 	char *fullpath = "unknown";
755 	char *freepath = NULL;
756 
757 	rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
758 	vn_fullpath(td, rvp, &fullpath, &freepath);
759 	sbuf_printf(sb, "%s", fullpath);
760 	if (freepath)
761 		free(freepath, M_TEMP);
762 	return (0);
763 }
764 
765 /*
766  * Filler function for proc/pid/cmdline
767  */
768 static int
769 linprocfs_doproccmdline(PFS_FILL_ARGS)
770 {
771 	struct ps_strings pstr;
772 	int error, i;
773 
774 	/*
775 	 * If we are using the ps/cmdline caching, use that.  Otherwise
776 	 * revert back to the old way which only implements full cmdline
777 	 * for the currept process and just p->p_comm for all other
778 	 * processes.
779 	 * Note that if the argv is no longer available, we deliberately
780 	 * don't fall back on p->p_comm or return an error: the authentic
781 	 * Linux behaviour is to return zero-length in this case.
782 	 */
783 
784 	PROC_LOCK(p);
785 	if (p->p_args && p_cansee(td, p) == 0) {
786 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
787 		PROC_UNLOCK(p);
788 	} else if (p != td->td_proc) {
789 		PROC_UNLOCK(p);
790 		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
791 	} else {
792 		PROC_UNLOCK(p);
793 		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
794 		    sizeof(pstr));
795 		if (error)
796 			return (error);
797 		for (i = 0; i < pstr.ps_nargvstr; i++) {
798 			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
799 			sbuf_printf(sb, "%c", '\0');
800 		}
801 	}
802 
803 	return (0);
804 }
805 
806 /*
807  * Filler function for proc/pid/environ
808  */
809 static int
810 linprocfs_doprocenviron(PFS_FILL_ARGS)
811 {
812 	sbuf_printf(sb, "doprocenviron\n%c", '\0');
813 
814 	return (0);
815 }
816 
817 /*
818  * Filler function for proc/pid/maps
819  */
820 static int
821 linprocfs_doprocmaps(PFS_FILL_ARGS)
822 {
823 	char mebuffer[512];
824 	vm_map_t map = &p->p_vmspace->vm_map;
825 	vm_map_entry_t entry;
826 	vm_object_t obj, tobj, lobj;
827 	vm_ooffset_t off = 0;
828 	char *name = "", *freename = NULL;
829 	size_t len;
830 	ino_t ino;
831 	int ref_count, shadow_count, flags;
832 	int error;
833 
834 	PROC_LOCK(p);
835 	error = p_candebug(td, p);
836 	PROC_UNLOCK(p);
837 	if (error)
838 		return (error);
839 
840 	if (uio->uio_rw != UIO_READ)
841 		return (EOPNOTSUPP);
842 
843 	if (uio->uio_offset != 0)
844 		return (0);
845 
846 	error = 0;
847 	if (map != &curthread->td_proc->p_vmspace->vm_map)
848 		vm_map_lock_read(map);
849         for (entry = map->header.next;
850 	    ((uio->uio_resid > 0) && (entry != &map->header));
851 	    entry = entry->next) {
852 		name = "";
853 		freename = NULL;
854 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
855 			continue;
856 		obj = entry->object.vm_object;
857 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
858 			lobj = tobj;
859 		ino = 0;
860 		if (lobj) {
861 			VM_OBJECT_LOCK(lobj);
862 			off = IDX_TO_OFF(lobj->size);
863 			if (lobj->type == OBJT_VNODE && lobj->handle) {
864 				vn_fullpath(td, (struct vnode *)lobj->handle,
865 				    &name, &freename);
866 				ino = ((struct vnode *)
867 				    lobj->handle)->v_cachedid;
868 			}
869 			flags = obj->flags;
870 			ref_count = obj->ref_count;
871 			shadow_count = obj->shadow_count;
872 			VM_OBJECT_UNLOCK(lobj);
873 		} else {
874 			flags = 0;
875 			ref_count = 0;
876 			shadow_count = 0;
877 		}
878 
879 		/*
880 	     	 * format:
881 		 *  start, end, access, offset, major, minor, inode, name.
882 		 */
883 		snprintf(mebuffer, sizeof mebuffer,
884 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
885 		    (u_long)entry->start, (u_long)entry->end,
886 		    (entry->protection & VM_PROT_READ)?"r":"-",
887 		    (entry->protection & VM_PROT_WRITE)?"w":"-",
888 		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
889 		    "p",
890 		    (u_long)off,
891 		    0,
892 		    0,
893 		    (u_long)ino,
894 		    *name ? "     " : "",
895 		    name
896 		    );
897 		if (freename)
898 			free(freename, M_TEMP);
899 		len = strlen(mebuffer);
900 		if (len > uio->uio_resid)
901 			len = uio->uio_resid; /*
902 					       * XXX We should probably return
903 					       * EFBIG here, as in procfs.
904 					       */
905 		error = uiomove(mebuffer, len, uio);
906 		if (error)
907 			break;
908 	}
909 	if (map != &curthread->td_proc->p_vmspace->vm_map)
910 		vm_map_unlock_read(map);
911 
912 	return (error);
913 }
914 
915 /*
916  * Filler function for proc/net/dev
917  */
918 static int
919 linprocfs_donetdev(PFS_FILL_ARGS)
920 {
921 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
922 	struct ifnet *ifp;
923 
924 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
925 	    "Inter-", "   Receive", "  Transmit", " face",
926 	    "bytes    packets errs drop fifo frame compressed",
927 	    "bytes    packets errs drop fifo frame compressed");
928 
929 	IFNET_RLOCK();
930 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
931 		linux_ifname(ifp, ifname, sizeof ifname);
932 			sbuf_printf(sb, "%6.6s:", ifname);
933 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
934 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
935 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
936 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
937 	}
938 	IFNET_RUNLOCK();
939 
940 	return (0);
941 }
942 
943 #if 0
944 extern struct cdevsw *cdevsw[];
945 
946 /*
947  * Filler function for proc/devices
948  */
949 static int
950 linprocfs_dodevices(PFS_FILL_ARGS)
951 {
952 	int i;
953 
954 	sbuf_printf(sb, "Character devices:\n");
955 
956 	for (i = 0; i < NUMCDEVSW; i++)
957 		if (cdevsw[i] != NULL)
958 			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
959 
960 	sbuf_printf(sb, "\nBlock devices:\n");
961 
962 	return (0);
963 }
964 #endif
965 
966 /*
967  * Filler function for proc/cmdline
968  */
969 static int
970 linprocfs_docmdline(PFS_FILL_ARGS)
971 {
972 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
973 	sbuf_printf(sb, " ro root=302\n");
974 	return (0);
975 }
976 
977 #if 0
978 /*
979  * Filler function for proc/modules
980  */
981 static int
982 linprocfs_domodules(PFS_FILL_ARGS)
983 {
984 	struct linker_file *lf;
985 
986 	TAILQ_FOREACH(lf, &linker_files, link) {
987 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
988 		    (unsigned long)lf->size, lf->refs);
989 	}
990 	return (0);
991 }
992 #endif
993 
994 /*
995  * Constructor
996  */
997 static int
998 linprocfs_init(PFS_INIT_ARGS)
999 {
1000 	struct pfs_node *root;
1001 	struct pfs_node *dir;
1002 
1003 	root = pi->pi_root;
1004 
1005 	/* /proc/... */
1006 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1007 	    NULL, NULL, PFS_RD);
1008 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1009 	    NULL, NULL, PFS_RD);
1010 #if 0
1011 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1012 	    NULL, NULL, PFS_RD);
1013 #endif
1014 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1015 	    NULL, NULL, PFS_RD);
1016 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1017 	    NULL, NULL, PFS_RD);
1018 #if 0
1019 	pfs_create_file(root, "modules", &linprocfs_domodules,
1020 	    NULL, NULL, PFS_RD);
1021 #endif
1022 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1023 	    NULL, NULL, PFS_RD);
1024 	pfs_create_link(root, "self", &procfs_docurproc,
1025 	    NULL, NULL, 0);
1026 	pfs_create_file(root, "stat", &linprocfs_dostat,
1027 	    NULL, NULL, PFS_RD);
1028 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1029 	    NULL, NULL, PFS_RD);
1030 	pfs_create_file(root, "version", &linprocfs_doversion,
1031 	    NULL, NULL, PFS_RD);
1032 
1033 	/* /proc/net/... */
1034 	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1035 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1036 	    NULL, NULL, PFS_RD);
1037 
1038 	/* /proc/<pid>/... */
1039 	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1040 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1041 	    NULL, NULL, PFS_RD);
1042 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1043 	    NULL, NULL, 0);
1044 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1045 	    NULL, NULL, PFS_RD);
1046 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1047 	    NULL, &procfs_notsystem, 0);
1048 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1049 	    NULL, NULL, PFS_RD);
1050 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1051 	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1052 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1053 	    NULL, NULL, 0);
1054 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1055 	    NULL, NULL, PFS_RD);
1056 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1057 	    NULL, NULL, PFS_RD);
1058 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1059 	    NULL, NULL, PFS_RD);
1060 
1061 	return (0);
1062 }
1063 
1064 /*
1065  * Destructor
1066  */
1067 static int
1068 linprocfs_uninit(PFS_INIT_ARGS)
1069 {
1070 
1071 	/* nothing to do, pseudofs will GC */
1072 	return (0);
1073 }
1074 
1075 PSEUDOFS(linprocfs, 1);
1076 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1077 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1078