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