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