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 <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/blist.h>
50 #include <sys/fcntl.h>
51 #include <sys/filedesc.h>
53 #include <sys/kernel.h>
54 #include <sys/limits.h>
55 #include <sys/linker.h>
57 #include <sys/malloc.h>
59 #include <sys/mutex.h>
60 #include <sys/namei.h>
62 #include <sys/ptrace.h>
63 #include <sys/resourcevar.h>
67 #include <sys/socket.h>
68 #include <sys/syscallsubr.h>
69 #include <sys/sysctl.h>
70 #include <sys/sysent.h>
71 #include <sys/systm.h>
76 #include <sys/vmmeter.h>
77 #include <sys/vnode.h>
81 #include <net/if_var.h>
82 #include <net/if_types.h>
85 #include <vm/vm_extern.h>
87 #include <vm/vm_map.h>
88 #include <vm/vm_param.h>
89 #include <vm/vm_object.h>
90 #include <vm/swap_pager.h>
92 #include <machine/clock.h>
94 #include <geom/geom.h>
95 #include <geom/geom_int.h>
97 #if defined(__i386__) || defined(__amd64__)
98 #include <machine/cputypes.h>
99 #include <machine/md_var.h>
100 #endif /* __i386__ || __amd64__ */
102 #include <compat/linux/linux.h>
103 #include <compat/linux/linux_mib.h>
104 #include <compat/linux/linux_misc.h>
105 #include <compat/linux/linux_util.h>
106 #include <fs/pseudofs/pseudofs.h>
107 #include <fs/procfs/procfs.h>
110 * Various conversion macros
112 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
113 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
114 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
115 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
116 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
117 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
118 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
119 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
122 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
124 * The linux procfs state field displays one of the characters RSDZTW to
125 * denote running, sleeping in an interruptible wait, waiting in an
126 * uninterruptible disk sleep, a zombie process, process is being traced
127 * or stopped, or process is paging respectively.
129 * Our struct kinfo_proc contains the variable ki_stat which contains a
130 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
132 * This character array is used with ki_stati-1 as an index and tries to
133 * map our states to suitable linux states.
135 static char linux_state[] = "RRSTZDD";
138 * Filler function for proc/meminfo
141 linprocfs_domeminfo(PFS_FILL_ARGS)
143 unsigned long memtotal; /* total memory in bytes */
144 unsigned long memused; /* used memory in bytes */
145 unsigned long memfree; /* free memory in bytes */
146 unsigned long memshared; /* shared memory ??? */
147 unsigned long buffers, cached; /* buffer / cache memory ??? */
148 unsigned long long swaptotal; /* total swap space in bytes */
149 unsigned long long swapused; /* used swap space in bytes */
150 unsigned long long swapfree; /* free swap space in bytes */
154 memtotal = physmem * PAGE_SIZE;
156 * The correct thing here would be:
158 memfree = vm_cnt.v_free_count * PAGE_SIZE;
159 memused = memtotal - memfree;
161 * but it might mislead linux binaries into thinking there
162 * is very little memory left, so we cheat and tell them that
163 * all memory that isn't wired down is free.
165 memused = vm_cnt.v_wire_count * PAGE_SIZE;
166 memfree = memtotal - memused;
167 swap_pager_status(&i, &j);
168 swaptotal = (unsigned long long)i * PAGE_SIZE;
169 swapused = (unsigned long long)j * PAGE_SIZE;
170 swapfree = swaptotal - swapused;
172 mtx_lock(&vm_object_list_mtx);
173 TAILQ_FOREACH(object, &vm_object_list, object_list)
174 if (object->shadow_count > 1)
175 memshared += object->resident_page_count;
176 mtx_unlock(&vm_object_list_mtx);
177 memshared *= PAGE_SIZE;
179 * We'd love to be able to write:
183 * but bufspace is internal to vfs_bio.c and we don't feel
184 * like unstaticizing it just for linprocfs's sake.
187 cached = vm_cnt.v_cache_count * PAGE_SIZE;
190 " total: used: free: shared: buffers: cached:\n"
191 "Mem: %lu %lu %lu %lu %lu %lu\n"
192 "Swap: %llu %llu %llu\n"
193 "MemTotal: %9lu kB\n"
195 "MemShared:%9lu kB\n"
198 "SwapTotal:%9llu kB\n"
199 "SwapFree: %9llu kB\n",
200 memtotal, memused, memfree, memshared, buffers, cached,
201 swaptotal, swapused, swapfree,
202 B2K(memtotal), B2K(memfree),
203 B2K(memshared), B2K(buffers), B2K(cached),
204 B2K(swaptotal), B2K(swapfree));
209 #if defined(__i386__) || defined(__amd64__)
211 * Filler function for proc/cpuinfo (i386 & amd64 version)
214 linprocfs_docpuinfo(PFS_FILL_ARGS)
220 int class, fqmhz, fqkhz;
224 * We default the flags to include all non-conflicting flags,
225 * and the Intel versions of conflicting flags.
227 static char *flags[] = {
228 "fpu", "vme", "de", "pse", "tsc",
229 "msr", "pae", "mce", "cx8", "apic",
230 "sep", "sep", "mtrr", "pge", "mca",
231 "cmov", "pat", "pse36", "pn", "b19",
232 "b20", "b21", "mmxext", "mmx", "fxsr",
233 "xmm", "sse2", "b27", "b28", "b29",
257 #else /* __amd64__ */
264 hw_model[0] = CTL_HW;
265 hw_model[1] = HW_MODEL;
267 size = sizeof(model);
268 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
269 strcpy(model, "unknown");
270 for (i = 0; i < mp_ncpus; ++i) {
273 "vendor_id\t: %.20s\n"
277 "stepping\t: %u\n\n",
278 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
279 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
280 /* XXX per-cpu vendor / class / model / id? */
283 sbuf_cat(sb, "flags\t\t:");
286 switch (cpu_vendor_id) {
291 case CPU_VENDOR_CYRIX:
297 for (i = 0; i < 32; i++)
298 if (cpu_feature & (1 << i))
299 sbuf_printf(sb, " %s", flags[i]);
301 freq = atomic_load_acq_64(&tsc_freq);
303 fqmhz = (freq + 4999) / 1000000;
304 fqkhz = ((freq + 4999) / 10000) % 100;
306 "cpu MHz\t\t: %d.%02d\n"
307 "bogomips\t: %d.%02d\n",
308 fqmhz, fqkhz, fqmhz, fqkhz);
313 #endif /* __i386__ || __amd64__ */
316 * Filler function for proc/mtab
318 * This file doesn't exist in Linux' procfs, but is included here so
319 * users can symlink /compat/linux/etc/mtab to /proc/mtab
322 linprocfs_domtab(PFS_FILL_ARGS)
326 char *dlep, *flep, *mntto, *mntfrom, *fstype;
329 struct statfs *buf, *sp;
332 /* resolve symlinks etc. in the emulation tree prefix */
333 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
336 lep = linux_emul_path;
338 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
342 lep_len = strlen(lep);
345 error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
346 UIO_SYSSPACE, MNT_WAIT);
353 for (sp = buf; count > 0; sp++, count--) {
354 /* determine device name */
355 mntfrom = sp->f_mntfromname;
357 /* determine mount point */
358 mntto = sp->f_mntonname;
359 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
362 /* determine fs type */
363 fstype = sp->f_fstypename;
364 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365 mntfrom = fstype = "proc";
366 else if (strcmp(fstype, "procfs") == 0)
369 if (strcmp(fstype, "linsysfs") == 0) {
370 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
373 /* For Linux msdosfs is called vfat */
374 if (strcmp(fstype, "msdosfs") == 0)
376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
379 #define ADD_OPTION(opt, name) \
380 if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
381 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
382 ADD_OPTION(MNT_NOEXEC, "noexec");
383 ADD_OPTION(MNT_NOSUID, "nosuid");
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");
390 /* a real Linux mtab will also show NFS options */
391 sbuf_printf(sb, " 0 0\n");
400 * Filler function for proc/partitions
403 linprocfs_dopartitions(PFS_FILL_ARGS)
407 struct g_provider *pp;
411 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
412 "ruse wio wmerge wsect wuse running use aveq\n");
414 LIST_FOREACH(cp, &g_classes, class) {
415 if (strcmp(cp->name, "DISK") == 0 ||
416 strcmp(cp->name, "PART") == 0)
417 LIST_FOREACH(gp, &cp->geom, geom) {
418 LIST_FOREACH(pp, &gp->provider, provider) {
419 if (linux_driver_get_major_minor(
420 pp->name, &major, &minor) != 0) {
424 sbuf_printf(sb, "%d %d %lld %s "
426 "%d %d %d %d %d %d\n",
428 (long long)pp->mediasize, pp->name,
441 * Filler function for proc/stat
444 linprocfs_dostat(PFS_FILL_ARGS)
447 long cp_time[CPUSTATES];
451 read_cpu_time(cp_time);
452 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
453 T2J(cp_time[CP_USER]),
454 T2J(cp_time[CP_NICE]),
455 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
456 T2J(cp_time[CP_IDLE]));
459 cp = pcpu->pc_cp_time;
460 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
463 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
474 vm_cnt.v_vnodepgsout,
479 (long long)boottime.tv_sec);
484 linprocfs_doswaps(PFS_FILL_ARGS)
487 uintmax_t total, used;
489 char devname[SPECNAMELEN + 1];
491 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
494 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
496 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
497 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
500 * The space and not tab after the device name is on
501 * purpose. Linux does so.
503 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
504 devname, total, used);
511 * Filler function for proc/uptime
514 linprocfs_douptime(PFS_FILL_ARGS)
516 long cp_time[CPUSTATES];
520 read_cpu_time(cp_time);
521 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
522 (long long)tv.tv_sec, tv.tv_usec / 10000,
523 T2S(cp_time[CP_IDLE] / mp_ncpus),
524 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
532 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
538 strncpy(osbuild, version, 256);
540 cp1 = strstr(osbuild, "\n");
541 cp2 = strstr(osbuild, ":");
544 cp1 = strstr(osbuild, "#");
548 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
551 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
558 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
564 cp = strstr(version, "\n ");
566 strncpy(builder, cp + 5, 256);
568 cp = strstr(builder, ":");
573 sbuf_cat(sb, builder);
576 sbuf_cat(sb, "des@freebsd.org");
580 * Filler function for proc/version
583 linprocfs_doversion(PFS_FILL_ARGS)
585 char osname[LINUX_MAX_UTSNAME];
586 char osrelease[LINUX_MAX_UTSNAME];
588 linux_get_osname(td, osname);
589 linux_get_osrelease(td, osrelease);
590 sbuf_printf(sb, "%s version %s (", osname, osrelease);
591 linprocfs_osbuilder(td, sb);
592 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
593 linprocfs_osbuild(td, sb);
600 * Filler function for proc/loadavg
603 linprocfs_doloadavg(PFS_FILL_ARGS)
607 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
608 (int)(averunnable.ldavg[0] / averunnable.fscale),
609 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
610 (int)(averunnable.ldavg[1] / averunnable.fscale),
611 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
612 (int)(averunnable.ldavg[2] / averunnable.fscale),
613 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
614 1, /* number of running tasks */
615 nprocs, /* number of tasks */
616 lastpid /* the last pid */
622 * Filler function for proc/pid/stat
625 linprocfs_doprocstat(PFS_FILL_ARGS)
627 struct kinfo_proc kp;
629 static int ratelimit = 0;
630 vm_offset_t startcode, startdata;
632 sx_slock(&proctree_lock);
634 fill_kinfo_proc(p, &kp);
635 sx_sunlock(&proctree_lock);
637 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
638 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
643 sbuf_printf(sb, "%d", p->p_pid);
644 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
645 PS_ADD("comm", "(%s)", p->p_comm);
646 if (kp.ki_stat > sizeof(linux_state)) {
649 if (ratelimit == 0) {
650 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
651 kp.ki_stat, sizeof(linux_state));
655 state = linux_state[kp.ki_stat - 1];
656 PS_ADD("state", "%c", state);
657 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
658 PS_ADD("pgrp", "%d", p->p_pgid);
659 PS_ADD("session", "%d", p->p_session->s_sid);
661 PS_ADD("tty", "%ju", (uintmax_t)kp.ki_tdev);
662 PS_ADD("tpgid", "%d", kp.ki_tpgid);
663 PS_ADD("flags", "%u", 0); /* XXX */
664 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
665 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
666 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
667 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
668 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
669 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
670 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
671 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
672 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
673 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
674 PS_ADD("0", "%d", 0); /* removed field */
675 PS_ADD("itrealvalue", "%d", 0); /* XXX */
676 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
677 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
678 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
679 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
680 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
681 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
682 PS_ADD("startstack", "%u", 0); /* XXX */
683 PS_ADD("kstkesp", "%u", 0); /* XXX */
684 PS_ADD("kstkeip", "%u", 0); /* XXX */
685 PS_ADD("signal", "%u", 0); /* XXX */
686 PS_ADD("blocked", "%u", 0); /* XXX */
687 PS_ADD("sigignore", "%u", 0); /* XXX */
688 PS_ADD("sigcatch", "%u", 0); /* XXX */
689 PS_ADD("wchan", "%u", 0); /* XXX */
690 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
691 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
692 PS_ADD("exitsignal", "%d", 0); /* XXX */
693 PS_ADD("processor", "%u", kp.ki_lastcpu);
694 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
695 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
703 * Filler function for proc/pid/statm
706 linprocfs_doprocstatm(PFS_FILL_ARGS)
708 struct kinfo_proc kp;
711 sx_slock(&proctree_lock);
713 fill_kinfo_proc(p, &kp);
715 sx_sunlock(&proctree_lock);
718 * See comments in linprocfs_doprocstatus() regarding the
719 * computation of lsize.
721 /* size resident share trs drs lrs dt */
722 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
723 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
724 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
725 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
726 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
727 lsize = B2P(kp.ki_size) - kp.ki_dsize -
728 kp.ki_ssize - kp.ki_tsize - 1;
729 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
730 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
736 * Filler function for proc/pid/status
739 linprocfs_doprocstatus(PFS_FILL_ARGS)
741 struct kinfo_proc kp;
746 l_sigset_t siglist, sigignore, sigcatch;
749 sx_slock(&proctree_lock);
751 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
753 if (P_SHOULDSTOP(p)) {
754 state = "T (stopped)";
761 if (p->p_flag & P_WEXIT) {
762 state = "X (exiting)";
765 switch(td2->td_state) {
767 state = "S (sleeping)";
771 state = "R (running)";
774 state = "? (unknown)";
779 state = "Z (zombie)";
782 state = "? (unknown)";
787 fill_kinfo_proc(p, &kp);
788 sx_sunlock(&proctree_lock);
790 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
791 sbuf_printf(sb, "State:\t%s\n", state);
796 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
797 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
798 p->p_pptr->p_pid : 0);
799 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
801 p->p_ucred->cr_svuid,
802 /* FreeBSD doesn't have fsuid */
804 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
806 p->p_ucred->cr_svgid,
807 /* FreeBSD doesn't have fsgid */
809 sbuf_cat(sb, "Groups:\t");
810 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
811 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
818 * While our approximation of VmLib may not be accurate (I
819 * don't know of a simple way to verify it, and I'm not sure
820 * it has much meaning anyway), I believe it's good enough.
822 * The same code that could (I think) accurately compute VmLib
823 * could also compute VmLck, but I don't really care enough to
824 * implement it. Submissions are welcome.
826 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
827 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
828 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
829 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
830 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
831 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
832 lsize = B2P(kp.ki_size) - kp.ki_dsize -
833 kp.ki_ssize - kp.ki_tsize - 1;
834 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
840 bsd_to_linux_sigset(&p->p_siglist, &siglist);
842 mtx_lock(&ps->ps_mtx);
843 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
844 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
845 mtx_unlock(&ps->ps_mtx);
848 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
850 * XXX. SigBlk - target thread's signal mask, td_sigmask.
851 * To implement SigBlk pseudofs should support proc/tid dir entries.
853 sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
854 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
855 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
858 * Linux also prints the capability masks, but we don't have
859 * capabilities yet, and when we do get them they're likely to
860 * be meaningless to Linux programs, so we lie. XXX
862 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
863 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
864 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
871 * Filler function for proc/pid/cwd
874 linprocfs_doproccwd(PFS_FILL_ARGS)
876 char *fullpath = "unknown";
877 char *freepath = NULL;
879 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
880 sbuf_printf(sb, "%s", fullpath);
882 free(freepath, M_TEMP);
887 * Filler function for proc/pid/root
890 linprocfs_doprocroot(PFS_FILL_ARGS)
893 char *fullpath = "unknown";
894 char *freepath = NULL;
896 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
897 vn_fullpath(td, rvp, &fullpath, &freepath);
898 sbuf_printf(sb, "%s", fullpath);
900 free(freepath, M_TEMP);
905 * Filler function for proc/pid/cmdline
908 linprocfs_doproccmdline(PFS_FILL_ARGS)
913 if ((ret = p_cansee(td, p)) != 0) {
919 * Mimic linux behavior and pass only processes with usermode
920 * address space as valid. Return zero silently otherwize.
922 if (p->p_vmspace == &vmspace0) {
926 if (p->p_args != NULL) {
927 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
932 if ((p->p_flag & P_SYSTEM) != 0) {
939 ret = proc_getargv(td, p, sb);
944 * Filler function for proc/pid/environ
947 linprocfs_doprocenviron(PFS_FILL_ARGS)
951 * Mimic linux behavior and pass only processes with usermode
952 * address space as valid. Return zero silently otherwize.
954 if (p->p_vmspace == &vmspace0)
957 return (proc_getenvv(td, p, sb));
960 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
961 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
962 static char vdso_str[] = " [vdso]";
963 static char stack_str[] = " [stack]";
966 * Filler function for proc/pid/maps
969 linprocfs_doprocmaps(PFS_FILL_ARGS)
973 vm_map_entry_t entry, tmp_entry;
974 vm_object_t obj, tobj, lobj;
975 vm_offset_t e_start, e_end;
976 vm_ooffset_t off = 0;
978 unsigned int last_timestamp;
979 char *name = "", *freename = NULL;
980 const char *l_map_str;
982 int ref_count, shadow_count, flags;
988 error = p_candebug(td, p);
993 if (uio->uio_rw != UIO_READ)
997 vm = vmspace_acquire_ref(p);
1001 if (SV_CURPROC_FLAG(SV_LP64))
1002 l_map_str = l64_map_str;
1004 l_map_str = l32_map_str;
1006 vm_map_lock_read(map);
1007 for (entry = map->header.next; entry != &map->header;
1008 entry = entry->next) {
1011 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1013 e_prot = entry->protection;
1014 e_start = entry->start;
1016 obj = entry->object.vm_object;
1017 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1018 VM_OBJECT_RLOCK(tobj);
1020 VM_OBJECT_RUNLOCK(lobj);
1023 last_timestamp = map->timestamp;
1024 vm_map_unlock_read(map);
1027 off = IDX_TO_OFF(lobj->size);
1028 if (lobj->type == OBJT_VNODE) {
1036 VM_OBJECT_RUNLOCK(lobj);
1038 ref_count = obj->ref_count;
1039 shadow_count = obj->shadow_count;
1040 VM_OBJECT_RUNLOCK(obj);
1042 vn_fullpath(td, vp, &name, &freename);
1043 vn_lock(vp, LK_SHARED | LK_RETRY);
1044 VOP_GETATTR(vp, &vat, td->td_ucred);
1045 ino = vat.va_fileid;
1047 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1048 if (e_start == p->p_sysent->sv_shared_page_base)
1050 if (e_end == p->p_sysent->sv_usrstack)
1061 * start, end, access, offset, major, minor, inode, name.
1063 error = sbuf_printf(sb, l_map_str,
1064 (u_long)e_start, (u_long)e_end,
1065 (e_prot & VM_PROT_READ)?"r":"-",
1066 (e_prot & VM_PROT_WRITE)?"w":"-",
1067 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1077 free(freename, M_TEMP);
1078 vm_map_lock_read(map);
1083 if (last_timestamp != map->timestamp) {
1085 * Look again for the entry because the map was
1086 * modified while it was unlocked. Specifically,
1087 * the entry may have been clipped, merged, or deleted.
1089 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1093 vm_map_unlock_read(map);
1100 * Criteria for interface name translation
1102 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1105 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1107 struct ifnet *ifscan;
1110 IFNET_RLOCK_ASSERT();
1112 /* Short-circuit non ethernet interfaces */
1113 if (!IFP_IS_ETH(ifp))
1114 return (strlcpy(buffer, ifp->if_xname, buflen));
1116 /* Determine the (relative) unit number for ethernet interfaces */
1118 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1120 return (snprintf(buffer, buflen, "eth%d", ethno));
1121 if (IFP_IS_ETH(ifscan))
1129 * Filler function for proc/net/dev
1132 linprocfs_donetdev(PFS_FILL_ARGS)
1134 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1137 sbuf_printf(sb, "%6s|%58s|%s\n"
1139 "Inter-", " Receive", " Transmit",
1141 "bytes packets errs drop fifo frame compressed multicast",
1142 "bytes packets errs drop fifo colls carrier compressed");
1144 CURVNET_SET(TD_TO_VNET(curthread));
1146 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1147 linux_ifname(ifp, ifname, sizeof ifname);
1148 sbuf_printf(sb, "%6.6s: ", ifname);
1149 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1150 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1151 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1152 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1153 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1154 /* rx_missed_errors */
1155 0UL, /* rx_fifo_errors */
1156 0UL, /* rx_length_errors +
1159 * rx_frame_errors */
1160 0UL, /* rx_compressed */
1161 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1162 /* XXX-BZ rx only? */
1163 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1164 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1165 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1166 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1167 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1168 0UL, /* tx_fifo_errors */
1169 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1170 0UL, /* tx_carrier_errors +
1171 * tx_aborted_errors +
1172 * tx_window_errors +
1173 * tx_heartbeat_errors*/
1174 0UL); /* tx_compressed */
1183 * Filler function for proc/sys/kernel/osrelease
1186 linprocfs_doosrelease(PFS_FILL_ARGS)
1188 char osrelease[LINUX_MAX_UTSNAME];
1190 linux_get_osrelease(td, osrelease);
1191 sbuf_printf(sb, "%s\n", osrelease);
1197 * Filler function for proc/sys/kernel/ostype
1200 linprocfs_doostype(PFS_FILL_ARGS)
1202 char osname[LINUX_MAX_UTSNAME];
1204 linux_get_osname(td, osname);
1205 sbuf_printf(sb, "%s\n", osname);
1211 * Filler function for proc/sys/kernel/version
1214 linprocfs_doosbuild(PFS_FILL_ARGS)
1217 linprocfs_osbuild(td, sb);
1223 * Filler function for proc/sys/kernel/msgmni
1226 linprocfs_domsgmni(PFS_FILL_ARGS)
1229 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1234 * Filler function for proc/sys/kernel/pid_max
1237 linprocfs_dopid_max(PFS_FILL_ARGS)
1240 sbuf_printf(sb, "%i\n", PID_MAX);
1245 * Filler function for proc/sys/kernel/sem
1248 linprocfs_dosem(PFS_FILL_ARGS)
1251 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1252 seminfo.semopm, seminfo.semmni);
1257 * Filler function for proc/scsi/device_info
1260 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1267 * Filler function for proc/scsi/scsi
1270 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1277 * Filler function for proc/devices
1280 linprocfs_dodevices(PFS_FILL_ARGS)
1283 sbuf_printf(sb, "Character devices:\n");
1285 char_devices = linux_get_char_devices();
1286 sbuf_printf(sb, "%s", char_devices);
1287 linux_free_get_char_devices(char_devices);
1289 sbuf_printf(sb, "\nBlock devices:\n");
1295 * Filler function for proc/cmdline
1298 linprocfs_docmdline(PFS_FILL_ARGS)
1301 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1302 sbuf_printf(sb, " ro root=302\n");
1307 * Filler function for proc/filesystems
1310 linprocfs_dofilesystems(PFS_FILL_ARGS)
1312 struct vfsconf *vfsp;
1315 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1316 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1317 sbuf_printf(sb, "nodev");
1318 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1326 * Filler function for proc/modules
1329 linprocfs_domodules(PFS_FILL_ARGS)
1331 struct linker_file *lf;
1333 TAILQ_FOREACH(lf, &linker_files, link) {
1334 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1335 (unsigned long)lf->size, lf->refs);
1342 * Filler function for proc/pid/fd
1345 linprocfs_dofdescfs(PFS_FILL_ARGS)
1349 sbuf_printf(sb, "/dev/fd");
1351 sbuf_printf(sb, "unknown");
1357 * Filler function for proc/sys/kernel/random/uuid
1360 linprocfs_douuid(PFS_FILL_ARGS)
1364 kern_uuidgen(&uuid, 1);
1365 sbuf_printf_uuid(sb, &uuid);
1366 sbuf_printf(sb, "\n");
1371 * Filler function for proc/pid/auxv
1374 linprocfs_doauxv(PFS_FILL_ARGS)
1377 off_t buflen, resid;
1381 * Mimic linux behavior and pass only processes with usermode
1382 * address space as valid. Return zero silently otherwise.
1384 if (p->p_vmspace == &vmspace0)
1387 if (uio->uio_resid == 0)
1389 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1392 asb = sbuf_new_auto();
1395 error = proc_getauxv(td, p, asb);
1397 error = sbuf_finish(asb);
1399 resid = sbuf_len(asb) - uio->uio_offset;
1400 if (resid > uio->uio_resid)
1401 buflen = uio->uio_resid;
1404 if (buflen > IOSIZE_MAX)
1406 if (buflen > MAXPHYS)
1412 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1421 linprocfs_init(PFS_INIT_ARGS)
1423 struct pfs_node *root;
1424 struct pfs_node *dir;
1429 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1430 NULL, NULL, NULL, PFS_RD);
1431 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1432 NULL, NULL, NULL, PFS_RD);
1433 pfs_create_file(root, "devices", &linprocfs_dodevices,
1434 NULL, NULL, NULL, PFS_RD);
1435 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1436 NULL, NULL, NULL, PFS_RD);
1437 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1438 NULL, NULL, NULL, PFS_RD);
1439 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1440 NULL, NULL, NULL, PFS_RD);
1442 pfs_create_file(root, "modules", &linprocfs_domodules,
1443 NULL, NULL, NULL, PFS_RD);
1445 pfs_create_file(root, "mounts", &linprocfs_domtab,
1446 NULL, NULL, NULL, PFS_RD);
1447 pfs_create_file(root, "mtab", &linprocfs_domtab,
1448 NULL, NULL, NULL, PFS_RD);
1449 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1450 NULL, NULL, NULL, PFS_RD);
1451 pfs_create_link(root, "self", &procfs_docurproc,
1452 NULL, NULL, NULL, 0);
1453 pfs_create_file(root, "stat", &linprocfs_dostat,
1454 NULL, NULL, NULL, PFS_RD);
1455 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1456 NULL, NULL, NULL, PFS_RD);
1457 pfs_create_file(root, "uptime", &linprocfs_douptime,
1458 NULL, NULL, NULL, PFS_RD);
1459 pfs_create_file(root, "version", &linprocfs_doversion,
1460 NULL, NULL, NULL, PFS_RD);
1463 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1464 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1465 NULL, NULL, NULL, PFS_RD);
1467 /* /proc/<pid>/... */
1468 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1469 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1470 NULL, NULL, NULL, PFS_RD);
1471 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1472 NULL, NULL, NULL, 0);
1473 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1474 NULL, &procfs_candebug, NULL, PFS_RD);
1475 pfs_create_link(dir, "exe", &procfs_doprocfile,
1476 NULL, &procfs_notsystem, NULL, 0);
1477 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1478 NULL, NULL, NULL, PFS_RD);
1479 pfs_create_file(dir, "mem", &procfs_doprocmem,
1480 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1481 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1482 NULL, NULL, NULL, 0);
1483 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1484 NULL, NULL, NULL, PFS_RD);
1485 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1486 NULL, NULL, NULL, PFS_RD);
1487 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1488 NULL, NULL, NULL, PFS_RD);
1489 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1490 NULL, NULL, NULL, 0);
1491 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1492 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1494 /* /proc/scsi/... */
1495 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1496 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1497 NULL, NULL, NULL, PFS_RD);
1498 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1499 NULL, NULL, NULL, PFS_RD);
1502 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1503 /* /proc/sys/kernel/... */
1504 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1505 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1506 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1508 NULL, NULL, NULL, PFS_RD);
1509 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1510 NULL, NULL, NULL, PFS_RD);
1511 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1512 NULL, NULL, NULL, PFS_RD);
1513 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1514 NULL, NULL, NULL, PFS_RD);
1515 pfs_create_file(dir, "sem", &linprocfs_dosem,
1516 NULL, NULL, NULL, PFS_RD);
1518 /* /proc/sys/kernel/random/... */
1519 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1520 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1521 NULL, NULL, NULL, PFS_RD);
1530 linprocfs_uninit(PFS_INIT_ARGS)
1533 /* nothing to do, pseudofs will GC */
1537 PSEUDOFS(linprocfs, 1, 0);
1538 #if defined(__amd64__)
1539 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1541 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1543 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1544 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1545 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);