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