2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
42 #include "opt_compat.h"
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
47 #include <sys/param.h>
48 #include <sys/queue.h>
49 #include <sys/blist.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
55 #include <sys/kernel.h>
56 #include <sys/limits.h>
57 #include <sys/linker.h>
59 #include <sys/malloc.h>
61 #include <sys/mutex.h>
62 #include <sys/namei.h>
64 #include <sys/ptrace.h>
65 #include <sys/resourcevar.h>
69 #include <sys/socket.h>
70 #include <sys/syscallsubr.h>
71 #include <sys/sysctl.h>
72 #include <sys/systm.h>
77 #include <sys/vmmeter.h>
78 #include <sys/vnode.h>
82 #include <net/if_var.h>
86 #include <vm/vm_extern.h>
88 #include <vm/vm_map.h>
89 #include <vm/vm_param.h>
90 #include <vm/vm_object.h>
91 #include <vm/swap_pager.h>
93 #include <machine/clock.h>
95 #include <geom/geom.h>
96 #include <geom/geom_int.h>
98 #if defined(__i386__) || defined(__amd64__)
99 #include <machine/cputypes.h>
100 #include <machine/md_var.h>
101 #endif /* __i386__ || __amd64__ */
103 #ifdef COMPAT_FREEBSD32
104 #include <compat/freebsd32/freebsd32_util.h>
107 #include <compat/linux/linux_ioctl.h>
108 #include <compat/linux/linux_mib.h>
109 #include <compat/linux/linux_misc.h>
110 #include <compat/linux/linux_util.h>
111 #include <fs/pseudofs/pseudofs.h>
112 #include <fs/procfs/procfs.h>
115 * Various conversion macros
117 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
118 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
119 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
120 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
121 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
122 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
123 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
124 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
127 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
129 * The linux procfs state field displays one of the characters RSDZTW to
130 * denote running, sleeping in an interruptible wait, waiting in an
131 * uninterruptible disk sleep, a zombie process, process is being traced
132 * or stopped, or process is paging respectively.
134 * Our struct kinfo_proc contains the variable ki_stat which contains a
135 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
137 * This character array is used with ki_stati-1 as an index and tries to
138 * map our states to suitable linux states.
140 static char linux_state[] = "RRSTZDD";
143 * Filler function for proc/meminfo
146 linprocfs_domeminfo(PFS_FILL_ARGS)
148 unsigned long memtotal; /* total memory in bytes */
149 unsigned long memused; /* used memory in bytes */
150 unsigned long memfree; /* free memory in bytes */
151 unsigned long memshared; /* shared memory ??? */
152 unsigned long buffers, cached; /* buffer / cache memory ??? */
153 unsigned long long swaptotal; /* total swap space in bytes */
154 unsigned long long swapused; /* used swap space in bytes */
155 unsigned long long swapfree; /* free swap space in bytes */
159 memtotal = physmem * PAGE_SIZE;
161 * The correct thing here would be:
163 memfree = vm_cnt.v_free_count * PAGE_SIZE;
164 memused = memtotal - memfree;
166 * but it might mislead linux binaries into thinking there
167 * is very little memory left, so we cheat and tell them that
168 * all memory that isn't wired down is free.
170 memused = vm_cnt.v_wire_count * PAGE_SIZE;
171 memfree = memtotal - memused;
172 swap_pager_status(&i, &j);
173 swaptotal = (unsigned long long)i * PAGE_SIZE;
174 swapused = (unsigned long long)j * PAGE_SIZE;
175 swapfree = swaptotal - swapused;
177 mtx_lock(&vm_object_list_mtx);
178 TAILQ_FOREACH(object, &vm_object_list, object_list)
179 if (object->shadow_count > 1)
180 memshared += object->resident_page_count;
181 mtx_unlock(&vm_object_list_mtx);
182 memshared *= PAGE_SIZE;
184 * We'd love to be able to write:
188 * but bufspace is internal to vfs_bio.c and we don't feel
189 * like unstaticizing it just for linprocfs's sake.
192 cached = vm_cnt.v_cache_count * PAGE_SIZE;
195 " total: used: free: shared: buffers: cached:\n"
196 "Mem: %lu %lu %lu %lu %lu %lu\n"
197 "Swap: %llu %llu %llu\n"
198 "MemTotal: %9lu kB\n"
200 "MemShared:%9lu kB\n"
203 "SwapTotal:%9llu kB\n"
204 "SwapFree: %9llu kB\n",
205 memtotal, memused, memfree, memshared, buffers, cached,
206 swaptotal, swapused, swapfree,
207 B2K(memtotal), B2K(memfree),
208 B2K(memshared), B2K(buffers), B2K(cached),
209 B2K(swaptotal), B2K(swapfree));
214 #if defined(__i386__) || defined(__amd64__)
216 * Filler function for proc/cpuinfo (i386 & amd64 version)
219 linprocfs_docpuinfo(PFS_FILL_ARGS)
225 int class, fqmhz, fqkhz;
229 * We default the flags to include all non-conflicting flags,
230 * and the Intel versions of conflicting flags.
232 static char *flags[] = {
233 "fpu", "vme", "de", "pse", "tsc",
234 "msr", "pae", "mce", "cx8", "apic",
235 "sep", "sep", "mtrr", "pge", "mca",
236 "cmov", "pat", "pse36", "pn", "b19",
237 "b20", "b21", "mmxext", "mmx", "fxsr",
238 "xmm", "sse2", "b27", "b28", "b29",
262 #else /* __amd64__ */
269 hw_model[0] = CTL_HW;
270 hw_model[1] = HW_MODEL;
272 size = sizeof(model);
273 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
274 strcpy(model, "unknown");
275 for (i = 0; i < mp_ncpus; ++i) {
278 "vendor_id\t: %.20s\n"
282 "stepping\t: %u\n\n",
283 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
284 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
285 /* XXX per-cpu vendor / class / model / id? */
288 sbuf_cat(sb, "flags\t\t:");
291 switch (cpu_vendor_id) {
296 case CPU_VENDOR_CYRIX:
302 for (i = 0; i < 32; i++)
303 if (cpu_feature & (1 << i))
304 sbuf_printf(sb, " %s", flags[i]);
306 freq = atomic_load_acq_64(&tsc_freq);
308 fqmhz = (freq + 4999) / 1000000;
309 fqkhz = ((freq + 4999) / 10000) % 100;
311 "cpu MHz\t\t: %d.%02d\n"
312 "bogomips\t: %d.%02d\n",
313 fqmhz, fqkhz, fqmhz, fqkhz);
318 #endif /* __i386__ || __amd64__ */
321 * Filler function for proc/mtab
323 * This file doesn't exist in Linux' procfs, but is included here so
324 * users can symlink /compat/linux/etc/mtab to /proc/mtab
327 linprocfs_domtab(PFS_FILL_ARGS)
331 char *dlep, *flep, *mntto, *mntfrom, *fstype;
334 struct statfs *buf, *sp;
337 /* resolve symlinks etc. in the emulation tree prefix */
338 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
341 lep = linux_emul_path;
343 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
347 lep_len = strlen(lep);
350 error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
351 UIO_SYSSPACE, MNT_WAIT);
358 for (sp = buf; count > 0; sp++, count--) {
359 /* determine device name */
360 mntfrom = sp->f_mntfromname;
362 /* determine mount point */
363 mntto = sp->f_mntonname;
364 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
367 /* determine fs type */
368 fstype = sp->f_fstypename;
369 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
370 mntfrom = fstype = "proc";
371 else if (strcmp(fstype, "procfs") == 0)
374 if (strcmp(fstype, "linsysfs") == 0) {
375 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
376 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
378 /* For Linux msdosfs is called vfat */
379 if (strcmp(fstype, "msdosfs") == 0)
381 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
382 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
384 #define ADD_OPTION(opt, name) \
385 if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
386 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
387 ADD_OPTION(MNT_NOEXEC, "noexec");
388 ADD_OPTION(MNT_NOSUID, "nosuid");
389 ADD_OPTION(MNT_UNION, "union");
390 ADD_OPTION(MNT_ASYNC, "async");
391 ADD_OPTION(MNT_SUIDDIR, "suiddir");
392 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
393 ADD_OPTION(MNT_NOATIME, "noatime");
395 /* a real Linux mtab will also show NFS options */
396 sbuf_printf(sb, " 0 0\n");
405 * Filler function for proc/partitions
408 linprocfs_dopartitions(PFS_FILL_ARGS)
412 struct g_provider *pp;
416 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
417 "ruse wio wmerge wsect wuse running use aveq\n");
419 LIST_FOREACH(cp, &g_classes, class) {
420 if (strcmp(cp->name, "DISK") == 0 ||
421 strcmp(cp->name, "PART") == 0)
422 LIST_FOREACH(gp, &cp->geom, geom) {
423 LIST_FOREACH(pp, &gp->provider, provider) {
424 if (linux_driver_get_major_minor(
425 pp->name, &major, &minor) != 0) {
429 sbuf_printf(sb, "%d %d %lld %s "
431 "%d %d %d %d %d %d\n",
433 (long long)pp->mediasize, pp->name,
446 * Filler function for proc/stat
449 linprocfs_dostat(PFS_FILL_ARGS)
452 long cp_time[CPUSTATES];
456 read_cpu_time(cp_time);
457 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
458 T2J(cp_time[CP_USER]),
459 T2J(cp_time[CP_NICE]),
460 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
461 T2J(cp_time[CP_IDLE]));
464 cp = pcpu->pc_cp_time;
465 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
468 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
479 vm_cnt.v_vnodepgsout,
484 (long long)boottime.tv_sec);
489 linprocfs_doswaps(PFS_FILL_ARGS)
492 uintmax_t total, used;
494 char devname[SPECNAMELEN + 1];
496 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
499 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
501 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
502 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
505 * The space and not tab after the device name is on
506 * purpose. Linux does so.
508 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
509 devname, total, used);
516 * Filler function for proc/uptime
519 linprocfs_douptime(PFS_FILL_ARGS)
521 long cp_time[CPUSTATES];
525 read_cpu_time(cp_time);
526 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
527 (long long)tv.tv_sec, tv.tv_usec / 10000,
528 T2S(cp_time[CP_IDLE] / mp_ncpus),
529 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
537 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
543 strncpy(osbuild, version, 256);
545 cp1 = strstr(osbuild, "\n");
546 cp2 = strstr(osbuild, ":");
549 cp1 = strstr(osbuild, "#");
553 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
556 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
563 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
569 cp = strstr(version, "\n ");
571 strncpy(builder, cp + 5, 256);
573 cp = strstr(builder, ":");
578 sbuf_cat(sb, builder);
581 sbuf_cat(sb, "des@freebsd.org");
585 * Filler function for proc/version
588 linprocfs_doversion(PFS_FILL_ARGS)
590 char osname[LINUX_MAX_UTSNAME];
591 char osrelease[LINUX_MAX_UTSNAME];
593 linux_get_osname(td, osname);
594 linux_get_osrelease(td, osrelease);
595 sbuf_printf(sb, "%s version %s (", osname, osrelease);
596 linprocfs_osbuilder(td, sb);
597 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
598 linprocfs_osbuild(td, sb);
605 * Filler function for proc/loadavg
608 linprocfs_doloadavg(PFS_FILL_ARGS)
612 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
613 (int)(averunnable.ldavg[0] / averunnable.fscale),
614 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
615 (int)(averunnable.ldavg[1] / averunnable.fscale),
616 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
617 (int)(averunnable.ldavg[2] / averunnable.fscale),
618 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
619 1, /* number of running tasks */
620 nprocs, /* number of tasks */
621 lastpid /* the last pid */
627 * Filler function for proc/pid/stat
630 linprocfs_doprocstat(PFS_FILL_ARGS)
632 struct kinfo_proc kp;
634 static int ratelimit = 0;
635 vm_offset_t startcode, startdata;
637 sx_slock(&proctree_lock);
639 fill_kinfo_proc(p, &kp);
640 sx_sunlock(&proctree_lock);
642 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
643 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
648 sbuf_printf(sb, "%d", p->p_pid);
649 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
650 PS_ADD("comm", "(%s)", p->p_comm);
651 if (kp.ki_stat > sizeof(linux_state)) {
654 if (ratelimit == 0) {
655 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
656 kp.ki_stat, sizeof(linux_state));
660 state = linux_state[kp.ki_stat - 1];
661 PS_ADD("state", "%c", state);
662 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
663 PS_ADD("pgrp", "%d", p->p_pgid);
664 PS_ADD("session", "%d", p->p_session->s_sid);
666 PS_ADD("tty", "%ju", (uintmax_t)kp.ki_tdev);
667 PS_ADD("tpgid", "%d", kp.ki_tpgid);
668 PS_ADD("flags", "%u", 0); /* XXX */
669 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
670 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
671 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
672 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
673 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
674 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
675 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
676 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
677 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
678 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
679 PS_ADD("0", "%d", 0); /* removed field */
680 PS_ADD("itrealvalue", "%d", 0); /* XXX */
681 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
682 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
683 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
684 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
685 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
686 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
687 PS_ADD("startstack", "%u", 0); /* XXX */
688 PS_ADD("kstkesp", "%u", 0); /* XXX */
689 PS_ADD("kstkeip", "%u", 0); /* XXX */
690 PS_ADD("signal", "%u", 0); /* XXX */
691 PS_ADD("blocked", "%u", 0); /* XXX */
692 PS_ADD("sigignore", "%u", 0); /* XXX */
693 PS_ADD("sigcatch", "%u", 0); /* XXX */
694 PS_ADD("wchan", "%u", 0); /* XXX */
695 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
696 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
697 PS_ADD("exitsignal", "%d", 0); /* XXX */
698 PS_ADD("processor", "%u", kp.ki_lastcpu);
699 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
700 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
708 * Filler function for proc/pid/statm
711 linprocfs_doprocstatm(PFS_FILL_ARGS)
713 struct kinfo_proc kp;
716 sx_slock(&proctree_lock);
718 fill_kinfo_proc(p, &kp);
720 sx_sunlock(&proctree_lock);
723 * See comments in linprocfs_doprocstatus() regarding the
724 * computation of lsize.
726 /* size resident share trs drs lrs dt */
727 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
728 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
729 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
730 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
731 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
732 lsize = B2P(kp.ki_size) - kp.ki_dsize -
733 kp.ki_ssize - kp.ki_tsize - 1;
734 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
735 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
741 * Filler function for proc/pid/status
744 linprocfs_doprocstatus(PFS_FILL_ARGS)
746 struct kinfo_proc kp;
753 sx_slock(&proctree_lock);
755 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
757 if (P_SHOULDSTOP(p)) {
758 state = "T (stopped)";
765 if (p->p_flag & P_WEXIT) {
766 state = "X (exiting)";
769 switch(td2->td_state) {
771 state = "S (sleeping)";
775 state = "R (running)";
778 state = "? (unknown)";
783 state = "Z (zombie)";
786 state = "? (unknown)";
791 fill_kinfo_proc(p, &kp);
792 sx_sunlock(&proctree_lock);
794 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
795 sbuf_printf(sb, "State:\t%s\n", state);
800 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
801 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
802 p->p_pptr->p_pid : 0);
803 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
805 p->p_ucred->cr_svuid,
806 /* FreeBSD doesn't have fsuid */
808 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
810 p->p_ucred->cr_svgid,
811 /* FreeBSD doesn't have fsgid */
813 sbuf_cat(sb, "Groups:\t");
814 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
815 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
822 * While our approximation of VmLib may not be accurate (I
823 * don't know of a simple way to verify it, and I'm not sure
824 * it has much meaning anyway), I believe it's good enough.
826 * The same code that could (I think) accurately compute VmLib
827 * could also compute VmLck, but I don't really care enough to
828 * implement it. Submissions are welcome.
830 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
831 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
832 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
833 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
834 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
835 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
836 lsize = B2P(kp.ki_size) - kp.ki_dsize -
837 kp.ki_ssize - kp.ki_tsize - 1;
838 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
843 * We support up to 128 signals, while Linux supports 32,
844 * but we only define 32 (the same 32 as Linux, to boot), so
845 * just show the lower 32 bits of each mask. XXX hack.
847 * NB: on certain platforms (Sparc at least) Linux actually
848 * supports 64 signals, but this code is a long way from
849 * running on anything but i386, so ignore that for now.
852 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
854 * I can't seem to find out where the signal mask is in
855 * relation to struct proc, so SigBlk is left unimplemented.
857 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
859 mtx_lock(&ps->ps_mtx);
860 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
861 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
862 mtx_unlock(&ps->ps_mtx);
866 * Linux also prints the capability masks, but we don't have
867 * capabilities yet, and when we do get them they're likely to
868 * be meaningless to Linux programs, so we lie. XXX
870 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
871 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
872 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
879 * Filler function for proc/pid/cwd
882 linprocfs_doproccwd(PFS_FILL_ARGS)
884 char *fullpath = "unknown";
885 char *freepath = NULL;
887 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
888 sbuf_printf(sb, "%s", fullpath);
890 free(freepath, M_TEMP);
895 * Filler function for proc/pid/root
898 linprocfs_doprocroot(PFS_FILL_ARGS)
901 char *fullpath = "unknown";
902 char *freepath = NULL;
904 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
905 vn_fullpath(td, rvp, &fullpath, &freepath);
906 sbuf_printf(sb, "%s", fullpath);
908 free(freepath, M_TEMP);
913 * Filler function for proc/pid/cmdline
916 linprocfs_doproccmdline(PFS_FILL_ARGS)
921 if ((ret = p_cansee(td, p)) != 0) {
927 * Mimic linux behavior and pass only processes with usermode
928 * address space as valid. Return zero silently otherwize.
930 if (p->p_vmspace == &vmspace0) {
934 if (p->p_args != NULL) {
935 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
940 if ((p->p_flag & P_SYSTEM) != 0) {
947 ret = proc_getargv(td, p, sb);
952 * Filler function for proc/pid/environ
955 linprocfs_doprocenviron(PFS_FILL_ARGS)
960 if ((ret = p_candebug(td, p)) != 0) {
966 * Mimic linux behavior and pass only processes with usermode
967 * address space as valid. Return zero silently otherwize.
969 if (p->p_vmspace == &vmspace0) {
974 if ((p->p_flag & P_SYSTEM) != 0) {
981 ret = proc_getenvv(td, p, sb);
986 * Filler function for proc/pid/maps
989 linprocfs_doprocmaps(PFS_FILL_ARGS)
993 vm_map_entry_t entry, tmp_entry;
994 vm_object_t obj, tobj, lobj;
995 vm_offset_t e_start, e_end;
996 vm_ooffset_t off = 0;
998 unsigned int last_timestamp;
999 char *name = "", *freename = NULL;
1001 int ref_count, shadow_count, flags;
1007 error = p_candebug(td, p);
1012 if (uio->uio_rw != UIO_READ)
1013 return (EOPNOTSUPP);
1016 vm = vmspace_acquire_ref(p);
1020 vm_map_lock_read(map);
1021 for (entry = map->header.next; entry != &map->header;
1022 entry = entry->next) {
1025 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1027 e_prot = entry->protection;
1028 e_start = entry->start;
1030 obj = entry->object.vm_object;
1031 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1032 VM_OBJECT_RLOCK(tobj);
1034 VM_OBJECT_RUNLOCK(lobj);
1037 last_timestamp = map->timestamp;
1038 vm_map_unlock_read(map);
1041 off = IDX_TO_OFF(lobj->size);
1042 if (lobj->type == OBJT_VNODE) {
1050 VM_OBJECT_RUNLOCK(lobj);
1052 ref_count = obj->ref_count;
1053 shadow_count = obj->shadow_count;
1054 VM_OBJECT_RUNLOCK(obj);
1056 vn_fullpath(td, vp, &name, &freename);
1057 vn_lock(vp, LK_SHARED | LK_RETRY);
1058 VOP_GETATTR(vp, &vat, td->td_ucred);
1059 ino = vat.va_fileid;
1070 * start, end, access, offset, major, minor, inode, name.
1072 error = sbuf_printf(sb,
1073 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1074 (u_long)e_start, (u_long)e_end,
1075 (e_prot & VM_PROT_READ)?"r":"-",
1076 (e_prot & VM_PROT_WRITE)?"w":"-",
1077 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1087 free(freename, M_TEMP);
1088 vm_map_lock_read(map);
1093 if (last_timestamp != map->timestamp) {
1095 * Look again for the entry because the map was
1096 * modified while it was unlocked. Specifically,
1097 * the entry may have been clipped, merged, or deleted.
1099 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1103 vm_map_unlock_read(map);
1110 * Filler function for proc/net/dev
1113 linprocfs_donetdev(PFS_FILL_ARGS)
1115 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1118 sbuf_printf(sb, "%6s|%58s|%s\n"
1120 "Inter-", " Receive", " Transmit",
1122 "bytes packets errs drop fifo frame compressed multicast",
1123 "bytes packets errs drop fifo colls carrier compressed");
1125 CURVNET_SET(TD_TO_VNET(curthread));
1127 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1128 linux_ifname(ifp, ifname, sizeof ifname);
1129 sbuf_printf(sb, "%6.6s: ", ifname);
1130 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1131 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1132 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1133 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1134 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1135 /* rx_missed_errors */
1136 0UL, /* rx_fifo_errors */
1137 0UL, /* rx_length_errors +
1140 * rx_frame_errors */
1141 0UL, /* rx_compressed */
1142 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1143 /* XXX-BZ rx only? */
1144 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1145 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1146 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1147 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1148 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1149 0UL, /* tx_fifo_errors */
1150 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1151 0UL, /* tx_carrier_errors +
1152 * tx_aborted_errors +
1153 * tx_window_errors +
1154 * tx_heartbeat_errors*/
1155 0UL); /* tx_compressed */
1164 * Filler function for proc/sys/kernel/osrelease
1167 linprocfs_doosrelease(PFS_FILL_ARGS)
1169 char osrelease[LINUX_MAX_UTSNAME];
1171 linux_get_osrelease(td, osrelease);
1172 sbuf_printf(sb, "%s\n", osrelease);
1178 * Filler function for proc/sys/kernel/ostype
1181 linprocfs_doostype(PFS_FILL_ARGS)
1183 char osname[LINUX_MAX_UTSNAME];
1185 linux_get_osname(td, osname);
1186 sbuf_printf(sb, "%s\n", osname);
1192 * Filler function for proc/sys/kernel/version
1195 linprocfs_doosbuild(PFS_FILL_ARGS)
1198 linprocfs_osbuild(td, sb);
1204 * Filler function for proc/sys/kernel/msgmni
1207 linprocfs_domsgmni(PFS_FILL_ARGS)
1210 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1215 * Filler function for proc/sys/kernel/pid_max
1218 linprocfs_dopid_max(PFS_FILL_ARGS)
1221 sbuf_printf(sb, "%i\n", PID_MAX);
1226 * Filler function for proc/sys/kernel/sem
1229 linprocfs_dosem(PFS_FILL_ARGS)
1232 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1233 seminfo.semopm, seminfo.semmni);
1238 * Filler function for proc/scsi/device_info
1241 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1248 * Filler function for proc/scsi/scsi
1251 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1257 extern struct cdevsw *cdevsw[];
1260 * Filler function for proc/devices
1263 linprocfs_dodevices(PFS_FILL_ARGS)
1266 sbuf_printf(sb, "Character devices:\n");
1268 char_devices = linux_get_char_devices();
1269 sbuf_printf(sb, "%s", char_devices);
1270 linux_free_get_char_devices(char_devices);
1272 sbuf_printf(sb, "\nBlock devices:\n");
1278 * Filler function for proc/cmdline
1281 linprocfs_docmdline(PFS_FILL_ARGS)
1284 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1285 sbuf_printf(sb, " ro root=302\n");
1290 * Filler function for proc/filesystems
1293 linprocfs_dofilesystems(PFS_FILL_ARGS)
1295 struct vfsconf *vfsp;
1298 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1299 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1300 sbuf_printf(sb, "nodev");
1301 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1309 * Filler function for proc/modules
1312 linprocfs_domodules(PFS_FILL_ARGS)
1314 struct linker_file *lf;
1316 TAILQ_FOREACH(lf, &linker_files, link) {
1317 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1318 (unsigned long)lf->size, lf->refs);
1325 * Filler function for proc/pid/fd
1328 linprocfs_dofdescfs(PFS_FILL_ARGS)
1332 sbuf_printf(sb, "/dev/fd");
1334 sbuf_printf(sb, "unknown");
1340 * Filler function for proc/sys/kernel/random/uuid
1343 linprocfs_douuid(PFS_FILL_ARGS)
1347 kern_uuidgen(&uuid, 1);
1348 sbuf_printf_uuid(sb, &uuid);
1349 sbuf_printf(sb, "\n");
1358 linprocfs_init(PFS_INIT_ARGS)
1360 struct pfs_node *root;
1361 struct pfs_node *dir;
1366 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1367 NULL, NULL, NULL, PFS_RD);
1368 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1369 NULL, NULL, NULL, PFS_RD);
1370 pfs_create_file(root, "devices", &linprocfs_dodevices,
1371 NULL, NULL, NULL, PFS_RD);
1372 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1373 NULL, NULL, NULL, PFS_RD);
1374 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1375 NULL, NULL, NULL, PFS_RD);
1376 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1377 NULL, NULL, NULL, PFS_RD);
1379 pfs_create_file(root, "modules", &linprocfs_domodules,
1380 NULL, NULL, NULL, PFS_RD);
1382 pfs_create_file(root, "mounts", &linprocfs_domtab,
1383 NULL, NULL, NULL, PFS_RD);
1384 pfs_create_file(root, "mtab", &linprocfs_domtab,
1385 NULL, NULL, NULL, PFS_RD);
1386 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1387 NULL, NULL, NULL, PFS_RD);
1388 pfs_create_link(root, "self", &procfs_docurproc,
1389 NULL, NULL, NULL, 0);
1390 pfs_create_file(root, "stat", &linprocfs_dostat,
1391 NULL, NULL, NULL, PFS_RD);
1392 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1393 NULL, NULL, NULL, PFS_RD);
1394 pfs_create_file(root, "uptime", &linprocfs_douptime,
1395 NULL, NULL, NULL, PFS_RD);
1396 pfs_create_file(root, "version", &linprocfs_doversion,
1397 NULL, NULL, NULL, PFS_RD);
1400 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1401 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1402 NULL, NULL, NULL, PFS_RD);
1404 /* /proc/<pid>/... */
1405 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1406 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1407 NULL, NULL, NULL, PFS_RD);
1408 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1409 NULL, NULL, NULL, 0);
1410 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1411 NULL, NULL, NULL, PFS_RD);
1412 pfs_create_link(dir, "exe", &procfs_doprocfile,
1413 NULL, &procfs_notsystem, NULL, 0);
1414 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1415 NULL, NULL, NULL, PFS_RD);
1416 pfs_create_file(dir, "mem", &procfs_doprocmem,
1417 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1418 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1419 NULL, NULL, NULL, 0);
1420 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1421 NULL, NULL, NULL, PFS_RD);
1422 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1423 NULL, NULL, NULL, PFS_RD);
1424 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1425 NULL, NULL, NULL, PFS_RD);
1426 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1427 NULL, NULL, NULL, 0);
1429 /* /proc/scsi/... */
1430 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1431 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1432 NULL, NULL, NULL, PFS_RD);
1433 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1434 NULL, NULL, NULL, PFS_RD);
1437 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1438 /* /proc/sys/kernel/... */
1439 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1440 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1441 NULL, NULL, NULL, PFS_RD);
1442 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1443 NULL, NULL, NULL, PFS_RD);
1444 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1445 NULL, NULL, NULL, PFS_RD);
1446 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1447 NULL, NULL, NULL, PFS_RD);
1448 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1449 NULL, NULL, NULL, PFS_RD);
1450 pfs_create_file(dir, "sem", &linprocfs_dosem,
1451 NULL, NULL, NULL, PFS_RD);
1453 /* /proc/sys/kernel/random/... */
1454 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1455 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1456 NULL, NULL, NULL, PFS_RD);
1465 linprocfs_uninit(PFS_INIT_ARGS)
1468 /* nothing to do, pseudofs will GC */
1472 PSEUDOFS(linprocfs, 1, 0);
1473 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1474 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1475 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1476 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);