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/systm.h>
48 #include <sys/blist.h>
51 #include <sys/fcntl.h>
52 #include <sys/filedesc.h>
54 #include <sys/kernel.h>
55 #include <sys/limits.h>
56 #include <sys/linker.h>
58 #include <sys/malloc.h>
59 #include <sys/mount.h>
61 #include <sys/mutex.h>
62 #include <sys/namei.h>
64 #include <sys/ptrace.h>
65 #include <sys/resourcevar.h>
66 #include <sys/resource.h>
70 #include <sys/socket.h>
71 #include <sys/sysctl.h>
72 #include <sys/sysent.h>
73 #include <sys/systm.h>
78 #include <sys/vmmeter.h>
79 #include <sys/vnode.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 memshared; /* shared memory ??? */
148 unsigned long buffers, cached; /* buffer / cache memory ??? */
149 unsigned long long swaptotal; /* total swap space in bytes */
150 unsigned long long swapused; /* used swap space in bytes */
151 unsigned long long swapfree; /* free swap space in bytes */
155 memtotal = physmem * PAGE_SIZE;
157 * The correct thing here would be:
159 memfree = cnt.v_free_count * PAGE_SIZE;
160 memused = memtotal - memfree;
162 * but it might mislead linux binaries into thinking there
163 * is very little memory left, so we cheat and tell them that
164 * all memory that isn't wired down is free.
166 memused = cnt.v_wire_count * PAGE_SIZE;
167 memfree = memtotal - memused;
168 swap_pager_status(&i, &j);
169 swaptotal = (unsigned long long)i * PAGE_SIZE;
170 swapused = (unsigned long long)j * PAGE_SIZE;
171 swapfree = swaptotal - swapused;
173 mtx_lock(&vm_object_list_mtx);
174 TAILQ_FOREACH(object, &vm_object_list, object_list)
175 if (object->shadow_count > 1)
176 memshared += object->resident_page_count;
177 mtx_unlock(&vm_object_list_mtx);
178 memshared *= PAGE_SIZE;
180 * We'd love to be able to write:
184 * but bufspace is internal to vfs_bio.c and we don't feel
185 * like unstaticizing it just for linprocfs's sake.
188 cached = cnt.v_cache_count * PAGE_SIZE;
191 " total: used: free: shared: buffers: cached:\n"
192 "Mem: %lu %lu %lu %lu %lu %lu\n"
193 "Swap: %llu %llu %llu\n"
194 "MemTotal: %9lu kB\n"
196 "MemShared:%9lu kB\n"
199 "SwapTotal:%9llu kB\n"
200 "SwapFree: %9llu kB\n",
201 memtotal, memused, memfree, memshared, buffers, cached,
202 swaptotal, swapused, swapfree,
203 B2K(memtotal), B2K(memfree),
204 B2K(memshared), B2K(buffers), B2K(cached),
205 B2K(swaptotal), B2K(swapfree));
210 #if defined(__i386__) || defined(__amd64__)
212 * Filler function for proc/cpuinfo (i386 & amd64 version)
215 linprocfs_docpuinfo(PFS_FILL_ARGS)
221 int class, fqmhz, fqkhz;
225 * We default the flags to include all non-conflicting flags,
226 * and the Intel versions of conflicting flags.
228 static char *flags[] = {
229 "fpu", "vme", "de", "pse", "tsc",
230 "msr", "pae", "mce", "cx8", "apic",
231 "sep", "sep", "mtrr", "pge", "mca",
232 "cmov", "pat", "pse36", "pn", "b19",
233 "b20", "b21", "mmxext", "mmx", "fxsr",
234 "xmm", "sse2", "b27", "b28", "b29",
258 #else /* __amd64__ */
265 hw_model[0] = CTL_HW;
266 hw_model[1] = HW_MODEL;
268 size = sizeof(model);
269 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
270 strcpy(model, "unknown");
271 for (i = 0; i < mp_ncpus; ++i) {
274 "vendor_id\t: %.20s\n"
278 "stepping\t: %u\n\n",
279 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
280 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
281 /* XXX per-cpu vendor / class / model / id? */
284 sbuf_cat(sb, "flags\t\t:");
287 switch (cpu_vendor_id) {
292 case CPU_VENDOR_CYRIX:
298 for (i = 0; i < 32; i++)
299 if (cpu_feature & (1 << i))
300 sbuf_printf(sb, " %s", flags[i]);
302 freq = atomic_load_acq_64(&tsc_freq);
304 fqmhz = (freq + 4999) / 1000000;
305 fqkhz = ((freq + 4999) / 10000) % 100;
307 "cpu MHz\t\t: %d.%02d\n"
308 "bogomips\t: %d.%02d\n",
309 fqmhz, fqkhz, fqmhz, fqkhz);
314 #endif /* __i386__ || __amd64__ */
317 * Filler function for proc/mtab
319 * This file doesn't exist in Linux' procfs, but is included here so
320 * users can symlink /compat/linux/etc/mtab to /proc/mtab
323 linprocfs_domtab(PFS_FILL_ARGS)
328 char *dlep, *flep, *mntto, *mntfrom, *fstype;
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);
344 mtx_lock(&mountlist_mtx);
346 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
347 /* determine device name */
348 mntfrom = mp->mnt_stat.f_mntfromname;
350 /* determine mount point */
351 mntto = mp->mnt_stat.f_mntonname;
352 if (strncmp(mntto, lep, lep_len) == 0 &&
353 mntto[lep_len] == '/')
356 /* determine fs type */
357 fstype = mp->mnt_stat.f_fstypename;
358 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
359 mntfrom = fstype = "proc";
360 else if (strcmp(fstype, "procfs") == 0)
363 if (strcmp(fstype, "linsysfs") == 0) {
364 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
365 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
367 /* For Linux msdosfs is called vfat */
368 if (strcmp(fstype, "msdosfs") == 0)
370 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
371 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
373 #define ADD_OPTION(opt, name) \
374 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
375 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
376 ADD_OPTION(MNT_NOEXEC, "noexec");
377 ADD_OPTION(MNT_NOSUID, "nosuid");
378 ADD_OPTION(MNT_UNION, "union");
379 ADD_OPTION(MNT_ASYNC, "async");
380 ADD_OPTION(MNT_SUIDDIR, "suiddir");
381 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
382 ADD_OPTION(MNT_NOATIME, "noatime");
384 /* a real Linux mtab will also show NFS options */
385 sbuf_printf(sb, " 0 0\n");
387 mtx_unlock(&mountlist_mtx);
393 * Filler function for proc/partitions
396 linprocfs_dopartitions(PFS_FILL_ARGS)
400 struct g_provider *pp;
404 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
405 "ruse wio wmerge wsect wuse running use aveq\n");
407 LIST_FOREACH(cp, &g_classes, class) {
408 if (strcmp(cp->name, "DISK") == 0 ||
409 strcmp(cp->name, "PART") == 0)
410 LIST_FOREACH(gp, &cp->geom, geom) {
411 LIST_FOREACH(pp, &gp->provider, provider) {
412 if (linux_driver_get_major_minor(
413 pp->name, &major, &minor) != 0) {
417 sbuf_printf(sb, "%d %d %lld %s "
419 "%d %d %d %d %d %d\n",
421 (long long)pp->mediasize, pp->name,
434 * Filler function for proc/stat
437 linprocfs_dostat(PFS_FILL_ARGS)
440 long cp_time[CPUSTATES];
444 read_cpu_time(cp_time);
445 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
446 T2J(cp_time[CP_USER]),
447 T2J(cp_time[CP_NICE]),
448 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
449 T2J(cp_time[CP_IDLE]));
452 cp = pcpu->pc_cp_time;
453 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
456 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
472 (long long)boottime.tv_sec);
477 linprocfs_doswaps(PFS_FILL_ARGS)
480 uintmax_t total, used;
482 char devname[SPECNAMELEN + 1];
484 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
487 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
489 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
490 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
493 * The space and not tab after the device name is on
494 * purpose. Linux does so.
496 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
497 devname, total, used);
504 * Filler function for proc/uptime
507 linprocfs_douptime(PFS_FILL_ARGS)
509 long cp_time[CPUSTATES];
513 read_cpu_time(cp_time);
514 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
515 (long long)tv.tv_sec, tv.tv_usec / 10000,
516 T2S(cp_time[CP_IDLE] / mp_ncpus),
517 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
525 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
531 strncpy(osbuild, version, 256);
533 cp1 = strstr(osbuild, "\n");
534 cp2 = strstr(osbuild, ":");
537 cp1 = strstr(osbuild, "#");
541 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
544 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
551 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
557 cp = strstr(version, "\n ");
559 strncpy(builder, cp + 5, 256);
561 cp = strstr(builder, ":");
566 sbuf_cat(sb, builder);
569 sbuf_cat(sb, "des@freebsd.org");
573 * Filler function for proc/version
576 linprocfs_doversion(PFS_FILL_ARGS)
578 char osname[LINUX_MAX_UTSNAME];
579 char osrelease[LINUX_MAX_UTSNAME];
581 linux_get_osname(td, osname);
582 linux_get_osrelease(td, osrelease);
583 sbuf_printf(sb, "%s version %s (", osname, osrelease);
584 linprocfs_osbuilder(td, sb);
585 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
586 linprocfs_osbuild(td, sb);
593 * Filler function for proc/loadavg
596 linprocfs_doloadavg(PFS_FILL_ARGS)
600 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
601 (int)(averunnable.ldavg[0] / averunnable.fscale),
602 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
603 (int)(averunnable.ldavg[1] / averunnable.fscale),
604 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
605 (int)(averunnable.ldavg[2] / averunnable.fscale),
606 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
607 1, /* number of running tasks */
608 nprocs, /* number of tasks */
609 lastpid /* the last pid */
615 * Filler function for proc/pid/stat
618 linprocfs_doprocstat(PFS_FILL_ARGS)
620 struct kinfo_proc kp;
622 static int ratelimit = 0;
623 vm_offset_t startcode, startdata;
626 fill_kinfo_proc(p, &kp);
628 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
629 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
634 sbuf_printf(sb, "%d", p->p_pid);
635 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
636 PS_ADD("comm", "(%s)", p->p_comm);
637 if (kp.ki_stat > sizeof(linux_state)) {
640 if (ratelimit == 0) {
641 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
642 kp.ki_stat, sizeof(linux_state));
646 state = linux_state[kp.ki_stat - 1];
647 PS_ADD("state", "%c", state);
648 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
649 PS_ADD("pgrp", "%d", p->p_pgid);
650 PS_ADD("session", "%d", p->p_session->s_sid);
652 PS_ADD("tty", "%d", kp.ki_tdev);
653 PS_ADD("tpgid", "%d", kp.ki_tpgid);
654 PS_ADD("flags", "%u", 0); /* XXX */
655 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
656 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
657 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
658 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
659 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
660 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
661 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
662 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
663 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
664 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
665 PS_ADD("0", "%d", 0); /* removed field */
666 PS_ADD("itrealvalue", "%d", 0); /* XXX */
667 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
668 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
669 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
670 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
671 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
672 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
673 PS_ADD("startstack", "%u", 0); /* XXX */
674 PS_ADD("kstkesp", "%u", 0); /* XXX */
675 PS_ADD("kstkeip", "%u", 0); /* XXX */
676 PS_ADD("signal", "%u", 0); /* XXX */
677 PS_ADD("blocked", "%u", 0); /* XXX */
678 PS_ADD("sigignore", "%u", 0); /* XXX */
679 PS_ADD("sigcatch", "%u", 0); /* XXX */
680 PS_ADD("wchan", "%u", 0); /* XXX */
681 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
682 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
683 PS_ADD("exitsignal", "%d", 0); /* XXX */
684 PS_ADD("processor", "%u", kp.ki_lastcpu);
685 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
686 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
694 * Filler function for proc/pid/statm
697 linprocfs_doprocstatm(PFS_FILL_ARGS)
699 struct kinfo_proc kp;
703 fill_kinfo_proc(p, &kp);
707 * See comments in linprocfs_doprocstatus() regarding the
708 * computation of lsize.
710 /* size resident share trs drs lrs dt */
711 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
712 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
713 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
714 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
715 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
716 lsize = B2P(kp.ki_size) - kp.ki_dsize -
717 kp.ki_ssize - kp.ki_tsize - 1;
718 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
719 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
725 * Filler function for proc/pid/status
728 linprocfs_doprocstatus(PFS_FILL_ARGS)
730 struct kinfo_proc kp;
735 l_sigset_t siglist, sigignore, sigcatch;
739 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
741 if (P_SHOULDSTOP(p)) {
742 state = "T (stopped)";
749 if (p->p_flag & P_WEXIT) {
750 state = "X (exiting)";
753 switch(td2->td_state) {
755 state = "S (sleeping)";
759 state = "R (running)";
762 state = "? (unknown)";
767 state = "Z (zombie)";
770 state = "? (unknown)";
775 fill_kinfo_proc(p, &kp);
776 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
777 sbuf_printf(sb, "State:\t%s\n", state);
782 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
783 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
784 p->p_pptr->p_pid : 0);
785 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
787 p->p_ucred->cr_svuid,
788 /* FreeBSD doesn't have fsuid */
790 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
792 p->p_ucred->cr_svgid,
793 /* FreeBSD doesn't have fsgid */
795 sbuf_cat(sb, "Groups:\t");
796 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
797 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
804 * While our approximation of VmLib may not be accurate (I
805 * don't know of a simple way to verify it, and I'm not sure
806 * it has much meaning anyway), I believe it's good enough.
808 * The same code that could (I think) accurately compute VmLib
809 * could also compute VmLck, but I don't really care enough to
810 * implement it. Submissions are welcome.
812 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
813 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
814 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
815 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
816 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
817 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
818 lsize = B2P(kp.ki_size) - kp.ki_dsize -
819 kp.ki_ssize - kp.ki_tsize - 1;
820 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
826 bsd_to_linux_sigset(&p->p_siglist, &siglist);
828 mtx_lock(&ps->ps_mtx);
829 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
830 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
831 mtx_unlock(&ps->ps_mtx);
834 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
836 * XXX. SigBlk - target thread's signal mask, td_sigmask.
837 * To implement SigBlk pseudofs should support proc/tid dir entries.
839 sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
840 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
841 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
844 * Linux also prints the capability masks, but we don't have
845 * capabilities yet, and when we do get them they're likely to
846 * be meaningless to Linux programs, so we lie. XXX
848 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
849 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
850 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
857 * Filler function for proc/pid/cwd
860 linprocfs_doproccwd(PFS_FILL_ARGS)
862 struct filedesc *fdp;
864 char *fullpath = "unknown";
865 char *freepath = NULL;
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/root
886 linprocfs_doprocroot(PFS_FILL_ARGS)
888 struct filedesc *fdp;
890 char *fullpath = "unknown";
891 char *freepath = NULL;
895 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
898 FILEDESC_SUNLOCK(fdp);
899 vn_fullpath(td, vp, &fullpath, &freepath);
902 sbuf_printf(sb, "%s", fullpath);
904 free(freepath, M_TEMP);
909 * Filler function for proc/pid/cmdline
912 linprocfs_doproccmdline(PFS_FILL_ARGS)
917 if ((ret = p_cansee(td, p)) != 0) {
923 * Mimic linux behavior and pass only processes with usermode
924 * address space as valid. Return zero silently otherwize.
926 if (p->p_vmspace == &vmspace0) {
930 if (p->p_args != NULL) {
931 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
936 if ((p->p_flag & P_SYSTEM) != 0) {
943 ret = proc_getargv(td, p, sb);
948 * Filler function for proc/pid/environ
951 linprocfs_doprocenviron(PFS_FILL_ARGS)
955 * Mimic linux behavior and pass only processes with usermode
956 * address space as valid. Return zero silently otherwize.
958 if (p->p_vmspace == &vmspace0)
961 return (proc_getenvv(td, p, sb));
964 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
965 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
966 static char vdso_str[] = " [vdso]";
967 static char stack_str[] = " [stack]";
970 * Filler function for proc/pid/maps
973 linprocfs_doprocmaps(PFS_FILL_ARGS)
977 vm_map_entry_t entry, tmp_entry;
978 vm_object_t obj, tobj, lobj;
979 vm_offset_t e_start, e_end;
980 vm_ooffset_t off = 0;
982 unsigned int last_timestamp;
983 char *name = "", *freename = NULL;
984 const char *l_map_str;
986 int ref_count, shadow_count, flags;
992 error = p_candebug(td, p);
997 if (uio->uio_rw != UIO_READ)
1001 vm = vmspace_acquire_ref(p);
1005 if (SV_CURPROC_FLAG(SV_LP64))
1006 l_map_str = l64_map_str;
1008 l_map_str = l32_map_str;
1010 vm_map_lock_read(map);
1011 for (entry = map->header.next; entry != &map->header;
1012 entry = entry->next) {
1015 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1017 e_prot = entry->protection;
1018 e_start = entry->start;
1020 obj = entry->object.vm_object;
1021 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1022 VM_OBJECT_RLOCK(tobj);
1024 VM_OBJECT_RUNLOCK(lobj);
1027 last_timestamp = map->timestamp;
1028 vm_map_unlock_read(map);
1031 off = IDX_TO_OFF(lobj->size);
1032 vp = vm_object_vnode(lobj);
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, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1150 ifp->if_ibytes, /* rx_bytes */
1151 ifp->if_ipackets, /* rx_packets */
1152 ifp->if_ierrors, /* rx_errors */
1153 ifp->if_iqdrops, /* rx_dropped +
1154 * rx_missed_errors */
1155 0UL, /* rx_fifo_errors */
1156 0UL, /* rx_length_errors +
1159 * rx_frame_errors */
1160 0UL, /* rx_compressed */
1161 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1162 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1163 ifp->if_obytes, /* tx_bytes */
1164 ifp->if_opackets, /* tx_packets */
1165 ifp->if_oerrors, /* tx_errors */
1166 0UL, /* tx_dropped */
1167 0UL, /* tx_fifo_errors */
1168 ifp->if_collisions, /* collisions */
1169 0UL, /* tx_carrier_errors +
1170 * tx_aborted_errors +
1171 * tx_window_errors +
1172 * tx_heartbeat_errors */
1173 0UL); /* tx_compressed */
1182 * Filler function for proc/sys/kernel/osrelease
1185 linprocfs_doosrelease(PFS_FILL_ARGS)
1187 char osrelease[LINUX_MAX_UTSNAME];
1189 linux_get_osrelease(td, osrelease);
1190 sbuf_printf(sb, "%s\n", osrelease);
1196 * Filler function for proc/sys/kernel/ostype
1199 linprocfs_doostype(PFS_FILL_ARGS)
1201 char osname[LINUX_MAX_UTSNAME];
1203 linux_get_osname(td, osname);
1204 sbuf_printf(sb, "%s\n", osname);
1210 * Filler function for proc/sys/kernel/version
1213 linprocfs_doosbuild(PFS_FILL_ARGS)
1216 linprocfs_osbuild(td, sb);
1222 * Filler function for proc/sys/kernel/msgmni
1225 linprocfs_domsgmni(PFS_FILL_ARGS)
1228 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1233 * Filler function for proc/sys/kernel/pid_max
1236 linprocfs_dopid_max(PFS_FILL_ARGS)
1239 sbuf_printf(sb, "%i\n", PID_MAX);
1244 * Filler function for proc/sys/kernel/sem
1247 linprocfs_dosem(PFS_FILL_ARGS)
1250 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1251 seminfo.semopm, seminfo.semmni);
1256 * Filler function for proc/scsi/device_info
1259 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1266 * Filler function for proc/scsi/scsi
1269 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1276 * Filler function for proc/devices
1279 linprocfs_dodevices(PFS_FILL_ARGS)
1282 sbuf_printf(sb, "Character devices:\n");
1284 char_devices = linux_get_char_devices();
1285 sbuf_printf(sb, "%s", char_devices);
1286 linux_free_get_char_devices(char_devices);
1288 sbuf_printf(sb, "\nBlock devices:\n");
1294 * Filler function for proc/cmdline
1297 linprocfs_docmdline(PFS_FILL_ARGS)
1300 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1301 sbuf_printf(sb, " ro root=302\n");
1306 * Filler function for proc/filesystems
1309 linprocfs_dofilesystems(PFS_FILL_ARGS)
1311 struct vfsconf *vfsp;
1314 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1315 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1316 sbuf_printf(sb, "nodev");
1317 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1325 * Filler function for proc/modules
1328 linprocfs_domodules(PFS_FILL_ARGS)
1330 struct linker_file *lf;
1332 TAILQ_FOREACH(lf, &linker_files, link) {
1333 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1334 (unsigned long)lf->size, lf->refs);
1341 * Filler function for proc/pid/fd
1344 linprocfs_dofdescfs(PFS_FILL_ARGS)
1348 sbuf_printf(sb, "/dev/fd");
1350 sbuf_printf(sb, "unknown");
1355 * Filler function for proc/pid/limits
1357 static const struct linux_rlimit_ident {
1360 unsigned int rlim_id;
1361 } linux_rlimits_ident[] = {
1362 { "Max cpu time", "seconds", RLIMIT_CPU },
1363 { "Max file size", "bytes", RLIMIT_FSIZE },
1364 { "Max data size", "bytes", RLIMIT_DATA },
1365 { "Max stack size", "bytes", RLIMIT_STACK },
1366 { "Max core file size", "bytes", RLIMIT_CORE },
1367 { "Max resident set", "bytes", RLIMIT_RSS },
1368 { "Max processes", "processes", RLIMIT_NPROC },
1369 { "Max open files", "files", RLIMIT_NOFILE },
1370 { "Max locked memory", "bytes", RLIMIT_MEMLOCK },
1371 { "Max address space", "bytes", RLIMIT_AS },
1372 { "Max file locks", "locks", LINUX_RLIMIT_LOCKS },
1373 { "Max pending signals", "signals", LINUX_RLIMIT_SIGPENDING },
1374 { "Max msgqueue size", "bytes", LINUX_RLIMIT_MSGQUEUE },
1375 { "Max nice priority", "", LINUX_RLIMIT_NICE },
1376 { "Max realtime priority", "", LINUX_RLIMIT_RTPRIO },
1377 { "Max realtime timeout", "us", LINUX_RLIMIT_RTTIME },
1382 linprocfs_doproclimits(PFS_FILL_ARGS)
1384 const struct linux_rlimit_ident *li;
1385 struct plimit *limp;
1393 limp = lim_hold(p->p_limit);
1396 sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1397 "Hard Limit", "Units");
1398 for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1399 switch (li->rlim_id)
1401 case LINUX_RLIMIT_LOCKS:
1403 case LINUX_RLIMIT_RTTIME:
1404 rl.rlim_cur = RLIM_INFINITY;
1406 case LINUX_RLIMIT_SIGPENDING:
1407 error = kernel_sysctlbyname(td,
1408 "kern.sigqueue.max_pending_per_proc",
1409 &res, &size, 0, 0, 0, 0);
1415 case LINUX_RLIMIT_MSGQUEUE:
1416 error = kernel_sysctlbyname(td,
1417 "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1423 case LINUX_RLIMIT_NICE:
1425 case LINUX_RLIMIT_RTPRIO:
1430 rl = limp->pl_rlimit[li->rlim_id];
1433 if (rl.rlim_cur == RLIM_INFINITY)
1434 sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1435 li->desc, "unlimited", "unlimited", li->unit);
1437 sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1438 li->desc, (unsigned long long)rl.rlim_cur,
1439 (unsigned long long)rl.rlim_max, li->unit);
1447 * Filler function for proc/sys/kernel/random/uuid
1450 linprocfs_douuid(PFS_FILL_ARGS)
1454 kern_uuidgen(&uuid, 1);
1455 sbuf_printf_uuid(sb, &uuid);
1456 sbuf_printf(sb, "\n");
1461 * Filler function for proc/pid/auxv
1464 linprocfs_doauxv(PFS_FILL_ARGS)
1467 off_t buflen, resid;
1471 * Mimic linux behavior and pass only processes with usermode
1472 * address space as valid. Return zero silently otherwise.
1474 if (p->p_vmspace == &vmspace0)
1477 if (uio->uio_resid == 0)
1479 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1482 asb = sbuf_new_auto();
1485 error = proc_getauxv(td, p, asb);
1487 error = sbuf_finish(asb);
1489 resid = sbuf_len(asb) - uio->uio_offset;
1490 if (resid > uio->uio_resid)
1491 buflen = uio->uio_resid;
1494 if (buflen > IOSIZE_MAX)
1496 if (buflen > MAXPHYS)
1502 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1511 linprocfs_init(PFS_INIT_ARGS)
1513 struct pfs_node *root;
1514 struct pfs_node *dir;
1519 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1520 NULL, NULL, NULL, PFS_RD);
1521 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1522 NULL, NULL, NULL, PFS_RD);
1523 pfs_create_file(root, "devices", &linprocfs_dodevices,
1524 NULL, NULL, NULL, PFS_RD);
1525 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1526 NULL, NULL, NULL, PFS_RD);
1527 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1528 NULL, NULL, NULL, PFS_RD);
1529 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1530 NULL, NULL, NULL, PFS_RD);
1532 pfs_create_file(root, "modules", &linprocfs_domodules,
1533 NULL, NULL, NULL, PFS_RD);
1535 pfs_create_file(root, "mounts", &linprocfs_domtab,
1536 NULL, NULL, NULL, PFS_RD);
1537 pfs_create_file(root, "mtab", &linprocfs_domtab,
1538 NULL, NULL, NULL, PFS_RD);
1539 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1540 NULL, NULL, NULL, PFS_RD);
1541 pfs_create_link(root, "self", &procfs_docurproc,
1542 NULL, NULL, NULL, 0);
1543 pfs_create_file(root, "stat", &linprocfs_dostat,
1544 NULL, NULL, NULL, PFS_RD);
1545 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1546 NULL, NULL, NULL, PFS_RD);
1547 pfs_create_file(root, "uptime", &linprocfs_douptime,
1548 NULL, NULL, NULL, PFS_RD);
1549 pfs_create_file(root, "version", &linprocfs_doversion,
1550 NULL, NULL, NULL, PFS_RD);
1553 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1554 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1555 NULL, NULL, NULL, PFS_RD);
1557 /* /proc/<pid>/... */
1558 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1559 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1560 NULL, NULL, NULL, PFS_RD);
1561 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1562 NULL, NULL, NULL, 0);
1563 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1564 NULL, &procfs_candebug, NULL, PFS_RD);
1565 pfs_create_link(dir, "exe", &procfs_doprocfile,
1566 NULL, &procfs_notsystem, NULL, 0);
1567 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1568 NULL, NULL, NULL, PFS_RD);
1569 pfs_create_file(dir, "mem", &procfs_doprocmem,
1570 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1571 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1572 NULL, NULL, NULL, 0);
1573 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1574 NULL, NULL, NULL, PFS_RD);
1575 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1576 NULL, NULL, NULL, PFS_RD);
1577 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1578 NULL, NULL, NULL, PFS_RD);
1579 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1580 NULL, NULL, NULL, 0);
1581 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1582 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1583 pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1584 NULL, NULL, NULL, PFS_RD);
1586 /* /proc/scsi/... */
1587 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1588 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1589 NULL, NULL, NULL, PFS_RD);
1590 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1591 NULL, NULL, NULL, PFS_RD);
1594 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1595 /* /proc/sys/kernel/... */
1596 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1597 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1598 NULL, NULL, NULL, PFS_RD);
1599 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1600 NULL, NULL, NULL, PFS_RD);
1601 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1602 NULL, NULL, NULL, PFS_RD);
1603 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1604 NULL, NULL, NULL, PFS_RD);
1605 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1606 NULL, NULL, NULL, PFS_RD);
1607 pfs_create_file(dir, "sem", &linprocfs_dosem,
1608 NULL, NULL, NULL, PFS_RD);
1610 /* /proc/sys/kernel/random/... */
1611 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1612 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1613 NULL, NULL, NULL, PFS_RD);
1622 linprocfs_uninit(PFS_INIT_ARGS)
1625 /* nothing to do, pseudofs will GC */
1629 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1630 #if defined(__amd64__)
1631 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1633 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1635 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1636 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1637 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);