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>
69 #include <sys/socket.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_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 = 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 = 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 = 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)
327 char *dlep, *flep, *mntto, *mntfrom, *fstype;
331 /* resolve symlinks etc. in the emulation tree prefix */
332 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
335 lep = linux_emul_path;
337 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
341 lep_len = strlen(lep);
343 mtx_lock(&mountlist_mtx);
345 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
346 /* determine device name */
347 mntfrom = mp->mnt_stat.f_mntfromname;
349 /* determine mount point */
350 mntto = mp->mnt_stat.f_mntonname;
351 if (strncmp(mntto, lep, lep_len) == 0 &&
352 mntto[lep_len] == '/')
355 /* determine fs type */
356 fstype = mp->mnt_stat.f_fstypename;
357 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
358 mntfrom = fstype = "proc";
359 else if (strcmp(fstype, "procfs") == 0)
362 if (strcmp(fstype, "linsysfs") == 0) {
363 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
364 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
366 /* For Linux msdosfs is called vfat */
367 if (strcmp(fstype, "msdosfs") == 0)
369 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
370 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
372 #define ADD_OPTION(opt, name) \
373 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
374 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
375 ADD_OPTION(MNT_NOEXEC, "noexec");
376 ADD_OPTION(MNT_NOSUID, "nosuid");
377 ADD_OPTION(MNT_UNION, "union");
378 ADD_OPTION(MNT_ASYNC, "async");
379 ADD_OPTION(MNT_SUIDDIR, "suiddir");
380 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
381 ADD_OPTION(MNT_NOATIME, "noatime");
383 /* a real Linux mtab will also show NFS options */
384 sbuf_printf(sb, " 0 0\n");
386 mtx_unlock(&mountlist_mtx);
392 * Filler function for proc/partitions
395 linprocfs_dopartitions(PFS_FILL_ARGS)
399 struct g_provider *pp;
403 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
404 "ruse wio wmerge wsect wuse running use aveq\n");
406 LIST_FOREACH(cp, &g_classes, class) {
407 if (strcmp(cp->name, "DISK") == 0 ||
408 strcmp(cp->name, "PART") == 0)
409 LIST_FOREACH(gp, &cp->geom, geom) {
410 LIST_FOREACH(pp, &gp->provider, provider) {
411 if (linux_driver_get_major_minor(
412 pp->name, &major, &minor) != 0) {
416 sbuf_printf(sb, "%d %d %lld %s "
418 "%d %d %d %d %d %d\n",
420 (long long)pp->mediasize, pp->name,
433 * Filler function for proc/stat
436 linprocfs_dostat(PFS_FILL_ARGS)
439 long cp_time[CPUSTATES];
443 read_cpu_time(cp_time);
444 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
445 T2J(cp_time[CP_USER]),
446 T2J(cp_time[CP_NICE]),
447 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
448 T2J(cp_time[CP_IDLE]));
451 cp = pcpu->pc_cp_time;
452 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
455 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
471 (long long)boottime.tv_sec);
476 linprocfs_doswaps(PFS_FILL_ARGS)
479 uintmax_t total, used;
481 char devname[SPECNAMELEN + 1];
483 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
486 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
488 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
489 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
492 * The space and not tab after the device name is on
493 * purpose. Linux does so.
495 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
496 devname, total, used);
503 * Filler function for proc/uptime
506 linprocfs_douptime(PFS_FILL_ARGS)
508 long cp_time[CPUSTATES];
512 read_cpu_time(cp_time);
513 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
514 (long long)tv.tv_sec, tv.tv_usec / 10000,
515 T2S(cp_time[CP_IDLE] / mp_ncpus),
516 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
524 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
530 strncpy(osbuild, version, 256);
532 cp1 = strstr(osbuild, "\n");
533 cp2 = strstr(osbuild, ":");
536 cp1 = strstr(osbuild, "#");
540 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
543 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
550 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
556 cp = strstr(version, "\n ");
558 strncpy(builder, cp + 5, 256);
560 cp = strstr(builder, ":");
565 sbuf_cat(sb, builder);
568 sbuf_cat(sb, "des@freebsd.org");
572 * Filler function for proc/version
575 linprocfs_doversion(PFS_FILL_ARGS)
577 char osname[LINUX_MAX_UTSNAME];
578 char osrelease[LINUX_MAX_UTSNAME];
580 linux_get_osname(td, osname);
581 linux_get_osrelease(td, osrelease);
582 sbuf_printf(sb, "%s version %s (", osname, osrelease);
583 linprocfs_osbuilder(td, sb);
584 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
585 linprocfs_osbuild(td, sb);
592 * Filler function for proc/loadavg
595 linprocfs_doloadavg(PFS_FILL_ARGS)
599 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
600 (int)(averunnable.ldavg[0] / averunnable.fscale),
601 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
602 (int)(averunnable.ldavg[1] / averunnable.fscale),
603 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
604 (int)(averunnable.ldavg[2] / averunnable.fscale),
605 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
606 1, /* number of running tasks */
607 nprocs, /* number of tasks */
608 lastpid /* the last pid */
614 * Filler function for proc/pid/stat
617 linprocfs_doprocstat(PFS_FILL_ARGS)
619 struct kinfo_proc kp;
621 static int ratelimit = 0;
622 vm_offset_t startcode, startdata;
625 fill_kinfo_proc(p, &kp);
627 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
628 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
633 sbuf_printf(sb, "%d", p->p_pid);
634 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
635 PS_ADD("comm", "(%s)", p->p_comm);
636 if (kp.ki_stat > sizeof(linux_state)) {
639 if (ratelimit == 0) {
640 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
641 kp.ki_stat, sizeof(linux_state));
645 state = linux_state[kp.ki_stat - 1];
646 PS_ADD("state", "%c", state);
647 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
648 PS_ADD("pgrp", "%d", p->p_pgid);
649 PS_ADD("session", "%d", p->p_session->s_sid);
651 PS_ADD("tty", "%d", kp.ki_tdev);
652 PS_ADD("tpgid", "%d", kp.ki_tpgid);
653 PS_ADD("flags", "%u", 0); /* XXX */
654 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
655 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
656 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
657 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
658 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
659 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
660 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
661 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
662 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
663 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
664 PS_ADD("0", "%d", 0); /* removed field */
665 PS_ADD("itrealvalue", "%d", 0); /* XXX */
666 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
667 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
668 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
669 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
670 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
671 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
672 PS_ADD("startstack", "%u", 0); /* XXX */
673 PS_ADD("kstkesp", "%u", 0); /* XXX */
674 PS_ADD("kstkeip", "%u", 0); /* XXX */
675 PS_ADD("signal", "%u", 0); /* XXX */
676 PS_ADD("blocked", "%u", 0); /* XXX */
677 PS_ADD("sigignore", "%u", 0); /* XXX */
678 PS_ADD("sigcatch", "%u", 0); /* XXX */
679 PS_ADD("wchan", "%u", 0); /* XXX */
680 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
681 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
682 PS_ADD("exitsignal", "%d", 0); /* XXX */
683 PS_ADD("processor", "%u", kp.ki_lastcpu);
684 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
685 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
693 * Filler function for proc/pid/statm
696 linprocfs_doprocstatm(PFS_FILL_ARGS)
698 struct kinfo_proc kp;
702 fill_kinfo_proc(p, &kp);
706 * See comments in linprocfs_doprocstatus() regarding the
707 * computation of lsize.
709 /* size resident share trs drs lrs dt */
710 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
711 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
712 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
713 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
714 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
715 lsize = B2P(kp.ki_size) - kp.ki_dsize -
716 kp.ki_ssize - kp.ki_tsize - 1;
717 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
718 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
724 * Filler function for proc/pid/status
727 linprocfs_doprocstatus(PFS_FILL_ARGS)
729 struct kinfo_proc kp;
734 l_sigset_t siglist, sigignore, sigcatch;
738 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
740 if (P_SHOULDSTOP(p)) {
741 state = "T (stopped)";
748 if (p->p_flag & P_WEXIT) {
749 state = "X (exiting)";
752 switch(td2->td_state) {
754 state = "S (sleeping)";
758 state = "R (running)";
761 state = "? (unknown)";
766 state = "Z (zombie)";
769 state = "? (unknown)";
774 fill_kinfo_proc(p, &kp);
775 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
776 sbuf_printf(sb, "State:\t%s\n", state);
781 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
782 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
783 p->p_pptr->p_pid : 0);
784 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
786 p->p_ucred->cr_svuid,
787 /* FreeBSD doesn't have fsuid */
789 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
791 p->p_ucred->cr_svgid,
792 /* FreeBSD doesn't have fsgid */
794 sbuf_cat(sb, "Groups:\t");
795 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
796 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
803 * While our approximation of VmLib may not be accurate (I
804 * don't know of a simple way to verify it, and I'm not sure
805 * it has much meaning anyway), I believe it's good enough.
807 * The same code that could (I think) accurately compute VmLib
808 * could also compute VmLck, but I don't really care enough to
809 * implement it. Submissions are welcome.
811 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
812 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
813 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
814 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
815 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
816 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
817 lsize = B2P(kp.ki_size) - kp.ki_dsize -
818 kp.ki_ssize - kp.ki_tsize - 1;
819 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
825 bsd_to_linux_sigset(&p->p_siglist, &siglist);
827 mtx_lock(&ps->ps_mtx);
828 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
829 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
830 mtx_unlock(&ps->ps_mtx);
833 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
835 * XXX. SigBlk - target thread's signal mask, td_sigmask.
836 * To implement SigBlk pseudofs should support proc/tid dir entries.
838 sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
839 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
840 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
843 * Linux also prints the capability masks, but we don't have
844 * capabilities yet, and when we do get them they're likely to
845 * be meaningless to Linux programs, so we lie. XXX
847 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
848 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
849 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
856 * Filler function for proc/pid/cwd
859 linprocfs_doproccwd(PFS_FILL_ARGS)
861 struct filedesc *fdp;
863 char *fullpath = "unknown";
864 char *freepath = NULL;
871 FILEDESC_SUNLOCK(fdp);
872 vn_fullpath(td, vp, &fullpath, &freepath);
875 sbuf_printf(sb, "%s", fullpath);
877 free(freepath, M_TEMP);
882 * Filler function for proc/pid/root
885 linprocfs_doprocroot(PFS_FILL_ARGS)
887 struct filedesc *fdp;
889 char *fullpath = "unknown";
890 char *freepath = NULL;
894 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
897 FILEDESC_SUNLOCK(fdp);
898 vn_fullpath(td, vp, &fullpath, &freepath);
901 sbuf_printf(sb, "%s", fullpath);
903 free(freepath, M_TEMP);
908 * Filler function for proc/pid/cmdline
911 linprocfs_doproccmdline(PFS_FILL_ARGS)
916 if ((ret = p_cansee(td, p)) != 0) {
922 * Mimic linux behavior and pass only processes with usermode
923 * address space as valid. Return zero silently otherwize.
925 if (p->p_vmspace == &vmspace0) {
929 if (p->p_args != NULL) {
930 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
935 if ((p->p_flag & P_SYSTEM) != 0) {
942 ret = proc_getargv(td, p, sb);
947 * Filler function for proc/pid/environ
950 linprocfs_doprocenviron(PFS_FILL_ARGS)
954 * Mimic linux behavior and pass only processes with usermode
955 * address space as valid. Return zero silently otherwize.
957 if (p->p_vmspace == &vmspace0)
960 return (proc_getenvv(td, p, sb));
963 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
964 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
965 static char vdso_str[] = " [vdso]";
966 static char stack_str[] = " [stack]";
969 * Filler function for proc/pid/maps
972 linprocfs_doprocmaps(PFS_FILL_ARGS)
976 vm_map_entry_t entry, tmp_entry;
977 vm_object_t obj, tobj, lobj;
978 vm_offset_t e_start, e_end;
979 vm_ooffset_t off = 0;
981 unsigned int last_timestamp;
982 char *name = "", *freename = NULL;
983 const char *l_map_str;
985 int ref_count, shadow_count, flags;
991 error = p_candebug(td, p);
996 if (uio->uio_rw != UIO_READ)
1000 vm = vmspace_acquire_ref(p);
1004 if (SV_CURPROC_FLAG(SV_LP64))
1005 l_map_str = l64_map_str;
1007 l_map_str = l32_map_str;
1009 vm_map_lock_read(map);
1010 for (entry = map->header.next; entry != &map->header;
1011 entry = entry->next) {
1014 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1016 e_prot = entry->protection;
1017 e_start = entry->start;
1019 obj = entry->object.vm_object;
1020 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1021 VM_OBJECT_RLOCK(tobj);
1023 VM_OBJECT_RUNLOCK(lobj);
1026 last_timestamp = map->timestamp;
1027 vm_map_unlock_read(map);
1030 off = IDX_TO_OFF(lobj->size);
1031 vp = vm_object_vnode(lobj);
1035 VM_OBJECT_RUNLOCK(lobj);
1037 ref_count = obj->ref_count;
1038 shadow_count = obj->shadow_count;
1039 VM_OBJECT_RUNLOCK(obj);
1041 vn_fullpath(td, vp, &name, &freename);
1042 vn_lock(vp, LK_SHARED | LK_RETRY);
1043 VOP_GETATTR(vp, &vat, td->td_ucred);
1044 ino = vat.va_fileid;
1046 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1047 if (e_start == p->p_sysent->sv_shared_page_base)
1049 if (e_end == p->p_sysent->sv_usrstack)
1060 * start, end, access, offset, major, minor, inode, name.
1062 error = sbuf_printf(sb, l_map_str,
1063 (u_long)e_start, (u_long)e_end,
1064 (e_prot & VM_PROT_READ)?"r":"-",
1065 (e_prot & VM_PROT_WRITE)?"w":"-",
1066 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1076 free(freename, M_TEMP);
1077 vm_map_lock_read(map);
1082 if (last_timestamp != map->timestamp) {
1084 * Look again for the entry because the map was
1085 * modified while it was unlocked. Specifically,
1086 * the entry may have been clipped, merged, or deleted.
1088 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1092 vm_map_unlock_read(map);
1099 * Criteria for interface name translation
1101 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1104 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1106 struct ifnet *ifscan;
1109 IFNET_RLOCK_ASSERT();
1111 /* Short-circuit non ethernet interfaces */
1112 if (!IFP_IS_ETH(ifp))
1113 return (strlcpy(buffer, ifp->if_xname, buflen));
1115 /* Determine the (relative) unit number for ethernet interfaces */
1117 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1119 return (snprintf(buffer, buflen, "eth%d", ethno));
1120 if (IFP_IS_ETH(ifscan))
1128 * Filler function for proc/net/dev
1131 linprocfs_donetdev(PFS_FILL_ARGS)
1133 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1136 sbuf_printf(sb, "%6s|%58s|%s\n"
1138 "Inter-", " Receive", " Transmit",
1140 "bytes packets errs drop fifo frame compressed multicast",
1141 "bytes packets errs drop fifo colls carrier compressed");
1143 CURVNET_SET(TD_TO_VNET(curthread));
1145 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1146 linux_ifname(ifp, ifname, sizeof ifname);
1147 sbuf_printf(sb, "%6.6s: ", ifname);
1148 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1149 ifp->if_ibytes, /* rx_bytes */
1150 ifp->if_ipackets, /* rx_packets */
1151 ifp->if_ierrors, /* rx_errors */
1152 ifp->if_iqdrops, /* rx_dropped +
1153 * rx_missed_errors */
1154 0UL, /* rx_fifo_errors */
1155 0UL, /* rx_length_errors +
1158 * rx_frame_errors */
1159 0UL, /* rx_compressed */
1160 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1161 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1162 ifp->if_obytes, /* tx_bytes */
1163 ifp->if_opackets, /* tx_packets */
1164 ifp->if_oerrors, /* tx_errors */
1165 0UL, /* tx_dropped */
1166 0UL, /* tx_fifo_errors */
1167 ifp->if_collisions, /* collisions */
1168 0UL, /* tx_carrier_errors +
1169 * tx_aborted_errors +
1170 * tx_window_errors +
1171 * tx_heartbeat_errors */
1172 0UL); /* tx_compressed */
1181 * Filler function for proc/sys/kernel/osrelease
1184 linprocfs_doosrelease(PFS_FILL_ARGS)
1186 char osrelease[LINUX_MAX_UTSNAME];
1188 linux_get_osrelease(td, osrelease);
1189 sbuf_printf(sb, "%s\n", osrelease);
1195 * Filler function for proc/sys/kernel/ostype
1198 linprocfs_doostype(PFS_FILL_ARGS)
1200 char osname[LINUX_MAX_UTSNAME];
1202 linux_get_osname(td, osname);
1203 sbuf_printf(sb, "%s\n", osname);
1209 * Filler function for proc/sys/kernel/version
1212 linprocfs_doosbuild(PFS_FILL_ARGS)
1215 linprocfs_osbuild(td, sb);
1221 * Filler function for proc/sys/kernel/msgmni
1224 linprocfs_domsgmni(PFS_FILL_ARGS)
1227 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1232 * Filler function for proc/sys/kernel/pid_max
1235 linprocfs_dopid_max(PFS_FILL_ARGS)
1238 sbuf_printf(sb, "%i\n", PID_MAX);
1243 * Filler function for proc/sys/kernel/sem
1246 linprocfs_dosem(PFS_FILL_ARGS)
1249 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1250 seminfo.semopm, seminfo.semmni);
1255 * Filler function for proc/scsi/device_info
1258 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1265 * Filler function for proc/scsi/scsi
1268 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1275 * Filler function for proc/devices
1278 linprocfs_dodevices(PFS_FILL_ARGS)
1281 sbuf_printf(sb, "Character devices:\n");
1283 char_devices = linux_get_char_devices();
1284 sbuf_printf(sb, "%s", char_devices);
1285 linux_free_get_char_devices(char_devices);
1287 sbuf_printf(sb, "\nBlock devices:\n");
1293 * Filler function for proc/cmdline
1296 linprocfs_docmdline(PFS_FILL_ARGS)
1299 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1300 sbuf_printf(sb, " ro root=302\n");
1305 * Filler function for proc/filesystems
1308 linprocfs_dofilesystems(PFS_FILL_ARGS)
1310 struct vfsconf *vfsp;
1313 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1314 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1315 sbuf_printf(sb, "nodev");
1316 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1324 * Filler function for proc/modules
1327 linprocfs_domodules(PFS_FILL_ARGS)
1329 struct linker_file *lf;
1331 TAILQ_FOREACH(lf, &linker_files, link) {
1332 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1333 (unsigned long)lf->size, lf->refs);
1340 * Filler function for proc/pid/fd
1343 linprocfs_dofdescfs(PFS_FILL_ARGS)
1347 sbuf_printf(sb, "/dev/fd");
1349 sbuf_printf(sb, "unknown");
1355 * Filler function for proc/sys/kernel/random/uuid
1358 linprocfs_douuid(PFS_FILL_ARGS)
1362 kern_uuidgen(&uuid, 1);
1363 sbuf_printf_uuid(sb, &uuid);
1364 sbuf_printf(sb, "\n");
1369 * Filler function for proc/pid/auxv
1372 linprocfs_doauxv(PFS_FILL_ARGS)
1375 off_t buflen, resid;
1379 * Mimic linux behavior and pass only processes with usermode
1380 * address space as valid. Return zero silently otherwise.
1382 if (p->p_vmspace == &vmspace0)
1385 if (uio->uio_resid == 0)
1387 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1390 asb = sbuf_new_auto();
1393 error = proc_getauxv(td, p, asb);
1395 error = sbuf_finish(asb);
1397 resid = sbuf_len(asb) - uio->uio_offset;
1398 if (resid > uio->uio_resid)
1399 buflen = uio->uio_resid;
1402 if (buflen > IOSIZE_MAX)
1404 if (buflen > MAXPHYS)
1410 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1419 linprocfs_init(PFS_INIT_ARGS)
1421 struct pfs_node *root;
1422 struct pfs_node *dir;
1427 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1428 NULL, NULL, NULL, PFS_RD);
1429 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1430 NULL, NULL, NULL, PFS_RD);
1431 pfs_create_file(root, "devices", &linprocfs_dodevices,
1432 NULL, NULL, NULL, PFS_RD);
1433 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1434 NULL, NULL, NULL, PFS_RD);
1435 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1436 NULL, NULL, NULL, PFS_RD);
1437 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1438 NULL, NULL, NULL, PFS_RD);
1440 pfs_create_file(root, "modules", &linprocfs_domodules,
1441 NULL, NULL, NULL, PFS_RD);
1443 pfs_create_file(root, "mounts", &linprocfs_domtab,
1444 NULL, NULL, NULL, PFS_RD);
1445 pfs_create_file(root, "mtab", &linprocfs_domtab,
1446 NULL, NULL, NULL, PFS_RD);
1447 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1448 NULL, NULL, NULL, PFS_RD);
1449 pfs_create_link(root, "self", &procfs_docurproc,
1450 NULL, NULL, NULL, 0);
1451 pfs_create_file(root, "stat", &linprocfs_dostat,
1452 NULL, NULL, NULL, PFS_RD);
1453 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1454 NULL, NULL, NULL, PFS_RD);
1455 pfs_create_file(root, "uptime", &linprocfs_douptime,
1456 NULL, NULL, NULL, PFS_RD);
1457 pfs_create_file(root, "version", &linprocfs_doversion,
1458 NULL, NULL, NULL, PFS_RD);
1461 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1462 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1463 NULL, NULL, NULL, PFS_RD);
1465 /* /proc/<pid>/... */
1466 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1467 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1468 NULL, NULL, NULL, PFS_RD);
1469 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1470 NULL, NULL, NULL, 0);
1471 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1472 NULL, &procfs_candebug, NULL, PFS_RD);
1473 pfs_create_link(dir, "exe", &procfs_doprocfile,
1474 NULL, &procfs_notsystem, NULL, 0);
1475 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1476 NULL, NULL, NULL, PFS_RD);
1477 pfs_create_file(dir, "mem", &procfs_doprocmem,
1478 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1479 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1480 NULL, NULL, NULL, 0);
1481 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1482 NULL, NULL, NULL, PFS_RD);
1483 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1484 NULL, NULL, NULL, PFS_RD);
1485 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1486 NULL, NULL, NULL, PFS_RD);
1487 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1488 NULL, NULL, NULL, 0);
1489 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1490 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1492 /* /proc/scsi/... */
1493 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1494 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1495 NULL, NULL, NULL, PFS_RD);
1496 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1497 NULL, NULL, NULL, PFS_RD);
1500 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1501 /* /proc/sys/kernel/... */
1502 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1503 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1504 NULL, NULL, NULL, PFS_RD);
1505 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1506 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1508 NULL, NULL, NULL, PFS_RD);
1509 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1510 NULL, NULL, NULL, PFS_RD);
1511 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1512 NULL, NULL, NULL, PFS_RD);
1513 pfs_create_file(dir, "sem", &linprocfs_dosem,
1514 NULL, NULL, NULL, PFS_RD);
1516 /* /proc/sys/kernel/random/... */
1517 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1518 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1519 NULL, NULL, NULL, PFS_RD);
1528 linprocfs_uninit(PFS_INIT_ARGS)
1531 /* nothing to do, pseudofs will GC */
1535 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1536 #if defined(__amd64__)
1537 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1539 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1541 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1542 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1543 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);