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