linprocfs.c revision 85538
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 * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 85538 2001-10-26 15:30:44Z phk $
42 */
43
44#include <sys/param.h>
45#include <sys/queue.h>
46#include <sys/blist.h>
47#include <sys/conf.h>
48#include <sys/dkstat.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/vm_zone.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>
85extern 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 <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 */
112static int
113linprocfs_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	u_quad_t swaptotal;		/* total swap space in bytes */
121	u_quad_t swapused;		/* used swap space in bytes */
122	u_quad_t swapfree;		/* free swap space in bytes */
123	vm_object_t object;
124
125	memtotal = physmem * PAGE_SIZE;
126	/*
127	 * The correct thing here would be:
128	 *
129	memfree = cnt.v_free_count * PAGE_SIZE;
130	memused = memtotal - memfree;
131	 *
132	 * but it might mislead linux binaries into thinking there
133	 * is very little memory left, so we cheat and tell them that
134	 * all memory that isn't wired down is free.
135	 */
136	memused = cnt.v_wire_count * PAGE_SIZE;
137	memfree = memtotal - memused;
138	if (swapblist == NULL) {
139		swaptotal = 0;
140		swapfree = 0;
141	} else {
142		swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */
143		swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
144	}
145	swapused = swaptotal - swapfree;
146	memshared = 0;
147	TAILQ_FOREACH(object, &vm_object_list, object_list)
148		if (object->shadow_count > 1)
149			memshared += object->resident_page_count;
150	memshared *= PAGE_SIZE;
151	/*
152	 * We'd love to be able to write:
153	 *
154	buffers = bufspace;
155	 *
156	 * but bufspace is internal to vfs_bio.c and we don't feel
157	 * like unstaticizing it just for linprocfs's sake.
158	 */
159	buffers = 0;
160	cached = cnt.v_cache_count * PAGE_SIZE;
161
162	sbuf_printf(sb,
163	    "	     total:    used:	free:  shared: buffers:	 cached:\n"
164	    "Mem:  %lu %lu %lu %lu %lu %lu\n"
165	    "Swap: %llu %llu %llu\n"
166	    "MemTotal: %9lu kB\n"
167	    "MemFree:  %9lu kB\n"
168	    "MemShared:%9lu kB\n"
169	    "Buffers:  %9lu kB\n"
170	    "Cached:   %9lu kB\n"
171	    "SwapTotal:%9llu kB\n"
172	    "SwapFree: %9llu kB\n",
173	    memtotal, memused, memfree, memshared, buffers, cached,
174	    swaptotal, swapused, swapfree,
175	    B2K(memtotal), B2K(memfree),
176	    B2K(memshared), B2K(buffers), B2K(cached),
177	    B2K(swaptotal), B2K(swapfree));
178
179	return (0);
180}
181
182#ifdef __alpha__
183/*
184 * Filler function for proc/cpuinfo (Alpha version)
185 */
186static int
187linprocfs_docpuinfo(PFS_FILL_ARGS)
188{
189	u_int64_t type, major;
190	struct pcs *pcsp;
191	const char *model, *sysname;
192
193	static const char *cpuname[] = {
194		"EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
195		"EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
196	};
197
198	pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
199	type = pcsp->pcs_proc_type;
200	major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
201	if (major < sizeof(cpuname)/sizeof(char *)) {
202		model = cpuname[major - 1];
203	} else {
204		model = "unknown";
205	}
206
207	sysname = alpha_dsr_sysname();
208
209	sbuf_printf(sb,
210	    "cpu\t\t\t: Alpha\n"
211	    "cpu model\t\t: %s\n"
212	    "cpu variation\t\t: %ld\n"
213	    "cpu revision\t\t: %ld\n"
214	    "cpu serial number\t: %s\n"
215	    "system type\t\t: %s\n"
216	    "system variation\t: %s\n"
217	    "system revision\t\t: %ld\n"
218	    "system serial number\t: %s\n"
219	    "cycle frequency [Hz]\t: %lu\n"
220	    "timer frequency [Hz]\t: %lu\n"
221	    "page size [bytes]\t: %ld\n"
222	    "phys. address bits\t: %ld\n"
223	    "max. addr. space #\t: %ld\n"
224	    "BogoMIPS\t\t: %lu.%02lu\n"
225	    "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
226	    "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
227	    "platform string\t\t: %s\n"
228	    "cpus detected\t\t: %d\n"
229	    ,
230	    model,
231	    pcsp->pcs_proc_var,
232	    *(int *)hwrpb->rpb_revision,
233	    " ",
234	    " ",
235	    "0",
236	    0,
237	    " ",
238	    hwrpb->rpb_cc_freq,
239	    hz,
240	    hwrpb->rpb_page_size,
241	    hwrpb->rpb_phys_addr_size,
242	    hwrpb->rpb_max_asn,
243	    0, 0,
244	    0, 0, 0,
245	    0, 0, 0,
246	    sysname,
247	    ncpus);
248	return (0);
249}
250#endif /* __alpha__ */
251
252#ifdef __i386__
253/*
254 * Filler function for proc/cpuinfo (i386 version)
255 */
256static int
257linprocfs_docpuinfo(PFS_FILL_ARGS)
258{
259	int class, i, fqmhz, fqkhz;
260
261	/*
262	 * We default the flags to include all non-conflicting flags,
263	 * and the Intel versions of conflicting flags.
264	 */
265	static char *flags[] = {
266		"fpu",	    "vme",     "de",	   "pse",      "tsc",
267		"msr",	    "pae",     "mce",	   "cx8",      "apic",
268		"sep",	    "sep",     "mtrr",	   "pge",      "mca",
269		"cmov",	    "pat",     "pse36",	   "pn",       "b19",
270		"b20",	    "b21",     "mmxext",   "mmx",      "fxsr",
271		"xmm",	    "b26",     "b27",	   "b28",      "b29",
272		"3dnowext", "3dnow"
273	};
274
275	switch (cpu_class) {
276	case CPUCLASS_286:
277		class = 2;
278		break;
279	case CPUCLASS_386:
280		class = 3;
281		break;
282	case CPUCLASS_486:
283		class = 4;
284		break;
285	case CPUCLASS_586:
286		class = 5;
287		break;
288	case CPUCLASS_686:
289		class = 6;
290		break;
291	default:
292		class = 0;
293		break;
294	}
295
296	sbuf_printf(sb,
297	    "processor\t: %d\n"
298	    "vendor_id\t: %.20s\n"
299	    "cpu family\t: %d\n"
300	    "model\t\t: %d\n"
301	    "stepping\t: %d\n",
302	    0, cpu_vendor, class, cpu, cpu_id & 0xf);
303
304	sbuf_cat(sb,
305	    "flags\t\t:");
306
307	if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
308		flags[16] = "fcmov";
309	} else if (!strcmp(cpu_vendor, "CyrixInstead")) {
310		flags[24] = "cxmmx";
311	}
312
313	for (i = 0; i < 32; i++)
314		if (cpu_feature & (1 << i))
315			sbuf_printf(sb, " %s", flags[i]);
316	sbuf_cat(sb, "\n");
317	if (class >= 5) {
318		fqmhz = (tsc_freq + 4999) / 1000000;
319		fqkhz = ((tsc_freq + 4999) / 10000) % 100;
320		sbuf_printf(sb,
321		    "cpu MHz\t\t: %d.%02d\n"
322		    "bogomips\t: %d.%02d\n",
323		    fqmhz, fqkhz, fqmhz, fqkhz);
324	}
325
326	return (0);
327}
328#endif /* __i386__ */
329
330/*
331 * Filler function for proc/mtab
332 *
333 * This file doesn't exist in Linux' procfs, but is included here so
334 * users can symlink /compat/linux/etc/mtab to /proc/mtab
335 */
336static int
337linprocfs_domtab(PFS_FILL_ARGS)
338{
339	struct nameidata nd;
340	struct mount *mp;
341	char *lep, *flep, *mntto, *mntfrom, *fstype;
342	size_t lep_len;
343	int error;
344
345	/* resolve symlinks etc. in the emulation tree prefix */
346	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
347	flep = NULL;
348	if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1)
349		lep = linux_emul_path;
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 */
401static int
402linprocfs_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 %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	    cnt.v_vnodepgsin,
417	    cnt.v_vnodepgsout,
418	    cnt.v_swappgsin,
419	    cnt.v_swappgsout,
420	    cnt.v_intr,
421	    cnt.v_swtch,
422	    boottime.tv_sec);
423	return (0);
424}
425
426/*
427 * Filler function for proc/uptime
428 */
429static int
430linprocfs_douptime(PFS_FILL_ARGS)
431{
432	struct timeval tv;
433
434	getmicrouptime(&tv);
435	sbuf_printf(sb, "%ld.%02ld %ld.%02ld\n",
436	    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 */
444static int
445linprocfs_doversion(PFS_FILL_ARGS)
446{
447	sbuf_printf(sb,
448	    "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
449	    " #4 Sun Dec 18 04:30:00 CET 1977\n",
450	    linux_get_osname(td->td_proc),
451	    linux_get_osrelease(td->td_proc));
452	return (0);
453}
454
455/*
456 * Filler function for proc/loadavg
457 */
458static int
459linprocfs_doloadavg(PFS_FILL_ARGS)
460{
461	sbuf_printf(sb,
462	    "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
463	    (int)(averunnable.ldavg[0] / averunnable.fscale),
464	    (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
465	    (int)(averunnable.ldavg[1] / averunnable.fscale),
466	    (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
467	    (int)(averunnable.ldavg[2] / averunnable.fscale),
468	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
469	    1,				/* number of running tasks */
470	    nprocs,			/* number of tasks */
471	    lastpid			/* the last pid */
472	);
473
474	return (0);
475}
476
477/*
478 * Filler function for proc/pid/stat
479 */
480static int
481linprocfs_doprocstat(PFS_FILL_ARGS)
482{
483	struct kinfo_proc kp;
484
485	fill_kinfo_proc(p, &kp);
486	sbuf_printf(sb, "%d", p->p_pid);
487#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
488	PS_ADD("comm",		"(%s)",	p->p_comm);
489	PS_ADD("statr",		"%c",	'0'); /* XXX */
490	PROC_LOCK(p);
491	PS_ADD("ppid",		"%d",	p->p_pptr ? p->p_pptr->p_pid : 0);
492	PROC_UNLOCK(p);
493	PS_ADD("pgrp",		"%d",	p->p_pgid);
494	PS_ADD("session",	"%d",	p->p_session->s_sid);
495	PS_ADD("tty",		"%d",	0); /* XXX */
496	PS_ADD("tpgid",		"%d",	0); /* XXX */
497	PS_ADD("flags",		"%u",	0); /* XXX */
498	PS_ADD("minflt",	"%u",	0); /* XXX */
499	PS_ADD("cminflt",	"%u",	0); /* XXX */
500	PS_ADD("majflt",	"%u",	0); /* XXX */
501	PS_ADD("cminflt",	"%u",	0); /* XXX */
502	PS_ADD("utime",		"%d",	0); /* XXX */
503	PS_ADD("stime",		"%d",	0); /* XXX */
504	PS_ADD("cutime",	"%d",	0); /* XXX */
505	PS_ADD("cstime",	"%d",	0); /* XXX */
506	PS_ADD("counter",	"%d",	0); /* XXX */
507	PS_ADD("priority",	"%d",	0); /* XXX */
508	PS_ADD("timeout",	"%u",	0); /* XXX */
509	PS_ADD("itrealvalue",	"%u",	0); /* XXX */
510	PS_ADD("starttime",	"%d",	0); /* XXX */
511	PS_ADD("vsize",		"%u",	kp.ki_size);
512	PS_ADD("rss",		"%u",	P2K(kp.ki_rssize));
513	PS_ADD("rlim",		"%u",	0); /* XXX */
514	PS_ADD("startcode",	"%u",	(unsigned)0);
515	PS_ADD("endcode",	"%u",	0); /* XXX */
516	PS_ADD("startstack",	"%u",	0); /* XXX */
517	PS_ADD("esp",		"%u",	0); /* XXX */
518	PS_ADD("eip",		"%u",	0); /* XXX */
519	PS_ADD("signal",	"%d",	0); /* XXX */
520	PS_ADD("blocked",	"%d",	0); /* XXX */
521	PS_ADD("sigignore",	"%d",	0); /* XXX */
522	PS_ADD("sigcatch",	"%d",	0); /* XXX */
523	PS_ADD("wchan",		"%u",	0); /* XXX */
524	PS_ADD("nswap",		"%lu",	(long unsigned)0); /* XXX */
525	PS_ADD("cnswap",	"%lu",	(long unsigned)0); /* XXX */
526	PS_ADD("exitsignal",	"%d",	0); /* XXX */
527	PS_ADD("processor",	"%d",	0); /* XXX */
528#undef PS_ADD
529	sbuf_putc(sb, '\n');
530
531	return (0);
532}
533
534/*
535 * Map process state to descriptive letter. Note that this does not
536 * quite correspond to what Linux outputs, but it's close enough.
537 */
538static char *state_str[] = {
539	"? (unknown)",
540	"I (idle)",
541	"R (running)",
542	"S (sleeping)",
543	"T (stopped)",
544	"Z (zombie)",
545	"W (waiting)",
546	"M (mutex)"
547};
548
549/*
550 * Filler function for proc/pid/status
551 */
552static int
553linprocfs_doprocstatus(PFS_FILL_ARGS)
554{
555	struct kinfo_proc kp;
556	char *state;
557	segsz_t lsize;
558	int i;
559
560	mtx_lock_spin(&sched_lock);
561	if (p->p_stat > sizeof state_str / sizeof *state_str)
562		state = state_str[0];
563	else
564		state = state_str[(int)p->p_stat];
565	mtx_unlock_spin(&sched_lock);
566
567	fill_kinfo_proc(p, &kp);
568	sbuf_printf(sb, "Name:\t%s\n",		p->p_comm); /* XXX escape */
569	sbuf_printf(sb, "State:\t%s\n",		state);
570
571	/*
572	 * Credentials
573	 */
574	sbuf_printf(sb, "Pid:\t%d\n",		p->p_pid);
575	PROC_LOCK(p);
576	sbuf_printf(sb, "PPid:\t%d\n",		p->p_pptr ?
577						p->p_pptr->p_pid : 0);
578	sbuf_printf(sb, "Uid:\t%d %d %d %d\n",	p->p_ucred->cr_ruid,
579						p->p_ucred->cr_uid,
580						p->p_ucred->cr_svuid,
581						/* FreeBSD doesn't have fsuid */
582						p->p_ucred->cr_uid);
583	sbuf_printf(sb, "Gid:\t%d %d %d %d\n",	p->p_ucred->cr_rgid,
584						p->p_ucred->cr_gid,
585						p->p_ucred->cr_svgid,
586						/* FreeBSD doesn't have fsgid */
587						p->p_ucred->cr_gid);
588	sbuf_cat(sb, "Groups:\t");
589	for (i = 0; i < p->p_ucred->cr_ngroups; i++)
590		sbuf_printf(sb, "%d ",		p->p_ucred->cr_groups[i]);
591	PROC_UNLOCK(p);
592	sbuf_putc(sb, '\n');
593
594	/*
595	 * Memory
596	 *
597	 * While our approximation of VmLib may not be accurate (I
598	 * don't know of a simple way to verify it, and I'm not sure
599	 * it has much meaning anyway), I believe it's good enough.
600	 *
601	 * The same code that could (I think) accurately compute VmLib
602	 * could also compute VmLck, but I don't really care enough to
603	 * implement it. Submissions are welcome.
604	 */
605	sbuf_printf(sb, "VmSize:\t%8u kB\n",	B2K(kp.ki_size));
606	sbuf_printf(sb, "VmLck:\t%8u kB\n",	P2K(0)); /* XXX */
607	sbuf_printf(sb, "VmRss:\t%8u kB\n",	P2K(kp.ki_rssize));
608	sbuf_printf(sb, "VmData:\t%8u kB\n",	P2K(kp.ki_dsize));
609	sbuf_printf(sb, "VmStk:\t%8u kB\n",	P2K(kp.ki_ssize));
610	sbuf_printf(sb, "VmExe:\t%8u kB\n",	P2K(kp.ki_tsize));
611	lsize = B2P(kp.ki_size) - kp.ki_dsize -
612	    kp.ki_ssize - kp.ki_tsize - 1;
613	sbuf_printf(sb, "VmLib:\t%8u kB\n",	P2K(lsize));
614
615	/*
616	 * Signal masks
617	 *
618	 * We support up to 128 signals, while Linux supports 32,
619	 * but we only define 32 (the same 32 as Linux, to boot), so
620	 * just show the lower 32 bits of each mask. XXX hack.
621	 *
622	 * NB: on certain platforms (Sparc at least) Linux actually
623	 * supports 64 signals, but this code is a long way from
624	 * running on anything but i386, so ignore that for now.
625	 */
626	PROC_LOCK(p);
627	sbuf_printf(sb, "SigPnd:\t%08x\n",	p->p_siglist.__bits[0]);
628	/*
629	 * I can't seem to find out where the signal mask is in
630	 * relation to struct proc, so SigBlk is left unimplemented.
631	 */
632	sbuf_printf(sb, "SigBlk:\t%08x\n",	0); /* XXX */
633	sbuf_printf(sb, "SigIgn:\t%08x\n",	p->p_sigignore.__bits[0]);
634	sbuf_printf(sb, "SigCgt:\t%08x\n",	p->p_sigcatch.__bits[0]);
635	PROC_UNLOCK(p);
636
637	/*
638	 * Linux also prints the capability masks, but we don't have
639	 * capabilities yet, and when we do get them they're likely to
640	 * be meaningless to Linux programs, so we lie. XXX
641	 */
642	sbuf_printf(sb, "CapInh:\t%016x\n",	0);
643	sbuf_printf(sb, "CapPrm:\t%016x\n",	0);
644	sbuf_printf(sb, "CapEff:\t%016x\n",	0);
645
646	return (0);
647}
648
649/*
650 * Filler function for proc/self
651 */
652static int
653linprocfs_doselflink(PFS_FILL_ARGS)
654{
655	sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid);
656	return (0);
657}
658
659/*
660 * Filler function for proc/pid/cmdline
661 */
662static int
663linprocfs_doproccmdline(PFS_FILL_ARGS)
664{
665	struct ps_strings pstr;
666	int error, i;
667
668	/*
669	 * If we are using the ps/cmdline caching, use that.  Otherwise
670	 * revert back to the old way which only implements full cmdline
671	 * for the currept process and just p->p_comm for all other
672	 * processes.
673	 * Note that if the argv is no longer available, we deliberately
674	 * don't fall back on p->p_comm or return an error: the authentic
675	 * Linux behaviour is to return zero-length in this case.
676	 */
677
678	if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) {
679		sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
680	} else if (p != td->td_proc) {
681		sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
682	} else {
683		error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr));
684		if (error)
685			return (error);
686		for (i = 0; i < pstr.ps_nargvstr; i++) {
687			sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
688			sbuf_printf(sb, "%c", '\0');
689		}
690	}
691
692	return (0);
693}
694
695/*
696 * Filler function for proc/pid/exe
697 */
698static int
699linprocfs_doprocexe(PFS_FILL_ARGS)
700{
701	char *fullpath = "unknown";
702	char *freepath = NULL;
703
704	vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath);
705	sbuf_printf(sb, "%s", fullpath);
706	if (freepath)
707		free(freepath, M_TEMP);
708	return (0);
709}
710
711/*
712 * Filler function for proc/net/dev
713 */
714static int
715linprocfs_donetdev(PFS_FILL_ARGS)
716{
717	char ifname[16]; /* XXX LINUX_IFNAMSIZ */
718	struct ifnet *ifp;
719
720	sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
721	    "Inter-", "   Receive", "  Transmit", " face",
722	    "bytes    packets errs drop fifo frame compressed",
723	    "bytes    packets errs drop fifo frame compressed");
724
725	TAILQ_FOREACH(ifp, &ifnet, if_link) {
726		linux_ifname(ifp, ifname, sizeof ifname);
727			sbuf_printf(sb, "%6.6s:", ifname);
728		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
729		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
730		sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
731		    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
732	}
733
734	return (0);
735}
736
737#if 0
738extern struct cdevsw *cdevsw[];
739
740/*
741 * Filler function for proc/devices
742 */
743static int
744linprocfs_dodevices(PFS_FILL_ARGS)
745{
746	int i;
747
748	sbuf_printf(sb, "Character devices:\n");
749
750	for (i = 0; i < NUMCDEVSW; i++)
751		if (cdevsw[i] != NULL)
752			sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
753
754	sbuf_printf(sb, "\nBlock devices:\n");
755
756	return (0);
757}
758#endif
759
760/*
761 * Filler function for proc/cmdline
762 */
763static int
764linprocfs_docmdline(PFS_FILL_ARGS)
765{
766	sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
767	sbuf_printf(sb, " ro root=302\n");
768	return (0);
769}
770
771#if 0
772/*
773 * Filler function for proc/modules
774 */
775static int
776linprocfs_domodules(PFS_FILL_ARGS)
777{
778	struct linker_file *lf;
779
780	TAILQ_FOREACH(lf, &linker_files, link) {
781		sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
782		    (unsigned long)lf->size, lf->refs);
783	}
784	return (0);
785}
786#endif
787
788/*
789 * Constructor
790 */
791static int
792linprocfs_init(PFS_INIT_ARGS)
793{
794	struct pfs_node *root;
795	struct pfs_node *dir;
796
797	root = pi->pi_root;
798
799#define PFS_CREATE_FILE(name) \
800	pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
801	PFS_CREATE_FILE(cmdline);
802	PFS_CREATE_FILE(cpuinfo);
803#if 0
804	PFS_CREATE_FILE(devices);
805#endif
806	PFS_CREATE_FILE(loadavg);
807	PFS_CREATE_FILE(meminfo);
808#if 0
809	PFS_CREATE_FILE(modules);
810#endif
811	PFS_CREATE_FILE(mtab);
812	PFS_CREATE_FILE(stat);
813	PFS_CREATE_FILE(uptime);
814	PFS_CREATE_FILE(version);
815#undef PFS_CREATE_FILE
816	pfs_create_link(root, "self", &linprocfs_doselflink,
817	    NULL, NULL, 0);
818
819	dir = pfs_create_dir(root, "net", NULL, NULL, 0);
820	pfs_create_file(dir, "dev", &linprocfs_donetdev,
821	    NULL, NULL, PFS_RD);
822
823	dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
824	pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
825	    NULL, NULL, PFS_RD);
826	pfs_create_link(dir, "exe", &linprocfs_doprocexe,
827	    NULL, NULL, 0);
828#if 0
829	pfs_create_file(dir, "mem", &procfs_doprocmem,
830	    &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
831#endif
832	pfs_create_file(dir, "stat", &linprocfs_doprocstat,
833	    NULL, NULL, PFS_RD);
834	pfs_create_file(dir, "status", &linprocfs_doprocstatus,
835	    NULL, NULL, PFS_RD);
836
837	return (0);
838}
839
840/*
841 * Destructor
842 */
843static int
844linprocfs_uninit(PFS_INIT_ARGS)
845{
846
847	/* nothing to do, pseudofs will GC */
848	return (0);
849}
850
851PSEUDOFS(linprocfs, 1);
852MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
853MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
854