xref: /freebsd/sys/compat/linprocfs/linprocfs.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
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 = 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 	char **ps_argvstr;
773 	int error, i;
774 
775 	/*
776 	 * If we are using the ps/cmdline caching, use that.  Otherwise
777 	 * revert back to the old way which only implements full cmdline
778 	 * for the currept process and just p->p_comm for all other
779 	 * processes.
780 	 * Note that if the argv is no longer available, we deliberately
781 	 * don't fall back on p->p_comm or return an error: the authentic
782 	 * Linux behaviour is to return zero-length in this case.
783 	 */
784 
785 	PROC_LOCK(p);
786 	if (p->p_args && p_cansee(td, p) == 0) {
787 		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
788 		PROC_UNLOCK(p);
789 	} else if (p != td->td_proc) {
790 		PROC_UNLOCK(p);
791 		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
792 	} else {
793 		PROC_UNLOCK(p);
794 		error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
795 		    sizeof(pstr));
796 		if (error)
797 			return (error);
798 		if (pstr.ps_nargvstr > ARG_MAX)
799 			return (E2BIG);
800 		ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
801 		    M_TEMP, M_WAITOK);
802 		error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
803 		    pstr.ps_nargvstr * sizeof(char *));
804 		if (error) {
805 			free(ps_argvstr, M_TEMP);
806 			return (error);
807 		}
808 		for (i = 0; i < pstr.ps_nargvstr; i++) {
809 			sbuf_copyin(sb, ps_argvstr[i], 0);
810 			sbuf_printf(sb, "%c", '\0');
811 		}
812 		free(ps_argvstr, M_TEMP);
813 	}
814 
815 	return (0);
816 }
817 
818 /*
819  * Filler function for proc/pid/environ
820  */
821 static int
822 linprocfs_doprocenviron(PFS_FILL_ARGS)
823 {
824 	sbuf_printf(sb, "doprocenviron\n%c", '\0');
825 
826 	return (0);
827 }
828 
829 /*
830  * Filler function for proc/pid/maps
831  */
832 static int
833 linprocfs_doprocmaps(PFS_FILL_ARGS)
834 {
835 	char mebuffer[512];
836 	vm_map_t map = &p->p_vmspace->vm_map;
837 	vm_map_entry_t entry;
838 	vm_object_t obj, tobj, lobj;
839 	vm_ooffset_t off = 0;
840 	char *name = "", *freename = NULL;
841 	size_t len;
842 	ino_t ino;
843 	int ref_count, shadow_count, flags;
844 	int error;
845 	struct vnode *vp;
846 	struct vattr vat;
847 
848 	PROC_LOCK(p);
849 	error = p_candebug(td, p);
850 	PROC_UNLOCK(p);
851 	if (error)
852 		return (error);
853 
854 	if (uio->uio_rw != UIO_READ)
855 		return (EOPNOTSUPP);
856 
857 	if (uio->uio_offset != 0)
858 		return (0);
859 
860 	error = 0;
861 	if (map != &curthread->td_proc->p_vmspace->vm_map)
862 		vm_map_lock_read(map);
863         for (entry = map->header.next;
864 	    ((uio->uio_resid > 0) && (entry != &map->header));
865 	    entry = entry->next) {
866 		name = "";
867 		freename = NULL;
868 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
869 			continue;
870 		obj = entry->object.vm_object;
871 		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
872 			lobj = tobj;
873 		ino = 0;
874 		if (lobj) {
875 			vp = lobj->handle;
876 			VM_OBJECT_LOCK(lobj);
877 			off = IDX_TO_OFF(lobj->size);
878 			if (lobj->type == OBJT_VNODE && lobj->handle) {
879 				vn_fullpath(td, vp, &name, &freename);
880 				VOP_GETATTR(vp, &vat, td->td_ucred, td);
881 				ino = vat.va_fileid;
882 			}
883 			flags = obj->flags;
884 			ref_count = obj->ref_count;
885 			shadow_count = obj->shadow_count;
886 			VM_OBJECT_UNLOCK(lobj);
887 		} else {
888 			flags = 0;
889 			ref_count = 0;
890 			shadow_count = 0;
891 		}
892 
893 		/*
894 	     	 * format:
895 		 *  start, end, access, offset, major, minor, inode, name.
896 		 */
897 		snprintf(mebuffer, sizeof mebuffer,
898 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
899 		    (u_long)entry->start, (u_long)entry->end,
900 		    (entry->protection & VM_PROT_READ)?"r":"-",
901 		    (entry->protection & VM_PROT_WRITE)?"w":"-",
902 		    (entry->protection & VM_PROT_EXECUTE)?"x":"-",
903 		    "p",
904 		    (u_long)off,
905 		    0,
906 		    0,
907 		    (u_long)ino,
908 		    *name ? "     " : "",
909 		    name
910 		    );
911 		if (freename)
912 			free(freename, M_TEMP);
913 		len = strlen(mebuffer);
914 		if (len > uio->uio_resid)
915 			len = uio->uio_resid; /*
916 					       * XXX We should probably return
917 					       * EFBIG here, as in procfs.
918 					       */
919 		error = uiomove(mebuffer, len, uio);
920 		if (error)
921 			break;
922 	}
923 	if (map != &curthread->td_proc->p_vmspace->vm_map)
924 		vm_map_unlock_read(map);
925 
926 	return (error);
927 }
928 
929 /*
930  * Filler function for proc/net/dev
931  */
932 static int
933 linprocfs_donetdev(PFS_FILL_ARGS)
934 {
935 	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
936 	struct ifnet *ifp;
937 
938 	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
939 	    "Inter-", "   Receive", "  Transmit", " face",
940 	    "bytes    packets errs drop fifo frame compressed",
941 	    "bytes    packets errs drop fifo frame compressed");
942 
943 	IFNET_RLOCK();
944 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
945 		linux_ifname(ifp, ifname, sizeof ifname);
946 			sbuf_printf(sb, "%6.6s:", ifname);
947 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
948 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
949 		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
950 		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
951 	}
952 	IFNET_RUNLOCK();
953 
954 	return (0);
955 }
956 
957 #if 0
958 extern struct cdevsw *cdevsw[];
959 
960 /*
961  * Filler function for proc/devices
962  */
963 static int
964 linprocfs_dodevices(PFS_FILL_ARGS)
965 {
966 	int i;
967 
968 	sbuf_printf(sb, "Character devices:\n");
969 
970 	for (i = 0; i < NUMCDEVSW; i++)
971 		if (cdevsw[i] != NULL)
972 			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
973 
974 	sbuf_printf(sb, "\nBlock devices:\n");
975 
976 	return (0);
977 }
978 #endif
979 
980 /*
981  * Filler function for proc/cmdline
982  */
983 static int
984 linprocfs_docmdline(PFS_FILL_ARGS)
985 {
986 	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
987 	sbuf_printf(sb, " ro root=302\n");
988 	return (0);
989 }
990 
991 #if 0
992 /*
993  * Filler function for proc/modules
994  */
995 static int
996 linprocfs_domodules(PFS_FILL_ARGS)
997 {
998 	struct linker_file *lf;
999 
1000 	TAILQ_FOREACH(lf, &linker_files, link) {
1001 		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1002 		    (unsigned long)lf->size, lf->refs);
1003 	}
1004 	return (0);
1005 }
1006 #endif
1007 
1008 /*
1009  * Constructor
1010  */
1011 static int
1012 linprocfs_init(PFS_INIT_ARGS)
1013 {
1014 	struct pfs_node *root;
1015 	struct pfs_node *dir;
1016 
1017 	root = pi->pi_root;
1018 
1019 	/* /proc/... */
1020 	pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1021 	    NULL, NULL, PFS_RD);
1022 	pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1023 	    NULL, NULL, PFS_RD);
1024 #if 0
1025 	pfs_create_file(root, "devices", &linprocfs_dodevices,
1026 	    NULL, NULL, PFS_RD);
1027 #endif
1028 	pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1029 	    NULL, NULL, PFS_RD);
1030 	pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1031 	    NULL, NULL, PFS_RD);
1032 #if 0
1033 	pfs_create_file(root, "modules", &linprocfs_domodules,
1034 	    NULL, NULL, PFS_RD);
1035 #endif
1036 	pfs_create_file(root, "mtab", &linprocfs_domtab,
1037 	    NULL, NULL, PFS_RD);
1038 	pfs_create_link(root, "self", &procfs_docurproc,
1039 	    NULL, NULL, 0);
1040 	pfs_create_file(root, "stat", &linprocfs_dostat,
1041 	    NULL, NULL, PFS_RD);
1042 	pfs_create_file(root, "uptime", &linprocfs_douptime,
1043 	    NULL, NULL, PFS_RD);
1044 	pfs_create_file(root, "version", &linprocfs_doversion,
1045 	    NULL, NULL, PFS_RD);
1046 
1047 	/* /proc/net/... */
1048 	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1049 	pfs_create_file(dir, "dev", &linprocfs_donetdev,
1050 	    NULL, NULL, PFS_RD);
1051 
1052 	/* /proc/<pid>/... */
1053 	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1054 	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1055 	    NULL, NULL, PFS_RD);
1056 	pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1057 	    NULL, NULL, 0);
1058 	pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1059 	    NULL, NULL, PFS_RD);
1060 	pfs_create_link(dir, "exe", &procfs_doprocfile,
1061 	    NULL, &procfs_notsystem, 0);
1062 	pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1063 	    NULL, NULL, PFS_RD);
1064 	pfs_create_file(dir, "mem", &procfs_doprocmem,
1065 	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1066 	pfs_create_link(dir, "root", &linprocfs_doprocroot,
1067 	    NULL, NULL, 0);
1068 	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1069 	    NULL, NULL, PFS_RD);
1070 	pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1071 	    NULL, NULL, PFS_RD);
1072 	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1073 	    NULL, NULL, PFS_RD);
1074 
1075 	return (0);
1076 }
1077 
1078 /*
1079  * Destructor
1080  */
1081 static int
1082 linprocfs_uninit(PFS_INIT_ARGS)
1083 {
1084 
1085 	/* nothing to do, pseudofs will GC */
1086 	return (0);
1087 }
1088 
1089 PSEUDOFS(linprocfs, 1);
1090 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1091 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1092