Deleted Added
full compact
linprocfs.c (105663) linprocfs.c (108172)
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 105663 2002-10-21 22:27:36Z julian $
41 * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 108172 2002-12-22 05:35:03Z hsu $
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/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>
84extern 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 */
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 const char *lep;
342 char *dlep, *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, &dlep, &flep) == -1)
350 lep = linux_emul_path;
351 else
352 lep = dlep;
353 lep_len = strlen(lep);
354
355 mtx_lock(&mountlist_mtx);
356 error = 0;
357 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
358 error = VFS_STATFS(mp, &mp->mnt_stat, td);
359 if (error)
360 break;
361
362 /* determine device name */
363 mntfrom = mp->mnt_stat.f_mntfromname;
364
365 /* determine mount point */
366 mntto = mp->mnt_stat.f_mntonname;
367 if (strncmp(mntto, lep, lep_len) == 0 &&
368 mntto[lep_len] == '/')
369 mntto += lep_len;
370
371 /* determine fs type */
372 fstype = mp->mnt_stat.f_fstypename;
373 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
374 mntfrom = fstype = "proc";
375 else if (strcmp(fstype, "procfs") == 0)
376 continue;
377
378 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
379 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
380#define ADD_OPTION(opt, name) \
381 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
382 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
383 ADD_OPTION(MNT_NOEXEC, "noexec");
384 ADD_OPTION(MNT_NOSUID, "nosuid");
385 ADD_OPTION(MNT_NODEV, "nodev");
386 ADD_OPTION(MNT_UNION, "union");
387 ADD_OPTION(MNT_ASYNC, "async");
388 ADD_OPTION(MNT_SUIDDIR, "suiddir");
389 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
390 ADD_OPTION(MNT_NOATIME, "noatime");
391#undef ADD_OPTION
392 /* a real Linux mtab will also show NFS options */
393 sbuf_printf(sb, " 0 0\n");
394 }
395 mtx_unlock(&mountlist_mtx);
396 if (flep != NULL)
397 free(flep, M_TEMP);
398 return (error);
399}
400
401/*
402 * Filler function for proc/stat
403 */
404static int
405linprocfs_dostat(PFS_FILL_ARGS)
406{
407 sbuf_printf(sb,
408 "cpu %ld %ld %ld %ld\n"
409 "disk 0 0 0 0\n"
410 "page %u %u\n"
411 "swap %u %u\n"
412 "intr %u\n"
413 "ctxt %u\n"
414 "btime %lld\n",
415 T2J(cp_time[CP_USER]),
416 T2J(cp_time[CP_NICE]),
417 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
418 T2J(cp_time[CP_IDLE]),
419 cnt.v_vnodepgsin,
420 cnt.v_vnodepgsout,
421 cnt.v_swappgsin,
422 cnt.v_swappgsout,
423 cnt.v_intr,
424 cnt.v_swtch,
425 (quad_t)boottime.tv_sec);
426 return (0);
427}
428
429/*
430 * Filler function for proc/uptime
431 */
432static int
433linprocfs_douptime(PFS_FILL_ARGS)
434{
435 struct timeval tv;
436
437 getmicrouptime(&tv);
438 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
439 (quad_t)tv.tv_sec, tv.tv_usec / 10000,
440 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
441 return (0);
442}
443
444/*
445 * Filler function for proc/version
446 */
447static int
448linprocfs_doversion(PFS_FILL_ARGS)
449{
450 char osname[LINUX_MAX_UTSNAME];
451 char osrelease[LINUX_MAX_UTSNAME];
452
453 linux_get_osname(td->td_proc, osname);
454 linux_get_osrelease(td->td_proc, osrelease);
455
456 sbuf_printf(sb,
457 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
458 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
459 return (0);
460}
461
462/*
463 * Filler function for proc/loadavg
464 */
465static int
466linprocfs_doloadavg(PFS_FILL_ARGS)
467{
468 sbuf_printf(sb,
469 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
470 (int)(averunnable.ldavg[0] / averunnable.fscale),
471 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
472 (int)(averunnable.ldavg[1] / averunnable.fscale),
473 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
474 (int)(averunnable.ldavg[2] / averunnable.fscale),
475 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
476 1, /* number of running tasks */
477 nprocs, /* number of tasks */
478 lastpid /* the last pid */
479 );
480
481 return (0);
482}
483
484/*
485 * Filler function for proc/pid/stat
486 */
487static int
488linprocfs_doprocstat(PFS_FILL_ARGS)
489{
490 struct kinfo_proc kp;
491
492 PROC_LOCK(p);
493 fill_kinfo_proc(p, &kp);
494 sbuf_printf(sb, "%d", p->p_pid);
495#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
496 PS_ADD("comm", "(%s)", p->p_comm);
497 PS_ADD("statr", "%c", '0'); /* XXX */
498 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
499 PS_ADD("pgrp", "%d", p->p_pgid);
500 PS_ADD("session", "%d", p->p_session->s_sid);
501 PROC_UNLOCK(p);
502 PS_ADD("tty", "%d", 0); /* XXX */
503 PS_ADD("tpgid", "%d", 0); /* XXX */
504 PS_ADD("flags", "%u", 0); /* XXX */
505 PS_ADD("minflt", "%u", 0); /* XXX */
506 PS_ADD("cminflt", "%u", 0); /* XXX */
507 PS_ADD("majflt", "%u", 0); /* XXX */
508 PS_ADD("cminflt", "%u", 0); /* XXX */
509 PS_ADD("utime", "%d", 0); /* XXX */
510 PS_ADD("stime", "%d", 0); /* XXX */
511 PS_ADD("cutime", "%d", 0); /* XXX */
512 PS_ADD("cstime", "%d", 0); /* XXX */
513 PS_ADD("counter", "%d", 0); /* XXX */
514 PS_ADD("priority", "%d", 0); /* XXX */
515 PS_ADD("timeout", "%u", 0); /* XXX */
516 PS_ADD("itrealvalue", "%u", 0); /* XXX */
517 PS_ADD("starttime", "%d", 0); /* XXX */
518 PS_ADD("vsize", "%u", kp.ki_size);
519 PS_ADD("rss", "%u", P2K(kp.ki_rssize));
520 PS_ADD("rlim", "%u", 0); /* XXX */
521 PS_ADD("startcode", "%u", (unsigned)0);
522 PS_ADD("endcode", "%u", 0); /* XXX */
523 PS_ADD("startstack", "%u", 0); /* XXX */
524 PS_ADD("esp", "%u", 0); /* XXX */
525 PS_ADD("eip", "%u", 0); /* XXX */
526 PS_ADD("signal", "%d", 0); /* XXX */
527 PS_ADD("blocked", "%d", 0); /* XXX */
528 PS_ADD("sigignore", "%d", 0); /* XXX */
529 PS_ADD("sigcatch", "%d", 0); /* XXX */
530 PS_ADD("wchan", "%u", 0); /* XXX */
531 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */
532 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */
533 PS_ADD("exitsignal", "%d", 0); /* XXX */
534 PS_ADD("processor", "%d", 0); /* XXX */
535#undef PS_ADD
536 sbuf_putc(sb, '\n');
537
538 return (0);
539}
540
541/*
542 * Filler function for proc/pid/status
543 */
544static int
545linprocfs_doprocstatus(PFS_FILL_ARGS)
546{
547 struct kinfo_proc kp;
548 char *state;
549 segsz_t lsize;
550 struct thread *td2;
551 int i;
552
553 mtx_lock_spin(&sched_lock);
554 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
555
556 if (P_SHOULDSTOP(p)) {
557 state = "T (stopped)";
558 } else {
559 switch(p->p_state) {
560 case PRS_NEW:
561 state = "I (idle)";
562 break;
563 case PRS_NORMAL:
564 if (p->p_flag & P_WEXIT) {
565 state = "X (exiting)";
566 break;
567 }
568 switch(td2->td_state) {
569 case TDS_INHIBITED:
570 state = "S (sleeping)";
571 break;
572 case TDS_RUNQ:
573 case TDS_RUNNING:
574 state = "R (running)";
575 break;
576 default:
577 state = "? (unknown)";
578 break;
579 }
580 break;
581 case PRS_ZOMBIE:
582 state = "Z (zombie)";
583 break;
584 default:
585 state = "? (unknown)";
586 break;
587 }
588 }
589 mtx_unlock_spin(&sched_lock);
590
591 PROC_LOCK(p);
592 fill_kinfo_proc(p, &kp);
593 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
594 sbuf_printf(sb, "State:\t%s\n", state);
595
596 /*
597 * Credentials
598 */
599 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
600 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
601 p->p_pptr->p_pid : 0);
602 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
603 p->p_ucred->cr_uid,
604 p->p_ucred->cr_svuid,
605 /* FreeBSD doesn't have fsuid */
606 p->p_ucred->cr_uid);
607 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
608 p->p_ucred->cr_gid,
609 p->p_ucred->cr_svgid,
610 /* FreeBSD doesn't have fsgid */
611 p->p_ucred->cr_gid);
612 sbuf_cat(sb, "Groups:\t");
613 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
614 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
615 PROC_UNLOCK(p);
616 sbuf_putc(sb, '\n');
617
618 /*
619 * Memory
620 *
621 * While our approximation of VmLib may not be accurate (I
622 * don't know of a simple way to verify it, and I'm not sure
623 * it has much meaning anyway), I believe it's good enough.
624 *
625 * The same code that could (I think) accurately compute VmLib
626 * could also compute VmLck, but I don't really care enough to
627 * implement it. Submissions are welcome.
628 */
629 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size));
630 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
631 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize));
632 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize));
633 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize));
634 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize));
635 lsize = B2P(kp.ki_size) - kp.ki_dsize -
636 kp.ki_ssize - kp.ki_tsize - 1;
637 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize));
638
639 /*
640 * Signal masks
641 *
642 * We support up to 128 signals, while Linux supports 32,
643 * but we only define 32 (the same 32 as Linux, to boot), so
644 * just show the lower 32 bits of each mask. XXX hack.
645 *
646 * NB: on certain platforms (Sparc at least) Linux actually
647 * supports 64 signals, but this code is a long way from
648 * running on anything but i386, so ignore that for now.
649 */
650 PROC_LOCK(p);
651 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
652 /*
653 * I can't seem to find out where the signal mask is in
654 * relation to struct proc, so SigBlk is left unimplemented.
655 */
656 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
657 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
658 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
659 PROC_UNLOCK(p);
660
661 /*
662 * Linux also prints the capability masks, but we don't have
663 * capabilities yet, and when we do get them they're likely to
664 * be meaningless to Linux programs, so we lie. XXX
665 */
666 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
667 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
668 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
669
670 return (0);
671}
672
673/*
674 * Filler function for proc/pid/cmdline
675 */
676static int
677linprocfs_doproccmdline(PFS_FILL_ARGS)
678{
679 struct ps_strings pstr;
680 int error, i;
681
682 /*
683 * If we are using the ps/cmdline caching, use that. Otherwise
684 * revert back to the old way which only implements full cmdline
685 * for the currept process and just p->p_comm for all other
686 * processes.
687 * Note that if the argv is no longer available, we deliberately
688 * don't fall back on p->p_comm or return an error: the authentic
689 * Linux behaviour is to return zero-length in this case.
690 */
691
692 PROC_LOCK(p);
693 if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
694 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
695 PROC_UNLOCK(p);
696 } else if (p != td->td_proc) {
697 PROC_UNLOCK(p);
698 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
699 } else {
700 PROC_UNLOCK(p);
701 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
702 sizeof(pstr));
703 if (error)
704 return (error);
705 for (i = 0; i < pstr.ps_nargvstr; i++) {
706 sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
707 sbuf_printf(sb, "%c", '\0');
708 }
709 }
710
711 return (0);
712}
713
714/*
715 * Filler function for proc/net/dev
716 */
717static int
718linprocfs_donetdev(PFS_FILL_ARGS)
719{
720 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
721 struct ifnet *ifp;
722
723 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
724 "Inter-", " Receive", " Transmit", " face",
725 "bytes packets errs drop fifo frame compressed",
726 "bytes packets errs drop fifo frame compressed");
727
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/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>
84extern 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 */
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 const char *lep;
342 char *dlep, *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, &dlep, &flep) == -1)
350 lep = linux_emul_path;
351 else
352 lep = dlep;
353 lep_len = strlen(lep);
354
355 mtx_lock(&mountlist_mtx);
356 error = 0;
357 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
358 error = VFS_STATFS(mp, &mp->mnt_stat, td);
359 if (error)
360 break;
361
362 /* determine device name */
363 mntfrom = mp->mnt_stat.f_mntfromname;
364
365 /* determine mount point */
366 mntto = mp->mnt_stat.f_mntonname;
367 if (strncmp(mntto, lep, lep_len) == 0 &&
368 mntto[lep_len] == '/')
369 mntto += lep_len;
370
371 /* determine fs type */
372 fstype = mp->mnt_stat.f_fstypename;
373 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
374 mntfrom = fstype = "proc";
375 else if (strcmp(fstype, "procfs") == 0)
376 continue;
377
378 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
379 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
380#define ADD_OPTION(opt, name) \
381 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
382 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
383 ADD_OPTION(MNT_NOEXEC, "noexec");
384 ADD_OPTION(MNT_NOSUID, "nosuid");
385 ADD_OPTION(MNT_NODEV, "nodev");
386 ADD_OPTION(MNT_UNION, "union");
387 ADD_OPTION(MNT_ASYNC, "async");
388 ADD_OPTION(MNT_SUIDDIR, "suiddir");
389 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
390 ADD_OPTION(MNT_NOATIME, "noatime");
391#undef ADD_OPTION
392 /* a real Linux mtab will also show NFS options */
393 sbuf_printf(sb, " 0 0\n");
394 }
395 mtx_unlock(&mountlist_mtx);
396 if (flep != NULL)
397 free(flep, M_TEMP);
398 return (error);
399}
400
401/*
402 * Filler function for proc/stat
403 */
404static int
405linprocfs_dostat(PFS_FILL_ARGS)
406{
407 sbuf_printf(sb,
408 "cpu %ld %ld %ld %ld\n"
409 "disk 0 0 0 0\n"
410 "page %u %u\n"
411 "swap %u %u\n"
412 "intr %u\n"
413 "ctxt %u\n"
414 "btime %lld\n",
415 T2J(cp_time[CP_USER]),
416 T2J(cp_time[CP_NICE]),
417 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
418 T2J(cp_time[CP_IDLE]),
419 cnt.v_vnodepgsin,
420 cnt.v_vnodepgsout,
421 cnt.v_swappgsin,
422 cnt.v_swappgsout,
423 cnt.v_intr,
424 cnt.v_swtch,
425 (quad_t)boottime.tv_sec);
426 return (0);
427}
428
429/*
430 * Filler function for proc/uptime
431 */
432static int
433linprocfs_douptime(PFS_FILL_ARGS)
434{
435 struct timeval tv;
436
437 getmicrouptime(&tv);
438 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
439 (quad_t)tv.tv_sec, tv.tv_usec / 10000,
440 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
441 return (0);
442}
443
444/*
445 * Filler function for proc/version
446 */
447static int
448linprocfs_doversion(PFS_FILL_ARGS)
449{
450 char osname[LINUX_MAX_UTSNAME];
451 char osrelease[LINUX_MAX_UTSNAME];
452
453 linux_get_osname(td->td_proc, osname);
454 linux_get_osrelease(td->td_proc, osrelease);
455
456 sbuf_printf(sb,
457 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
458 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
459 return (0);
460}
461
462/*
463 * Filler function for proc/loadavg
464 */
465static int
466linprocfs_doloadavg(PFS_FILL_ARGS)
467{
468 sbuf_printf(sb,
469 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
470 (int)(averunnable.ldavg[0] / averunnable.fscale),
471 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
472 (int)(averunnable.ldavg[1] / averunnable.fscale),
473 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
474 (int)(averunnable.ldavg[2] / averunnable.fscale),
475 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
476 1, /* number of running tasks */
477 nprocs, /* number of tasks */
478 lastpid /* the last pid */
479 );
480
481 return (0);
482}
483
484/*
485 * Filler function for proc/pid/stat
486 */
487static int
488linprocfs_doprocstat(PFS_FILL_ARGS)
489{
490 struct kinfo_proc kp;
491
492 PROC_LOCK(p);
493 fill_kinfo_proc(p, &kp);
494 sbuf_printf(sb, "%d", p->p_pid);
495#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
496 PS_ADD("comm", "(%s)", p->p_comm);
497 PS_ADD("statr", "%c", '0'); /* XXX */
498 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
499 PS_ADD("pgrp", "%d", p->p_pgid);
500 PS_ADD("session", "%d", p->p_session->s_sid);
501 PROC_UNLOCK(p);
502 PS_ADD("tty", "%d", 0); /* XXX */
503 PS_ADD("tpgid", "%d", 0); /* XXX */
504 PS_ADD("flags", "%u", 0); /* XXX */
505 PS_ADD("minflt", "%u", 0); /* XXX */
506 PS_ADD("cminflt", "%u", 0); /* XXX */
507 PS_ADD("majflt", "%u", 0); /* XXX */
508 PS_ADD("cminflt", "%u", 0); /* XXX */
509 PS_ADD("utime", "%d", 0); /* XXX */
510 PS_ADD("stime", "%d", 0); /* XXX */
511 PS_ADD("cutime", "%d", 0); /* XXX */
512 PS_ADD("cstime", "%d", 0); /* XXX */
513 PS_ADD("counter", "%d", 0); /* XXX */
514 PS_ADD("priority", "%d", 0); /* XXX */
515 PS_ADD("timeout", "%u", 0); /* XXX */
516 PS_ADD("itrealvalue", "%u", 0); /* XXX */
517 PS_ADD("starttime", "%d", 0); /* XXX */
518 PS_ADD("vsize", "%u", kp.ki_size);
519 PS_ADD("rss", "%u", P2K(kp.ki_rssize));
520 PS_ADD("rlim", "%u", 0); /* XXX */
521 PS_ADD("startcode", "%u", (unsigned)0);
522 PS_ADD("endcode", "%u", 0); /* XXX */
523 PS_ADD("startstack", "%u", 0); /* XXX */
524 PS_ADD("esp", "%u", 0); /* XXX */
525 PS_ADD("eip", "%u", 0); /* XXX */
526 PS_ADD("signal", "%d", 0); /* XXX */
527 PS_ADD("blocked", "%d", 0); /* XXX */
528 PS_ADD("sigignore", "%d", 0); /* XXX */
529 PS_ADD("sigcatch", "%d", 0); /* XXX */
530 PS_ADD("wchan", "%u", 0); /* XXX */
531 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */
532 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */
533 PS_ADD("exitsignal", "%d", 0); /* XXX */
534 PS_ADD("processor", "%d", 0); /* XXX */
535#undef PS_ADD
536 sbuf_putc(sb, '\n');
537
538 return (0);
539}
540
541/*
542 * Filler function for proc/pid/status
543 */
544static int
545linprocfs_doprocstatus(PFS_FILL_ARGS)
546{
547 struct kinfo_proc kp;
548 char *state;
549 segsz_t lsize;
550 struct thread *td2;
551 int i;
552
553 mtx_lock_spin(&sched_lock);
554 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
555
556 if (P_SHOULDSTOP(p)) {
557 state = "T (stopped)";
558 } else {
559 switch(p->p_state) {
560 case PRS_NEW:
561 state = "I (idle)";
562 break;
563 case PRS_NORMAL:
564 if (p->p_flag & P_WEXIT) {
565 state = "X (exiting)";
566 break;
567 }
568 switch(td2->td_state) {
569 case TDS_INHIBITED:
570 state = "S (sleeping)";
571 break;
572 case TDS_RUNQ:
573 case TDS_RUNNING:
574 state = "R (running)";
575 break;
576 default:
577 state = "? (unknown)";
578 break;
579 }
580 break;
581 case PRS_ZOMBIE:
582 state = "Z (zombie)";
583 break;
584 default:
585 state = "? (unknown)";
586 break;
587 }
588 }
589 mtx_unlock_spin(&sched_lock);
590
591 PROC_LOCK(p);
592 fill_kinfo_proc(p, &kp);
593 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
594 sbuf_printf(sb, "State:\t%s\n", state);
595
596 /*
597 * Credentials
598 */
599 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
600 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
601 p->p_pptr->p_pid : 0);
602 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
603 p->p_ucred->cr_uid,
604 p->p_ucred->cr_svuid,
605 /* FreeBSD doesn't have fsuid */
606 p->p_ucred->cr_uid);
607 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
608 p->p_ucred->cr_gid,
609 p->p_ucred->cr_svgid,
610 /* FreeBSD doesn't have fsgid */
611 p->p_ucred->cr_gid);
612 sbuf_cat(sb, "Groups:\t");
613 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
614 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
615 PROC_UNLOCK(p);
616 sbuf_putc(sb, '\n');
617
618 /*
619 * Memory
620 *
621 * While our approximation of VmLib may not be accurate (I
622 * don't know of a simple way to verify it, and I'm not sure
623 * it has much meaning anyway), I believe it's good enough.
624 *
625 * The same code that could (I think) accurately compute VmLib
626 * could also compute VmLck, but I don't really care enough to
627 * implement it. Submissions are welcome.
628 */
629 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size));
630 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
631 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize));
632 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize));
633 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize));
634 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize));
635 lsize = B2P(kp.ki_size) - kp.ki_dsize -
636 kp.ki_ssize - kp.ki_tsize - 1;
637 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize));
638
639 /*
640 * Signal masks
641 *
642 * We support up to 128 signals, while Linux supports 32,
643 * but we only define 32 (the same 32 as Linux, to boot), so
644 * just show the lower 32 bits of each mask. XXX hack.
645 *
646 * NB: on certain platforms (Sparc at least) Linux actually
647 * supports 64 signals, but this code is a long way from
648 * running on anything but i386, so ignore that for now.
649 */
650 PROC_LOCK(p);
651 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
652 /*
653 * I can't seem to find out where the signal mask is in
654 * relation to struct proc, so SigBlk is left unimplemented.
655 */
656 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
657 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
658 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
659 PROC_UNLOCK(p);
660
661 /*
662 * Linux also prints the capability masks, but we don't have
663 * capabilities yet, and when we do get them they're likely to
664 * be meaningless to Linux programs, so we lie. XXX
665 */
666 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
667 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
668 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
669
670 return (0);
671}
672
673/*
674 * Filler function for proc/pid/cmdline
675 */
676static int
677linprocfs_doproccmdline(PFS_FILL_ARGS)
678{
679 struct ps_strings pstr;
680 int error, i;
681
682 /*
683 * If we are using the ps/cmdline caching, use that. Otherwise
684 * revert back to the old way which only implements full cmdline
685 * for the currept process and just p->p_comm for all other
686 * processes.
687 * Note that if the argv is no longer available, we deliberately
688 * don't fall back on p->p_comm or return an error: the authentic
689 * Linux behaviour is to return zero-length in this case.
690 */
691
692 PROC_LOCK(p);
693 if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
694 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
695 PROC_UNLOCK(p);
696 } else if (p != td->td_proc) {
697 PROC_UNLOCK(p);
698 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
699 } else {
700 PROC_UNLOCK(p);
701 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
702 sizeof(pstr));
703 if (error)
704 return (error);
705 for (i = 0; i < pstr.ps_nargvstr; i++) {
706 sbuf_copyin(sb, pstr.ps_argvstr[i], 0);
707 sbuf_printf(sb, "%c", '\0');
708 }
709 }
710
711 return (0);
712}
713
714/*
715 * Filler function for proc/net/dev
716 */
717static int
718linprocfs_donetdev(PFS_FILL_ARGS)
719{
720 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
721 struct ifnet *ifp;
722
723 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
724 "Inter-", " Receive", " Transmit", " face",
725 "bytes packets errs drop fifo frame compressed",
726 "bytes packets errs drop fifo frame compressed");
727
728 IFNET_RLOCK();
728 TAILQ_FOREACH(ifp, &ifnet, if_link) {
729 linux_ifname(ifp, ifname, sizeof ifname);
730 sbuf_printf(sb, "%6.6s:", ifname);
731 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
732 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
733 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
734 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
735 }
729 TAILQ_FOREACH(ifp, &ifnet, if_link) {
730 linux_ifname(ifp, ifname, sizeof ifname);
731 sbuf_printf(sb, "%6.6s:", ifname);
732 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
733 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
734 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
735 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
736 }
737 IFNET_RUNLOCK();
736
737 return (0);
738}
739
740#if 0
741extern struct cdevsw *cdevsw[];
742
743/*
744 * Filler function for proc/devices
745 */
746static int
747linprocfs_dodevices(PFS_FILL_ARGS)
748{
749 int i;
750
751 sbuf_printf(sb, "Character devices:\n");
752
753 for (i = 0; i < NUMCDEVSW; i++)
754 if (cdevsw[i] != NULL)
755 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
756
757 sbuf_printf(sb, "\nBlock devices:\n");
758
759 return (0);
760}
761#endif
762
763/*
764 * Filler function for proc/cmdline
765 */
766static int
767linprocfs_docmdline(PFS_FILL_ARGS)
768{
769 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
770 sbuf_printf(sb, " ro root=302\n");
771 return (0);
772}
773
774#if 0
775/*
776 * Filler function for proc/modules
777 */
778static int
779linprocfs_domodules(PFS_FILL_ARGS)
780{
781 struct linker_file *lf;
782
783 TAILQ_FOREACH(lf, &linker_files, link) {
784 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
785 (unsigned long)lf->size, lf->refs);
786 }
787 return (0);
788}
789#endif
790
791/*
792 * Constructor
793 */
794static int
795linprocfs_init(PFS_INIT_ARGS)
796{
797 struct pfs_node *root;
798 struct pfs_node *dir;
799
800 root = pi->pi_root;
801
802#define PFS_CREATE_FILE(name) \
803 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
804 PFS_CREATE_FILE(cmdline);
805 PFS_CREATE_FILE(cpuinfo);
806#if 0
807 PFS_CREATE_FILE(devices);
808#endif
809 PFS_CREATE_FILE(loadavg);
810 PFS_CREATE_FILE(meminfo);
811#if 0
812 PFS_CREATE_FILE(modules);
813#endif
814 PFS_CREATE_FILE(mtab);
815 PFS_CREATE_FILE(stat);
816 PFS_CREATE_FILE(uptime);
817 PFS_CREATE_FILE(version);
818#undef PFS_CREATE_FILE
819 pfs_create_link(root, "self", &procfs_docurproc,
820 NULL, NULL, 0);
821
822 dir = pfs_create_dir(root, "net", NULL, NULL, 0);
823 pfs_create_file(dir, "dev", &linprocfs_donetdev,
824 NULL, NULL, PFS_RD);
825
826 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
827 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
828 NULL, NULL, PFS_RD);
829 pfs_create_link(dir, "exe", &procfs_doprocfile,
830 NULL, &procfs_notsystem, 0);
831 pfs_create_file(dir, "mem", &procfs_doprocmem,
832 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
833 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
834 NULL, NULL, PFS_RD);
835 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
836 NULL, NULL, PFS_RD);
837
838 return (0);
839}
840
841/*
842 * Destructor
843 */
844static int
845linprocfs_uninit(PFS_INIT_ARGS)
846{
847
848 /* nothing to do, pseudofs will GC */
849 return (0);
850}
851
852PSEUDOFS(linprocfs, 1);
853MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
854MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
738
739 return (0);
740}
741
742#if 0
743extern struct cdevsw *cdevsw[];
744
745/*
746 * Filler function for proc/devices
747 */
748static int
749linprocfs_dodevices(PFS_FILL_ARGS)
750{
751 int i;
752
753 sbuf_printf(sb, "Character devices:\n");
754
755 for (i = 0; i < NUMCDEVSW; i++)
756 if (cdevsw[i] != NULL)
757 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
758
759 sbuf_printf(sb, "\nBlock devices:\n");
760
761 return (0);
762}
763#endif
764
765/*
766 * Filler function for proc/cmdline
767 */
768static int
769linprocfs_docmdline(PFS_FILL_ARGS)
770{
771 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
772 sbuf_printf(sb, " ro root=302\n");
773 return (0);
774}
775
776#if 0
777/*
778 * Filler function for proc/modules
779 */
780static int
781linprocfs_domodules(PFS_FILL_ARGS)
782{
783 struct linker_file *lf;
784
785 TAILQ_FOREACH(lf, &linker_files, link) {
786 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
787 (unsigned long)lf->size, lf->refs);
788 }
789 return (0);
790}
791#endif
792
793/*
794 * Constructor
795 */
796static int
797linprocfs_init(PFS_INIT_ARGS)
798{
799 struct pfs_node *root;
800 struct pfs_node *dir;
801
802 root = pi->pi_root;
803
804#define PFS_CREATE_FILE(name) \
805 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD)
806 PFS_CREATE_FILE(cmdline);
807 PFS_CREATE_FILE(cpuinfo);
808#if 0
809 PFS_CREATE_FILE(devices);
810#endif
811 PFS_CREATE_FILE(loadavg);
812 PFS_CREATE_FILE(meminfo);
813#if 0
814 PFS_CREATE_FILE(modules);
815#endif
816 PFS_CREATE_FILE(mtab);
817 PFS_CREATE_FILE(stat);
818 PFS_CREATE_FILE(uptime);
819 PFS_CREATE_FILE(version);
820#undef PFS_CREATE_FILE
821 pfs_create_link(root, "self", &procfs_docurproc,
822 NULL, NULL, 0);
823
824 dir = pfs_create_dir(root, "net", NULL, NULL, 0);
825 pfs_create_file(dir, "dev", &linprocfs_donetdev,
826 NULL, NULL, PFS_RD);
827
828 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
829 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
830 NULL, NULL, PFS_RD);
831 pfs_create_link(dir, "exe", &procfs_doprocfile,
832 NULL, &procfs_notsystem, 0);
833 pfs_create_file(dir, "mem", &procfs_doprocmem,
834 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
835 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
836 NULL, NULL, PFS_RD);
837 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
838 NULL, NULL, PFS_RD);
839
840 return (0);
841}
842
843/*
844 * Destructor
845 */
846static int
847linprocfs_uninit(PFS_INIT_ARGS)
848{
849
850 /* nothing to do, pseudofs will GC */
851 return (0);
852}
853
854PSEUDOFS(linprocfs, 1);
855MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
856MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);