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/linker.h>
56 #include <sys/malloc.h>
57 #include <sys/mount.h>
59 #include <sys/mutex.h>
60 #include <sys/namei.h>
62 #include <sys/ptrace.h>
63 #include <sys/resourcevar.h>
67 #include <sys/socket.h>
68 #include <sys/sysctl.h>
69 #include <sys/sysent.h>
70 #include <sys/systm.h>
75 #include <sys/vmmeter.h>
76 #include <sys/vnode.h>
80 #include <net/if_types.h>
83 #include <vm/vm_extern.h>
85 #include <vm/vm_map.h>
86 #include <vm/vm_param.h>
87 #include <vm/vm_object.h>
88 #include <vm/swap_pager.h>
90 #include <machine/clock.h>
92 #include <geom/geom.h>
93 #include <geom/geom_int.h>
95 #if defined(__i386__) || defined(__amd64__)
96 #include <machine/cputypes.h>
97 #include <machine/md_var.h>
98 #endif /* __i386__ || __amd64__ */
100 #include <compat/linux/linux_mib.h>
101 #include <compat/linux/linux_misc.h>
102 #include <compat/linux/linux_util.h>
103 #include <fs/pseudofs/pseudofs.h>
104 #include <fs/procfs/procfs.h>
107 * Various conversion macros
109 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
110 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
111 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
112 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
113 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
114 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
115 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
116 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
119 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
121 * The linux procfs state field displays one of the characters RSDZTW to
122 * denote running, sleeping in an interruptible wait, waiting in an
123 * uninterruptible disk sleep, a zombie process, process is being traced
124 * or stopped, or process is paging respectively.
126 * Our struct kinfo_proc contains the variable ki_stat which contains a
127 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
129 * This character array is used with ki_stati-1 as an index and tries to
130 * map our states to suitable linux states.
132 static char linux_state[] = "RRSTZDD";
135 * Filler function for proc/meminfo
138 linprocfs_domeminfo(PFS_FILL_ARGS)
140 unsigned long memtotal; /* total memory in bytes */
141 unsigned long memused; /* used memory in bytes */
142 unsigned long memfree; /* free memory in bytes */
143 unsigned long memshared; /* shared memory ??? */
144 unsigned long buffers, cached; /* buffer / cache memory ??? */
145 unsigned long long swaptotal; /* total swap space in bytes */
146 unsigned long long swapused; /* used swap space in bytes */
147 unsigned long long swapfree; /* free swap space in bytes */
151 memtotal = physmem * PAGE_SIZE;
153 * The correct thing here would be:
155 memfree = cnt.v_free_count * PAGE_SIZE;
156 memused = memtotal - memfree;
158 * but it might mislead linux binaries into thinking there
159 * is very little memory left, so we cheat and tell them that
160 * all memory that isn't wired down is free.
162 memused = cnt.v_wire_count * PAGE_SIZE;
163 memfree = memtotal - memused;
164 swap_pager_status(&i, &j);
165 swaptotal = (unsigned long long)i * PAGE_SIZE;
166 swapused = (unsigned long long)j * PAGE_SIZE;
167 swapfree = swaptotal - swapused;
169 mtx_lock(&vm_object_list_mtx);
170 TAILQ_FOREACH(object, &vm_object_list, object_list)
171 if (object->shadow_count > 1)
172 memshared += object->resident_page_count;
173 mtx_unlock(&vm_object_list_mtx);
174 memshared *= PAGE_SIZE;
176 * We'd love to be able to write:
180 * but bufspace is internal to vfs_bio.c and we don't feel
181 * like unstaticizing it just for linprocfs's sake.
184 cached = cnt.v_cache_count * PAGE_SIZE;
187 " total: used: free: shared: buffers: cached:\n"
188 "Mem: %lu %lu %lu %lu %lu %lu\n"
189 "Swap: %llu %llu %llu\n"
190 "MemTotal: %9lu kB\n"
192 "MemShared:%9lu kB\n"
195 "SwapTotal:%9llu kB\n"
196 "SwapFree: %9llu kB\n",
197 memtotal, memused, memfree, memshared, buffers, cached,
198 swaptotal, swapused, swapfree,
199 B2K(memtotal), B2K(memfree),
200 B2K(memshared), B2K(buffers), B2K(cached),
201 B2K(swaptotal), B2K(swapfree));
206 #if defined(__i386__) || defined(__amd64__)
208 * Filler function for proc/cpuinfo (i386 & amd64 version)
211 linprocfs_docpuinfo(PFS_FILL_ARGS)
217 int class, fqmhz, fqkhz;
221 * We default the flags to include all non-conflicting flags,
222 * and the Intel versions of conflicting flags.
224 static char *flags[] = {
225 "fpu", "vme", "de", "pse", "tsc",
226 "msr", "pae", "mce", "cx8", "apic",
227 "sep", "sep", "mtrr", "pge", "mca",
228 "cmov", "pat", "pse36", "pn", "b19",
229 "b20", "b21", "mmxext", "mmx", "fxsr",
230 "xmm", "sse2", "b27", "b28", "b29",
254 #else /* __amd64__ */
261 hw_model[0] = CTL_HW;
262 hw_model[1] = HW_MODEL;
264 size = sizeof(model);
265 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
266 strcpy(model, "unknown");
267 for (i = 0; i < mp_ncpus; ++i) {
270 "vendor_id\t: %.20s\n"
274 "stepping\t: %u\n\n",
275 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
276 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
277 /* XXX per-cpu vendor / class / model / id? */
280 sbuf_cat(sb, "flags\t\t:");
283 switch (cpu_vendor_id) {
288 case CPU_VENDOR_CYRIX:
294 for (i = 0; i < 32; i++)
295 if (cpu_feature & (1 << i))
296 sbuf_printf(sb, " %s", flags[i]);
298 freq = atomic_load_acq_64(&tsc_freq);
300 fqmhz = (freq + 4999) / 1000000;
301 fqkhz = ((freq + 4999) / 10000) % 100;
303 "cpu MHz\t\t: %d.%02d\n"
304 "bogomips\t: %d.%02d\n",
305 fqmhz, fqkhz, fqmhz, fqkhz);
310 #endif /* __i386__ || __amd64__ */
313 * Filler function for proc/mtab
315 * This file doesn't exist in Linux' procfs, but is included here so
316 * users can symlink /compat/linux/etc/mtab to /proc/mtab
319 linprocfs_domtab(PFS_FILL_ARGS)
324 char *dlep, *flep, *mntto, *mntfrom, *fstype;
328 /* resolve symlinks etc. in the emulation tree prefix */
329 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
332 lep = linux_emul_path;
334 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
338 lep_len = strlen(lep);
340 mtx_lock(&mountlist_mtx);
342 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
343 /* determine device name */
344 mntfrom = mp->mnt_stat.f_mntfromname;
346 /* determine mount point */
347 mntto = mp->mnt_stat.f_mntonname;
348 if (strncmp(mntto, lep, lep_len) == 0 &&
349 mntto[lep_len] == '/')
352 /* determine fs type */
353 fstype = mp->mnt_stat.f_fstypename;
354 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
355 mntfrom = fstype = "proc";
356 else if (strcmp(fstype, "procfs") == 0)
359 if (strcmp(fstype, "linsysfs") == 0) {
360 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
361 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
363 /* For Linux msdosfs is called vfat */
364 if (strcmp(fstype, "msdosfs") == 0)
366 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
367 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
369 #define ADD_OPTION(opt, name) \
370 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
371 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
372 ADD_OPTION(MNT_NOEXEC, "noexec");
373 ADD_OPTION(MNT_NOSUID, "nosuid");
374 ADD_OPTION(MNT_UNION, "union");
375 ADD_OPTION(MNT_ASYNC, "async");
376 ADD_OPTION(MNT_SUIDDIR, "suiddir");
377 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
378 ADD_OPTION(MNT_NOATIME, "noatime");
380 /* a real Linux mtab will also show NFS options */
381 sbuf_printf(sb, " 0 0\n");
383 mtx_unlock(&mountlist_mtx);
389 * Filler function for proc/partitions
392 linprocfs_dopartitions(PFS_FILL_ARGS)
396 struct g_provider *pp;
400 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
401 "ruse wio wmerge wsect wuse running use aveq\n");
403 LIST_FOREACH(cp, &g_classes, class) {
404 if (strcmp(cp->name, "DISK") == 0 ||
405 strcmp(cp->name, "PART") == 0)
406 LIST_FOREACH(gp, &cp->geom, geom) {
407 LIST_FOREACH(pp, &gp->provider, provider) {
408 if (linux_driver_get_major_minor(
409 pp->name, &major, &minor) != 0) {
413 sbuf_printf(sb, "%d %d %lld %s "
415 "%d %d %d %d %d %d\n",
417 (long long)pp->mediasize, pp->name,
430 * Filler function for proc/stat
433 linprocfs_dostat(PFS_FILL_ARGS)
436 long cp_time[CPUSTATES];
440 read_cpu_time(cp_time);
441 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
442 T2J(cp_time[CP_USER]),
443 T2J(cp_time[CP_NICE]),
444 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
445 T2J(cp_time[CP_IDLE]));
448 cp = pcpu->pc_cp_time;
449 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
452 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
468 (long long)boottime.tv_sec);
473 linprocfs_doswaps(PFS_FILL_ARGS)
476 uintmax_t total, used;
478 char devname[SPECNAMELEN + 1];
480 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
483 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
485 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
486 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
489 * The space and not tab after the device name is on
490 * purpose. Linux does so.
492 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
493 devname, total, used);
500 * Filler function for proc/uptime
503 linprocfs_douptime(PFS_FILL_ARGS)
505 long cp_time[CPUSTATES];
509 read_cpu_time(cp_time);
510 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
511 (long long)tv.tv_sec, tv.tv_usec / 10000,
512 T2S(cp_time[CP_IDLE] / mp_ncpus),
513 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
521 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
527 strncpy(osbuild, version, 256);
529 cp1 = strstr(osbuild, "\n");
530 cp2 = strstr(osbuild, ":");
533 cp1 = strstr(osbuild, "#");
537 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
540 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
547 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
553 cp = strstr(version, "\n ");
555 strncpy(builder, cp + 5, 256);
557 cp = strstr(builder, ":");
562 sbuf_cat(sb, builder);
565 sbuf_cat(sb, "des@freebsd.org");
569 * Filler function for proc/version
572 linprocfs_doversion(PFS_FILL_ARGS)
574 char osname[LINUX_MAX_UTSNAME];
575 char osrelease[LINUX_MAX_UTSNAME];
577 linux_get_osname(td, osname);
578 linux_get_osrelease(td, osrelease);
579 sbuf_printf(sb, "%s version %s (", osname, osrelease);
580 linprocfs_osbuilder(td, sb);
581 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
582 linprocfs_osbuild(td, sb);
589 * Filler function for proc/loadavg
592 linprocfs_doloadavg(PFS_FILL_ARGS)
596 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
597 (int)(averunnable.ldavg[0] / averunnable.fscale),
598 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
599 (int)(averunnable.ldavg[1] / averunnable.fscale),
600 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
601 (int)(averunnable.ldavg[2] / averunnable.fscale),
602 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
603 1, /* number of running tasks */
604 nprocs, /* number of tasks */
605 lastpid /* the last pid */
611 * Filler function for proc/pid/stat
614 linprocfs_doprocstat(PFS_FILL_ARGS)
616 struct kinfo_proc kp;
618 static int ratelimit = 0;
619 vm_offset_t startcode, startdata;
622 fill_kinfo_proc(p, &kp);
624 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
625 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
630 sbuf_printf(sb, "%d", p->p_pid);
631 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
632 PS_ADD("comm", "(%s)", p->p_comm);
633 if (kp.ki_stat > sizeof(linux_state)) {
636 if (ratelimit == 0) {
637 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
638 kp.ki_stat, sizeof(linux_state));
642 state = linux_state[kp.ki_stat - 1];
643 PS_ADD("state", "%c", state);
644 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
645 PS_ADD("pgrp", "%d", p->p_pgid);
646 PS_ADD("session", "%d", p->p_session->s_sid);
648 PS_ADD("tty", "%d", kp.ki_tdev);
649 PS_ADD("tpgid", "%d", kp.ki_tpgid);
650 PS_ADD("flags", "%u", 0); /* XXX */
651 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
652 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
653 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
654 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
655 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
656 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
657 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
658 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
659 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
660 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
661 PS_ADD("0", "%d", 0); /* removed field */
662 PS_ADD("itrealvalue", "%d", 0); /* XXX */
663 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
664 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
665 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
666 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
667 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
668 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
669 PS_ADD("startstack", "%u", 0); /* XXX */
670 PS_ADD("kstkesp", "%u", 0); /* XXX */
671 PS_ADD("kstkeip", "%u", 0); /* XXX */
672 PS_ADD("signal", "%u", 0); /* XXX */
673 PS_ADD("blocked", "%u", 0); /* XXX */
674 PS_ADD("sigignore", "%u", 0); /* XXX */
675 PS_ADD("sigcatch", "%u", 0); /* XXX */
676 PS_ADD("wchan", "%u", 0); /* XXX */
677 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
678 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
679 PS_ADD("exitsignal", "%d", 0); /* XXX */
680 PS_ADD("processor", "%u", kp.ki_lastcpu);
681 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
682 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
690 * Filler function for proc/pid/statm
693 linprocfs_doprocstatm(PFS_FILL_ARGS)
695 struct kinfo_proc kp;
699 fill_kinfo_proc(p, &kp);
703 * See comments in linprocfs_doprocstatus() regarding the
704 * computation of lsize.
706 /* size resident share trs drs lrs dt */
707 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
708 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
709 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
710 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
711 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
712 lsize = B2P(kp.ki_size) - kp.ki_dsize -
713 kp.ki_ssize - kp.ki_tsize - 1;
714 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
715 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
721 * Filler function for proc/pid/status
724 linprocfs_doprocstatus(PFS_FILL_ARGS)
726 struct kinfo_proc kp;
734 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
736 if (P_SHOULDSTOP(p)) {
737 state = "T (stopped)";
744 if (p->p_flag & P_WEXIT) {
745 state = "X (exiting)";
748 switch(td2->td_state) {
750 state = "S (sleeping)";
754 state = "R (running)";
757 state = "? (unknown)";
762 state = "Z (zombie)";
765 state = "? (unknown)";
770 fill_kinfo_proc(p, &kp);
771 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
772 sbuf_printf(sb, "State:\t%s\n", state);
777 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
778 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
779 p->p_pptr->p_pid : 0);
780 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
782 p->p_ucred->cr_svuid,
783 /* FreeBSD doesn't have fsuid */
785 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
787 p->p_ucred->cr_svgid,
788 /* FreeBSD doesn't have fsgid */
790 sbuf_cat(sb, "Groups:\t");
791 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
792 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
799 * While our approximation of VmLib may not be accurate (I
800 * don't know of a simple way to verify it, and I'm not sure
801 * it has much meaning anyway), I believe it's good enough.
803 * The same code that could (I think) accurately compute VmLib
804 * could also compute VmLck, but I don't really care enough to
805 * implement it. Submissions are welcome.
807 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
808 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
809 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
810 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
811 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
812 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
813 lsize = B2P(kp.ki_size) - kp.ki_dsize -
814 kp.ki_ssize - kp.ki_tsize - 1;
815 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
820 * We support up to 128 signals, while Linux supports 32,
821 * but we only define 32 (the same 32 as Linux, to boot), so
822 * just show the lower 32 bits of each mask. XXX hack.
824 * NB: on certain platforms (Sparc at least) Linux actually
825 * supports 64 signals, but this code is a long way from
826 * running on anything but i386, so ignore that for now.
829 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
831 * I can't seem to find out where the signal mask is in
832 * relation to struct proc, so SigBlk is left unimplemented.
834 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
836 mtx_lock(&ps->ps_mtx);
837 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
838 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
839 mtx_unlock(&ps->ps_mtx);
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 char *fullpath = "unknown";
862 char *freepath = NULL;
864 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
865 sbuf_printf(sb, "%s", fullpath);
867 free(freepath, M_TEMP);
872 * Filler function for proc/pid/root
875 linprocfs_doprocroot(PFS_FILL_ARGS)
878 char *fullpath = "unknown";
879 char *freepath = NULL;
881 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
882 vn_fullpath(td, rvp, &fullpath, &freepath);
883 sbuf_printf(sb, "%s", fullpath);
885 free(freepath, M_TEMP);
890 * Filler function for proc/pid/cmdline
893 linprocfs_doproccmdline(PFS_FILL_ARGS)
898 if ((ret = p_cansee(td, p)) != 0) {
904 * Mimic linux behavior and pass only processes with usermode
905 * address space as valid. Return zero silently otherwize.
907 if (p->p_vmspace == &vmspace0) {
911 if (p->p_args != NULL) {
912 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
917 if ((p->p_flag & P_SYSTEM) != 0) {
924 ret = proc_getargv(td, p, sb);
929 * Filler function for proc/pid/environ
932 linprocfs_doprocenviron(PFS_FILL_ARGS)
937 if ((ret = p_candebug(td, p)) != 0) {
943 * Mimic linux behavior and pass only processes with usermode
944 * address space as valid. Return zero silently otherwize.
946 if (p->p_vmspace == &vmspace0) {
951 if ((p->p_flag & P_SYSTEM) != 0) {
958 ret = proc_getenvv(td, p, sb);
962 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
963 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
964 static char vdso_str[] = " [vdso]";
965 static char stack_str[] = " [stack]";
968 * Filler function for proc/pid/maps
971 linprocfs_doprocmaps(PFS_FILL_ARGS)
975 vm_map_entry_t entry, tmp_entry;
976 vm_object_t obj, tobj, lobj;
977 vm_offset_t e_start, e_end;
978 vm_ooffset_t off = 0;
980 unsigned int last_timestamp;
981 char *name = "", *freename = NULL;
982 const char *l_map_str;
984 int ref_count, shadow_count, flags;
990 error = p_candebug(td, p);
995 if (uio->uio_rw != UIO_READ)
999 vm = vmspace_acquire_ref(p);
1003 if (SV_CURPROC_FLAG(SV_LP64))
1004 l_map_str = l64_map_str;
1006 l_map_str = l32_map_str;
1008 vm_map_lock_read(map);
1009 for (entry = map->header.next; entry != &map->header;
1010 entry = entry->next) {
1013 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1015 e_prot = entry->protection;
1016 e_start = entry->start;
1018 obj = entry->object.vm_object;
1019 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1020 VM_OBJECT_RLOCK(tobj);
1022 VM_OBJECT_RUNLOCK(lobj);
1025 last_timestamp = map->timestamp;
1026 vm_map_unlock_read(map);
1029 off = IDX_TO_OFF(lobj->size);
1030 vp = vm_object_vnode(lobj);
1034 VM_OBJECT_RUNLOCK(lobj);
1036 ref_count = obj->ref_count;
1037 shadow_count = obj->shadow_count;
1038 VM_OBJECT_RUNLOCK(obj);
1040 vn_fullpath(td, vp, &name, &freename);
1041 vn_lock(vp, LK_SHARED | LK_RETRY);
1042 VOP_GETATTR(vp, &vat, td->td_ucred);
1043 ino = vat.va_fileid;
1045 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1046 if (e_start == p->p_sysent->sv_shared_page_base)
1048 if (e_end == p->p_sysent->sv_usrstack)
1059 * start, end, access, offset, major, minor, inode, name.
1061 error = sbuf_printf(sb, l_map_str,
1062 (u_long)e_start, (u_long)e_end,
1063 (e_prot & VM_PROT_READ)?"r":"-",
1064 (e_prot & VM_PROT_WRITE)?"w":"-",
1065 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1075 free(freename, M_TEMP);
1076 vm_map_lock_read(map);
1081 if (last_timestamp != map->timestamp) {
1083 * Look again for the entry because the map was
1084 * modified while it was unlocked. Specifically,
1085 * the entry may have been clipped, merged, or deleted.
1087 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1091 vm_map_unlock_read(map);
1098 * Criteria for interface name translation
1100 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1103 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1105 struct ifnet *ifscan;
1108 IFNET_RLOCK_ASSERT();
1110 /* Short-circuit non ethernet interfaces */
1111 if (!IFP_IS_ETH(ifp))
1112 return (strlcpy(buffer, ifp->if_xname, buflen));
1114 /* Determine the (relative) unit number for ethernet interfaces */
1116 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1118 return (snprintf(buffer, buflen, "eth%d", ethno));
1119 if (IFP_IS_ETH(ifscan))
1127 * Filler function for proc/net/dev
1130 linprocfs_donetdev(PFS_FILL_ARGS)
1132 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1135 sbuf_printf(sb, "%6s|%58s|%s\n"
1137 "Inter-", " Receive", " Transmit",
1139 "bytes packets errs drop fifo frame compressed multicast",
1140 "bytes packets errs drop fifo colls carrier compressed");
1142 CURVNET_SET(TD_TO_VNET(curthread));
1144 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1145 linux_ifname(ifp, ifname, sizeof ifname);
1146 sbuf_printf(sb, "%6.6s: ", ifname);
1147 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1148 ifp->if_ibytes, /* rx_bytes */
1149 ifp->if_ipackets, /* rx_packets */
1150 ifp->if_ierrors, /* rx_errors */
1151 ifp->if_iqdrops, /* rx_dropped +
1152 * rx_missed_errors */
1153 0UL, /* rx_fifo_errors */
1154 0UL, /* rx_length_errors +
1157 * rx_frame_errors */
1158 0UL, /* rx_compressed */
1159 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1160 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1161 ifp->if_obytes, /* tx_bytes */
1162 ifp->if_opackets, /* tx_packets */
1163 ifp->if_oerrors, /* tx_errors */
1164 0UL, /* tx_dropped */
1165 0UL, /* tx_fifo_errors */
1166 ifp->if_collisions, /* collisions */
1167 0UL, /* tx_carrier_errors +
1168 * tx_aborted_errors +
1169 * tx_window_errors +
1170 * tx_heartbeat_errors */
1171 0UL); /* tx_compressed */
1180 * Filler function for proc/sys/kernel/osrelease
1183 linprocfs_doosrelease(PFS_FILL_ARGS)
1185 char osrelease[LINUX_MAX_UTSNAME];
1187 linux_get_osrelease(td, osrelease);
1188 sbuf_printf(sb, "%s\n", osrelease);
1194 * Filler function for proc/sys/kernel/ostype
1197 linprocfs_doostype(PFS_FILL_ARGS)
1199 char osname[LINUX_MAX_UTSNAME];
1201 linux_get_osname(td, osname);
1202 sbuf_printf(sb, "%s\n", osname);
1208 * Filler function for proc/sys/kernel/version
1211 linprocfs_doosbuild(PFS_FILL_ARGS)
1214 linprocfs_osbuild(td, sb);
1220 * Filler function for proc/sys/kernel/msgmni
1223 linprocfs_domsgmni(PFS_FILL_ARGS)
1226 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1231 * Filler function for proc/sys/kernel/pid_max
1234 linprocfs_dopid_max(PFS_FILL_ARGS)
1237 sbuf_printf(sb, "%i\n", PID_MAX);
1242 * Filler function for proc/sys/kernel/sem
1245 linprocfs_dosem(PFS_FILL_ARGS)
1248 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1249 seminfo.semopm, seminfo.semmni);
1254 * Filler function for proc/scsi/device_info
1257 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1264 * Filler function for proc/scsi/scsi
1267 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1274 * Filler function for proc/devices
1277 linprocfs_dodevices(PFS_FILL_ARGS)
1280 sbuf_printf(sb, "Character devices:\n");
1282 char_devices = linux_get_char_devices();
1283 sbuf_printf(sb, "%s", char_devices);
1284 linux_free_get_char_devices(char_devices);
1286 sbuf_printf(sb, "\nBlock devices:\n");
1292 * Filler function for proc/cmdline
1295 linprocfs_docmdline(PFS_FILL_ARGS)
1298 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1299 sbuf_printf(sb, " ro root=302\n");
1304 * Filler function for proc/filesystems
1307 linprocfs_dofilesystems(PFS_FILL_ARGS)
1309 struct vfsconf *vfsp;
1312 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1313 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1314 sbuf_printf(sb, "nodev");
1315 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1323 * Filler function for proc/modules
1326 linprocfs_domodules(PFS_FILL_ARGS)
1328 struct linker_file *lf;
1330 TAILQ_FOREACH(lf, &linker_files, link) {
1331 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1332 (unsigned long)lf->size, lf->refs);
1339 * Filler function for proc/pid/fd
1342 linprocfs_dofdescfs(PFS_FILL_ARGS)
1346 sbuf_printf(sb, "/dev/fd");
1348 sbuf_printf(sb, "unknown");
1354 * Filler function for proc/sys/kernel/random/uuid
1357 linprocfs_douuid(PFS_FILL_ARGS)
1361 kern_uuidgen(&uuid, 1);
1362 sbuf_printf_uuid(sb, &uuid);
1363 sbuf_printf(sb, "\n");
1372 linprocfs_init(PFS_INIT_ARGS)
1374 struct pfs_node *root;
1375 struct pfs_node *dir;
1380 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1381 NULL, NULL, NULL, PFS_RD);
1382 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1383 NULL, NULL, NULL, PFS_RD);
1384 pfs_create_file(root, "devices", &linprocfs_dodevices,
1385 NULL, NULL, NULL, PFS_RD);
1386 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1387 NULL, NULL, NULL, PFS_RD);
1388 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1389 NULL, NULL, NULL, PFS_RD);
1390 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1391 NULL, NULL, NULL, PFS_RD);
1393 pfs_create_file(root, "modules", &linprocfs_domodules,
1394 NULL, NULL, NULL, PFS_RD);
1396 pfs_create_file(root, "mounts", &linprocfs_domtab,
1397 NULL, NULL, NULL, PFS_RD);
1398 pfs_create_file(root, "mtab", &linprocfs_domtab,
1399 NULL, NULL, NULL, PFS_RD);
1400 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1401 NULL, NULL, NULL, PFS_RD);
1402 pfs_create_link(root, "self", &procfs_docurproc,
1403 NULL, NULL, NULL, 0);
1404 pfs_create_file(root, "stat", &linprocfs_dostat,
1405 NULL, NULL, NULL, PFS_RD);
1406 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1407 NULL, NULL, NULL, PFS_RD);
1408 pfs_create_file(root, "uptime", &linprocfs_douptime,
1409 NULL, NULL, NULL, PFS_RD);
1410 pfs_create_file(root, "version", &linprocfs_doversion,
1411 NULL, NULL, NULL, PFS_RD);
1414 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1415 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1416 NULL, NULL, NULL, PFS_RD);
1418 /* /proc/<pid>/... */
1419 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1420 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1421 NULL, NULL, NULL, PFS_RD);
1422 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1423 NULL, NULL, NULL, 0);
1424 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1425 NULL, NULL, NULL, PFS_RD);
1426 pfs_create_link(dir, "exe", &procfs_doprocfile,
1427 NULL, &procfs_notsystem, NULL, 0);
1428 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1429 NULL, NULL, NULL, PFS_RD);
1430 pfs_create_file(dir, "mem", &procfs_doprocmem,
1431 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1432 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1433 NULL, NULL, NULL, 0);
1434 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1435 NULL, NULL, NULL, PFS_RD);
1436 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1437 NULL, NULL, NULL, PFS_RD);
1438 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1439 NULL, NULL, NULL, PFS_RD);
1440 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1441 NULL, NULL, NULL, 0);
1443 /* /proc/scsi/... */
1444 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1445 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1446 NULL, NULL, NULL, PFS_RD);
1447 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1448 NULL, NULL, NULL, PFS_RD);
1451 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1452 /* /proc/sys/kernel/... */
1453 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1454 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1455 NULL, NULL, NULL, PFS_RD);
1456 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1457 NULL, NULL, NULL, PFS_RD);
1458 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1459 NULL, NULL, NULL, PFS_RD);
1460 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1461 NULL, NULL, NULL, PFS_RD);
1462 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1463 NULL, NULL, NULL, PFS_RD);
1464 pfs_create_file(dir, "sem", &linprocfs_dosem,
1465 NULL, NULL, NULL, PFS_RD);
1467 /* /proc/sys/kernel/random/... */
1468 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1469 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1470 NULL, NULL, NULL, PFS_RD);
1479 linprocfs_uninit(PFS_INIT_ARGS)
1482 /* nothing to do, pseudofs will GC */
1486 PSEUDOFS(linprocfs, 1, 0);
1487 #if defined(__amd64__)
1488 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1490 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1492 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1493 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1494 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);