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>
64 #include <sys/resource.h>
68 #include <sys/socket.h>
69 #include <sys/syscallsubr.h>
70 #include <sys/sysctl.h>
71 #include <sys/sysent.h>
72 #include <sys/systm.h>
77 #include <sys/vmmeter.h>
78 #include <sys/vnode.h>
82 #include <net/if_var.h>
83 #include <net/if_types.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 #include <compat/linux/linux.h>
104 #include <compat/linux/linux_mib.h>
105 #include <compat/linux/linux_misc.h>
106 #include <compat/linux/linux_util.h>
107 #include <fs/pseudofs/pseudofs.h>
108 #include <fs/procfs/procfs.h>
111 * Various conversion macros
113 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
114 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
115 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
116 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
117 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
118 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
119 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
120 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
123 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
125 * The linux procfs state field displays one of the characters RSDZTW to
126 * denote running, sleeping in an interruptible wait, waiting in an
127 * uninterruptible disk sleep, a zombie process, process is being traced
128 * or stopped, or process is paging respectively.
130 * Our struct kinfo_proc contains the variable ki_stat which contains a
131 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
133 * This character array is used with ki_stati-1 as an index and tries to
134 * map our states to suitable linux states.
136 static char linux_state[] = "RRSTZDD";
139 * Filler function for proc/meminfo
142 linprocfs_domeminfo(PFS_FILL_ARGS)
144 unsigned long memtotal; /* total memory in bytes */
145 unsigned long memused; /* used memory in bytes */
146 unsigned long memfree; /* free memory in bytes */
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 */
153 memtotal = physmem * PAGE_SIZE;
155 * The correct thing here would be:
157 memfree = vm_cnt.v_free_count * PAGE_SIZE;
158 memused = memtotal - memfree;
160 * but it might mislead linux binaries into thinking there
161 * is very little memory left, so we cheat and tell them that
162 * all memory that isn't wired down is free.
164 memused = vm_cnt.v_wire_count * PAGE_SIZE;
165 memfree = memtotal - memused;
166 swap_pager_status(&i, &j);
167 swaptotal = (unsigned long long)i * PAGE_SIZE;
168 swapused = (unsigned long long)j * PAGE_SIZE;
169 swapfree = swaptotal - swapused;
171 * We'd love to be able to write:
175 * but bufspace is internal to vfs_bio.c and we don't feel
176 * like unstaticizing it just for linprocfs's sake.
179 cached = vm_cnt.v_inactive_count * PAGE_SIZE;
182 "MemTotal: %9lu kB\n"
186 "SwapTotal:%9llu kB\n"
187 "SwapFree: %9llu kB\n",
188 B2K(memtotal), B2K(memfree), B2K(buffers),
189 B2K(cached), B2K(swaptotal), B2K(swapfree));
194 #if defined(__i386__) || defined(__amd64__)
196 * Filler function for proc/cpuinfo (i386 & amd64 version)
199 linprocfs_docpuinfo(PFS_FILL_ARGS)
209 * We default the flags to include all non-conflicting flags,
210 * and the Intel versions of conflicting flags.
212 static char *flags[] = {
213 "fpu", "vme", "de", "pse", "tsc",
214 "msr", "pae", "mce", "cx8", "apic",
215 "sep", "sep", "mtrr", "pge", "mca",
216 "cmov", "pat", "pse36", "pn", "b19",
217 "b20", "b21", "mmxext", "mmx", "fxsr",
218 "xmm", "sse2", "b27", "b28", "b29",
222 hw_model[0] = CTL_HW;
223 hw_model[1] = HW_MODEL;
225 size = sizeof(model);
226 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
227 strcpy(model, "unknown");
228 for (i = 0; i < mp_ncpus; ++i) {
231 "vendor_id\t: %.20s\n"
235 "stepping\t: %u\n\n",
236 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
237 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
238 /* XXX per-cpu vendor / class / model / id? */
241 sbuf_cat(sb, "flags\t\t:");
244 switch (cpu_vendor_id) {
246 if (cpu_class < CPUCLASS_686)
249 case CPU_VENDOR_CYRIX:
255 for (i = 0; i < 32; i++)
256 if (cpu_feature & (1 << i))
257 sbuf_printf(sb, " %s", flags[i]);
259 freq = atomic_load_acq_64(&tsc_freq);
261 fqmhz = (freq + 4999) / 1000000;
262 fqkhz = ((freq + 4999) / 10000) % 100;
264 "cpu MHz\t\t: %d.%02d\n"
265 "bogomips\t: %d.%02d\n",
266 fqmhz, fqkhz, fqmhz, fqkhz);
271 #endif /* __i386__ || __amd64__ */
274 * Filler function for proc/mtab
276 * This file doesn't exist in Linux' procfs, but is included here so
277 * users can symlink /compat/linux/etc/mtab to /proc/mtab
280 linprocfs_domtab(PFS_FILL_ARGS)
284 char *dlep, *flep, *mntto, *mntfrom, *fstype;
287 struct statfs *buf, *sp;
290 /* resolve symlinks etc. in the emulation tree prefix */
291 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
294 lep = linux_emul_path;
296 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
300 lep_len = strlen(lep);
303 error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
304 UIO_SYSSPACE, MNT_WAIT);
311 for (sp = buf; count > 0; sp++, count--) {
312 /* determine device name */
313 mntfrom = sp->f_mntfromname;
315 /* determine mount point */
316 mntto = sp->f_mntonname;
317 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
320 /* determine fs type */
321 fstype = sp->f_fstypename;
322 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
323 mntfrom = fstype = "proc";
324 else if (strcmp(fstype, "procfs") == 0)
327 if (strcmp(fstype, "linsysfs") == 0) {
328 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
329 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
331 /* For Linux msdosfs is called vfat */
332 if (strcmp(fstype, "msdosfs") == 0)
334 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
335 sp->f_flags & MNT_RDONLY ? "ro" : "rw");
337 #define ADD_OPTION(opt, name) \
338 if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
339 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
340 ADD_OPTION(MNT_NOEXEC, "noexec");
341 ADD_OPTION(MNT_NOSUID, "nosuid");
342 ADD_OPTION(MNT_UNION, "union");
343 ADD_OPTION(MNT_ASYNC, "async");
344 ADD_OPTION(MNT_SUIDDIR, "suiddir");
345 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
346 ADD_OPTION(MNT_NOATIME, "noatime");
348 /* a real Linux mtab will also show NFS options */
349 sbuf_printf(sb, " 0 0\n");
358 * Filler function for proc/partitions
361 linprocfs_dopartitions(PFS_FILL_ARGS)
365 struct g_provider *pp;
369 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
370 "ruse wio wmerge wsect wuse running use aveq\n");
372 LIST_FOREACH(cp, &g_classes, class) {
373 if (strcmp(cp->name, "DISK") == 0 ||
374 strcmp(cp->name, "PART") == 0)
375 LIST_FOREACH(gp, &cp->geom, geom) {
376 LIST_FOREACH(pp, &gp->provider, provider) {
377 if (linux_driver_get_major_minor(
378 pp->name, &major, &minor) != 0) {
382 sbuf_printf(sb, "%d %d %lld %s "
384 "%d %d %d %d %d %d\n",
386 (long long)pp->mediasize, pp->name,
399 * Filler function for proc/stat
402 linprocfs_dostat(PFS_FILL_ARGS)
405 long cp_time[CPUSTATES];
407 struct timeval boottime;
410 read_cpu_time(cp_time);
411 getboottime(&boottime);
412 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
413 T2J(cp_time[CP_USER]),
414 T2J(cp_time[CP_NICE]),
415 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
416 T2J(cp_time[CP_IDLE]));
419 cp = pcpu->pc_cp_time;
420 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
423 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
434 vm_cnt.v_vnodepgsout,
439 (long long)boottime.tv_sec);
444 linprocfs_doswaps(PFS_FILL_ARGS)
447 uintmax_t total, used;
449 char devname[SPECNAMELEN + 1];
451 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
453 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
455 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
456 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
459 * The space and not tab after the device name is on
460 * purpose. Linux does so.
462 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
463 devname, total, used);
469 * Filler function for proc/uptime
472 linprocfs_douptime(PFS_FILL_ARGS)
474 long cp_time[CPUSTATES];
478 read_cpu_time(cp_time);
479 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
480 (long long)tv.tv_sec, tv.tv_usec / 10000,
481 T2S(cp_time[CP_IDLE] / mp_ncpus),
482 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
490 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
496 strncpy(osbuild, version, 256);
498 cp1 = strstr(osbuild, "\n");
499 cp2 = strstr(osbuild, ":");
502 cp1 = strstr(osbuild, "#");
506 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
509 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
516 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
522 cp = strstr(version, "\n ");
524 strncpy(builder, cp + 5, 256);
526 cp = strstr(builder, ":");
531 sbuf_cat(sb, builder);
534 sbuf_cat(sb, "des@freebsd.org");
538 * Filler function for proc/version
541 linprocfs_doversion(PFS_FILL_ARGS)
543 char osname[LINUX_MAX_UTSNAME];
544 char osrelease[LINUX_MAX_UTSNAME];
546 linux_get_osname(td, osname);
547 linux_get_osrelease(td, osrelease);
548 sbuf_printf(sb, "%s version %s (", osname, osrelease);
549 linprocfs_osbuilder(td, sb);
550 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
551 linprocfs_osbuild(td, sb);
558 * Filler function for proc/loadavg
561 linprocfs_doloadavg(PFS_FILL_ARGS)
565 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
566 (int)(averunnable.ldavg[0] / averunnable.fscale),
567 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
568 (int)(averunnable.ldavg[1] / averunnable.fscale),
569 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
570 (int)(averunnable.ldavg[2] / averunnable.fscale),
571 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
572 1, /* number of running tasks */
573 nprocs, /* number of tasks */
574 lastpid /* the last pid */
580 * Filler function for proc/pid/stat
583 linprocfs_doprocstat(PFS_FILL_ARGS)
585 struct kinfo_proc kp;
586 struct timeval boottime;
588 static int ratelimit = 0;
589 vm_offset_t startcode, startdata;
591 getboottime(&boottime);
592 sx_slock(&proctree_lock);
594 fill_kinfo_proc(p, &kp);
595 sx_sunlock(&proctree_lock);
597 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
598 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
603 sbuf_printf(sb, "%d", p->p_pid);
604 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
605 PS_ADD("comm", "(%s)", p->p_comm);
606 if (kp.ki_stat > sizeof(linux_state)) {
609 if (ratelimit == 0) {
610 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
611 kp.ki_stat, sizeof(linux_state));
615 state = linux_state[kp.ki_stat - 1];
616 PS_ADD("state", "%c", state);
617 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
618 PS_ADD("pgrp", "%d", p->p_pgid);
619 PS_ADD("session", "%d", p->p_session->s_sid);
621 PS_ADD("tty", "%ju", (uintmax_t)kp.ki_tdev);
622 PS_ADD("tpgid", "%d", kp.ki_tpgid);
623 PS_ADD("flags", "%u", 0); /* XXX */
624 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
625 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
626 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
627 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
628 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
629 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
630 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
631 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
632 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
633 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
634 PS_ADD("0", "%d", 0); /* removed field */
635 PS_ADD("itrealvalue", "%d", 0); /* XXX */
636 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
637 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
638 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
639 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
640 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
641 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
642 PS_ADD("startstack", "%u", 0); /* XXX */
643 PS_ADD("kstkesp", "%u", 0); /* XXX */
644 PS_ADD("kstkeip", "%u", 0); /* XXX */
645 PS_ADD("signal", "%u", 0); /* XXX */
646 PS_ADD("blocked", "%u", 0); /* XXX */
647 PS_ADD("sigignore", "%u", 0); /* XXX */
648 PS_ADD("sigcatch", "%u", 0); /* XXX */
649 PS_ADD("wchan", "%u", 0); /* XXX */
650 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
651 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
652 PS_ADD("exitsignal", "%d", 0); /* XXX */
653 PS_ADD("processor", "%u", kp.ki_lastcpu);
654 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
655 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
663 * Filler function for proc/pid/statm
666 linprocfs_doprocstatm(PFS_FILL_ARGS)
668 struct kinfo_proc kp;
671 sx_slock(&proctree_lock);
673 fill_kinfo_proc(p, &kp);
675 sx_sunlock(&proctree_lock);
678 * See comments in linprocfs_doprocstatus() regarding the
679 * computation of lsize.
681 /* size resident share trs drs lrs dt */
682 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
683 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
684 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
685 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
686 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
687 lsize = B2P(kp.ki_size) - kp.ki_dsize -
688 kp.ki_ssize - kp.ki_tsize - 1;
689 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
690 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
696 * Filler function for proc/pid/status
699 linprocfs_doprocstatus(PFS_FILL_ARGS)
701 struct kinfo_proc kp;
706 l_sigset_t siglist, sigignore, sigcatch;
709 sx_slock(&proctree_lock);
711 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
713 if (P_SHOULDSTOP(p)) {
714 state = "T (stopped)";
721 if (p->p_flag & P_WEXIT) {
722 state = "X (exiting)";
725 switch(td2->td_state) {
727 state = "S (sleeping)";
731 state = "R (running)";
734 state = "? (unknown)";
739 state = "Z (zombie)";
742 state = "? (unknown)";
747 fill_kinfo_proc(p, &kp);
748 sx_sunlock(&proctree_lock);
750 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
751 sbuf_printf(sb, "State:\t%s\n", state);
756 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
757 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
758 p->p_pptr->p_pid : 0);
759 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
761 p->p_ucred->cr_svuid,
762 /* FreeBSD doesn't have fsuid */
764 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
766 p->p_ucred->cr_svgid,
767 /* FreeBSD doesn't have fsgid */
769 sbuf_cat(sb, "Groups:\t");
770 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
771 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
778 * While our approximation of VmLib may not be accurate (I
779 * don't know of a simple way to verify it, and I'm not sure
780 * it has much meaning anyway), I believe it's good enough.
782 * The same code that could (I think) accurately compute VmLib
783 * could also compute VmLck, but I don't really care enough to
784 * implement it. Submissions are welcome.
786 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
787 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
788 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
789 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
790 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
791 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
792 lsize = B2P(kp.ki_size) - kp.ki_dsize -
793 kp.ki_ssize - kp.ki_tsize - 1;
794 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
800 bsd_to_linux_sigset(&p->p_siglist, &siglist);
802 mtx_lock(&ps->ps_mtx);
803 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
804 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
805 mtx_unlock(&ps->ps_mtx);
808 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
810 * XXX. SigBlk - target thread's signal mask, td_sigmask.
811 * To implement SigBlk pseudofs should support proc/tid dir entries.
813 sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
814 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
815 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
818 * Linux also prints the capability masks, but we don't have
819 * capabilities yet, and when we do get them they're likely to
820 * be meaningless to Linux programs, so we lie. XXX
822 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
823 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
824 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
831 * Filler function for proc/pid/cwd
834 linprocfs_doproccwd(PFS_FILL_ARGS)
836 struct filedesc *fdp;
838 char *fullpath = "unknown";
839 char *freepath = NULL;
846 FILEDESC_SUNLOCK(fdp);
847 vn_fullpath(td, vp, &fullpath, &freepath);
850 sbuf_printf(sb, "%s", fullpath);
852 free(freepath, M_TEMP);
857 * Filler function for proc/pid/root
860 linprocfs_doprocroot(PFS_FILL_ARGS)
862 struct filedesc *fdp;
864 char *fullpath = "unknown";
865 char *freepath = NULL;
869 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
872 FILEDESC_SUNLOCK(fdp);
873 vn_fullpath(td, vp, &fullpath, &freepath);
876 sbuf_printf(sb, "%s", fullpath);
878 free(freepath, M_TEMP);
883 * Filler function for proc/pid/cmdline
886 linprocfs_doproccmdline(PFS_FILL_ARGS)
891 if ((ret = p_cansee(td, p)) != 0) {
897 * Mimic linux behavior and pass only processes with usermode
898 * address space as valid. Return zero silently otherwize.
900 if (p->p_vmspace == &vmspace0) {
904 if (p->p_args != NULL) {
905 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
910 if ((p->p_flag & P_SYSTEM) != 0) {
917 ret = proc_getargv(td, p, sb);
922 * Filler function for proc/pid/environ
925 linprocfs_doprocenviron(PFS_FILL_ARGS)
929 * Mimic linux behavior and pass only processes with usermode
930 * address space as valid. Return zero silently otherwize.
932 if (p->p_vmspace == &vmspace0)
935 return (proc_getenvv(td, p, sb));
938 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
939 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
940 static char vdso_str[] = " [vdso]";
941 static char stack_str[] = " [stack]";
944 * Filler function for proc/pid/maps
947 linprocfs_doprocmaps(PFS_FILL_ARGS)
951 vm_map_entry_t entry, tmp_entry;
952 vm_object_t obj, tobj, lobj;
953 vm_offset_t e_start, e_end;
954 vm_ooffset_t off = 0;
956 unsigned int last_timestamp;
957 char *name = "", *freename = NULL;
958 const char *l_map_str;
960 int ref_count, shadow_count, flags;
966 error = p_candebug(td, p);
971 if (uio->uio_rw != UIO_READ)
975 vm = vmspace_acquire_ref(p);
979 if (SV_CURPROC_FLAG(SV_LP64))
980 l_map_str = l64_map_str;
982 l_map_str = l32_map_str;
984 vm_map_lock_read(map);
985 for (entry = map->header.next; entry != &map->header;
986 entry = entry->next) {
989 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
991 e_prot = entry->protection;
992 e_start = entry->start;
994 obj = entry->object.vm_object;
995 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
996 VM_OBJECT_RLOCK(tobj);
998 VM_OBJECT_RUNLOCK(lobj);
1001 last_timestamp = map->timestamp;
1002 vm_map_unlock_read(map);
1005 off = IDX_TO_OFF(lobj->size);
1006 vp = vm_object_vnode(lobj);
1010 VM_OBJECT_RUNLOCK(lobj);
1012 ref_count = obj->ref_count;
1013 shadow_count = obj->shadow_count;
1014 VM_OBJECT_RUNLOCK(obj);
1016 vn_fullpath(td, vp, &name, &freename);
1017 vn_lock(vp, LK_SHARED | LK_RETRY);
1018 VOP_GETATTR(vp, &vat, td->td_ucred);
1019 ino = vat.va_fileid;
1021 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1022 if (e_start == p->p_sysent->sv_shared_page_base)
1024 if (e_end == p->p_sysent->sv_usrstack)
1035 * start, end, access, offset, major, minor, inode, name.
1037 error = sbuf_printf(sb, l_map_str,
1038 (u_long)e_start, (u_long)e_end,
1039 (e_prot & VM_PROT_READ)?"r":"-",
1040 (e_prot & VM_PROT_WRITE)?"w":"-",
1041 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1051 free(freename, M_TEMP);
1052 vm_map_lock_read(map);
1057 if (last_timestamp != map->timestamp) {
1059 * Look again for the entry because the map was
1060 * modified while it was unlocked. Specifically,
1061 * the entry may have been clipped, merged, or deleted.
1063 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1067 vm_map_unlock_read(map);
1074 * Criteria for interface name translation
1076 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1079 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1081 struct ifnet *ifscan;
1084 IFNET_RLOCK_ASSERT();
1086 /* Short-circuit non ethernet interfaces */
1087 if (!IFP_IS_ETH(ifp))
1088 return (strlcpy(buffer, ifp->if_xname, buflen));
1090 /* Determine the (relative) unit number for ethernet interfaces */
1092 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1094 return (snprintf(buffer, buflen, "eth%d", ethno));
1095 if (IFP_IS_ETH(ifscan))
1103 * Filler function for proc/net/dev
1106 linprocfs_donetdev(PFS_FILL_ARGS)
1108 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1111 sbuf_printf(sb, "%6s|%58s|%s\n"
1113 "Inter-", " Receive", " Transmit",
1115 "bytes packets errs drop fifo frame compressed multicast",
1116 "bytes packets errs drop fifo colls carrier compressed");
1118 CURVNET_SET(TD_TO_VNET(curthread));
1120 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1121 linux_ifname(ifp, ifname, sizeof ifname);
1122 sbuf_printf(sb, "%6.6s: ", ifname);
1123 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1124 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1125 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1126 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1127 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1128 /* rx_missed_errors */
1129 0UL, /* rx_fifo_errors */
1130 0UL, /* rx_length_errors +
1133 * rx_frame_errors */
1134 0UL, /* rx_compressed */
1135 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1136 /* XXX-BZ rx only? */
1137 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1138 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1139 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1140 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1141 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1142 0UL, /* tx_fifo_errors */
1143 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1144 0UL, /* tx_carrier_errors +
1145 * tx_aborted_errors +
1146 * tx_window_errors +
1147 * tx_heartbeat_errors*/
1148 0UL); /* tx_compressed */
1157 * Filler function for proc/sys/kernel/osrelease
1160 linprocfs_doosrelease(PFS_FILL_ARGS)
1162 char osrelease[LINUX_MAX_UTSNAME];
1164 linux_get_osrelease(td, osrelease);
1165 sbuf_printf(sb, "%s\n", osrelease);
1171 * Filler function for proc/sys/kernel/ostype
1174 linprocfs_doostype(PFS_FILL_ARGS)
1176 char osname[LINUX_MAX_UTSNAME];
1178 linux_get_osname(td, osname);
1179 sbuf_printf(sb, "%s\n", osname);
1185 * Filler function for proc/sys/kernel/version
1188 linprocfs_doosbuild(PFS_FILL_ARGS)
1191 linprocfs_osbuild(td, sb);
1197 * Filler function for proc/sys/kernel/msgmni
1200 linprocfs_domsgmni(PFS_FILL_ARGS)
1203 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1208 * Filler function for proc/sys/kernel/pid_max
1211 linprocfs_dopid_max(PFS_FILL_ARGS)
1214 sbuf_printf(sb, "%i\n", PID_MAX);
1219 * Filler function for proc/sys/kernel/sem
1222 linprocfs_dosem(PFS_FILL_ARGS)
1225 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1226 seminfo.semopm, seminfo.semmni);
1231 * Filler function for proc/scsi/device_info
1234 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1241 * Filler function for proc/scsi/scsi
1244 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1251 * Filler function for proc/devices
1254 linprocfs_dodevices(PFS_FILL_ARGS)
1257 sbuf_printf(sb, "Character devices:\n");
1259 char_devices = linux_get_char_devices();
1260 sbuf_printf(sb, "%s", char_devices);
1261 linux_free_get_char_devices(char_devices);
1263 sbuf_printf(sb, "\nBlock devices:\n");
1269 * Filler function for proc/cmdline
1272 linprocfs_docmdline(PFS_FILL_ARGS)
1275 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1276 sbuf_printf(sb, " ro root=302\n");
1281 * Filler function for proc/filesystems
1284 linprocfs_dofilesystems(PFS_FILL_ARGS)
1286 struct vfsconf *vfsp;
1289 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1290 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1291 sbuf_printf(sb, "nodev");
1292 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1300 * Filler function for proc/modules
1303 linprocfs_domodules(PFS_FILL_ARGS)
1305 struct linker_file *lf;
1307 TAILQ_FOREACH(lf, &linker_files, link) {
1308 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1309 (unsigned long)lf->size, lf->refs);
1316 * Filler function for proc/pid/fd
1319 linprocfs_dofdescfs(PFS_FILL_ARGS)
1323 sbuf_printf(sb, "/dev/fd");
1325 sbuf_printf(sb, "unknown");
1330 * Filler function for proc/pid/limits
1332 static const struct linux_rlimit_ident {
1335 unsigned int rlim_id;
1336 } linux_rlimits_ident[] = {
1337 { "Max cpu time", "seconds", RLIMIT_CPU },
1338 { "Max file size", "bytes", RLIMIT_FSIZE },
1339 { "Max data size", "bytes", RLIMIT_DATA },
1340 { "Max stack size", "bytes", RLIMIT_STACK },
1341 { "Max core file size", "bytes", RLIMIT_CORE },
1342 { "Max resident set", "bytes", RLIMIT_RSS },
1343 { "Max processes", "processes", RLIMIT_NPROC },
1344 { "Max open files", "files", RLIMIT_NOFILE },
1345 { "Max locked memory", "bytes", RLIMIT_MEMLOCK },
1346 { "Max address space", "bytes", RLIMIT_AS },
1347 { "Max file locks", "locks", LINUX_RLIMIT_LOCKS },
1348 { "Max pending signals", "signals", LINUX_RLIMIT_SIGPENDING },
1349 { "Max msgqueue size", "bytes", LINUX_RLIMIT_MSGQUEUE },
1350 { "Max nice priority", "", LINUX_RLIMIT_NICE },
1351 { "Max realtime priority", "", LINUX_RLIMIT_RTPRIO },
1352 { "Max realtime timeout", "us", LINUX_RLIMIT_RTTIME },
1357 linprocfs_doproclimits(PFS_FILL_ARGS)
1359 const struct linux_rlimit_ident *li;
1360 struct plimit *limp;
1368 limp = lim_hold(p->p_limit);
1371 sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1372 "Hard Limit", "Units");
1373 for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1374 switch (li->rlim_id)
1376 case LINUX_RLIMIT_LOCKS:
1378 case LINUX_RLIMIT_RTTIME:
1379 rl.rlim_cur = RLIM_INFINITY;
1381 case LINUX_RLIMIT_SIGPENDING:
1382 error = kernel_sysctlbyname(td,
1383 "kern.sigqueue.max_pending_per_proc",
1384 &res, &size, 0, 0, 0, 0);
1390 case LINUX_RLIMIT_MSGQUEUE:
1391 error = kernel_sysctlbyname(td,
1392 "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1398 case LINUX_RLIMIT_NICE:
1400 case LINUX_RLIMIT_RTPRIO:
1405 rl = limp->pl_rlimit[li->rlim_id];
1408 if (rl.rlim_cur == RLIM_INFINITY)
1409 sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1410 li->desc, "unlimited", "unlimited", li->unit);
1412 sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1413 li->desc, (unsigned long long)rl.rlim_cur,
1414 (unsigned long long)rl.rlim_max, li->unit);
1422 * Filler function for proc/sys/kernel/random/uuid
1425 linprocfs_douuid(PFS_FILL_ARGS)
1429 kern_uuidgen(&uuid, 1);
1430 sbuf_printf_uuid(sb, &uuid);
1431 sbuf_printf(sb, "\n");
1436 * Filler function for proc/pid/auxv
1439 linprocfs_doauxv(PFS_FILL_ARGS)
1442 off_t buflen, resid;
1446 * Mimic linux behavior and pass only processes with usermode
1447 * address space as valid. Return zero silently otherwise.
1449 if (p->p_vmspace == &vmspace0)
1452 if (uio->uio_resid == 0)
1454 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1457 asb = sbuf_new_auto();
1460 error = proc_getauxv(td, p, asb);
1462 error = sbuf_finish(asb);
1464 resid = sbuf_len(asb) - uio->uio_offset;
1465 if (resid > uio->uio_resid)
1466 buflen = uio->uio_resid;
1469 if (buflen > IOSIZE_MAX)
1471 if (buflen > MAXPHYS)
1477 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1486 linprocfs_init(PFS_INIT_ARGS)
1488 struct pfs_node *root;
1489 struct pfs_node *dir;
1494 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1495 NULL, NULL, NULL, PFS_RD);
1496 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1497 NULL, NULL, NULL, PFS_RD);
1498 pfs_create_file(root, "devices", &linprocfs_dodevices,
1499 NULL, NULL, NULL, PFS_RD);
1500 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1501 NULL, NULL, NULL, PFS_RD);
1502 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1503 NULL, NULL, NULL, PFS_RD);
1504 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1505 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_file(root, "modules", &linprocfs_domodules,
1508 NULL, NULL, NULL, PFS_RD);
1510 pfs_create_file(root, "mounts", &linprocfs_domtab,
1511 NULL, NULL, NULL, PFS_RD);
1512 pfs_create_file(root, "mtab", &linprocfs_domtab,
1513 NULL, NULL, NULL, PFS_RD);
1514 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1515 NULL, NULL, NULL, PFS_RD);
1516 pfs_create_link(root, "self", &procfs_docurproc,
1517 NULL, NULL, NULL, 0);
1518 pfs_create_file(root, "stat", &linprocfs_dostat,
1519 NULL, NULL, NULL, PFS_RD);
1520 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1521 NULL, NULL, NULL, PFS_RD);
1522 pfs_create_file(root, "uptime", &linprocfs_douptime,
1523 NULL, NULL, NULL, PFS_RD);
1524 pfs_create_file(root, "version", &linprocfs_doversion,
1525 NULL, NULL, NULL, PFS_RD);
1528 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1529 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1530 NULL, NULL, NULL, PFS_RD);
1532 /* /proc/<pid>/... */
1533 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1534 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1535 NULL, NULL, NULL, PFS_RD);
1536 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1537 NULL, NULL, NULL, 0);
1538 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1539 NULL, &procfs_candebug, NULL, PFS_RD);
1540 pfs_create_link(dir, "exe", &procfs_doprocfile,
1541 NULL, &procfs_notsystem, NULL, 0);
1542 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1543 NULL, NULL, NULL, PFS_RD);
1544 pfs_create_file(dir, "mem", &procfs_doprocmem,
1545 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1546 pfs_create_file(dir, "mounts", &linprocfs_domtab,
1547 NULL, NULL, NULL, PFS_RD);
1548 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1549 NULL, NULL, NULL, 0);
1550 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1551 NULL, NULL, NULL, PFS_RD);
1552 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1553 NULL, NULL, NULL, PFS_RD);
1554 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1555 NULL, NULL, NULL, PFS_RD);
1556 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1557 NULL, NULL, NULL, 0);
1558 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1559 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1560 pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1561 NULL, NULL, NULL, PFS_RD);
1563 /* /proc/scsi/... */
1564 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1565 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1566 NULL, NULL, NULL, PFS_RD);
1567 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1568 NULL, NULL, NULL, PFS_RD);
1571 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1572 /* /proc/sys/kernel/... */
1573 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1574 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1575 NULL, NULL, NULL, PFS_RD);
1576 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1577 NULL, NULL, NULL, PFS_RD);
1578 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1579 NULL, NULL, NULL, PFS_RD);
1580 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1581 NULL, NULL, NULL, PFS_RD);
1582 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1583 NULL, NULL, NULL, PFS_RD);
1584 pfs_create_file(dir, "sem", &linprocfs_dosem,
1585 NULL, NULL, NULL, PFS_RD);
1587 /* /proc/sys/kernel/random/... */
1588 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1589 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1590 NULL, NULL, NULL, PFS_RD);
1599 linprocfs_uninit(PFS_INIT_ARGS)
1602 /* nothing to do, pseudofs will GC */
1606 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1607 #if defined(__amd64__)
1608 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1610 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1612 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1613 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1614 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);