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