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 "opt_compat.h"
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
47 #include <sys/param.h>
48 #include <sys/queue.h>
49 #include <sys/blist.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
55 #include <sys/kernel.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/systm.h>
76 #include <sys/vmmeter.h>
77 #include <sys/vnode.h>
84 #include <vm/vm_extern.h>
86 #include <vm/vm_map.h>
87 #include <vm/vm_param.h>
88 #include <vm/vm_object.h>
89 #include <vm/swap_pager.h>
91 #include <machine/clock.h>
93 #include <geom/geom.h>
94 #include <geom/geom_int.h>
96 #if defined(__i386__) || defined(__amd64__)
97 #include <machine/cputypes.h>
98 #include <machine/md_var.h>
99 #endif /* __i386__ || __amd64__ */
101 #ifdef COMPAT_FREEBSD32
102 #include <compat/freebsd32/freebsd32_util.h>
105 #include <compat/linux/linux_ioctl.h>
106 #include <compat/linux/linux_mib.h>
107 #include <compat/linux/linux_misc.h>
108 #include <compat/linux/linux_util.h>
109 #include <fs/pseudofs/pseudofs.h>
110 #include <fs/procfs/procfs.h>
113 * Various conversion macros
115 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
116 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
117 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
118 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
119 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
120 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
121 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
122 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
125 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
127 * The linux procfs state field displays one of the characters RSDZTW to
128 * denote running, sleeping in an interruptible wait, waiting in an
129 * uninterruptible disk sleep, a zombie process, process is being traced
130 * or stopped, or process is paging respectively.
132 * Our struct kinfo_proc contains the variable ki_stat which contains a
133 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
135 * This character array is used with ki_stati-1 as an index and tries to
136 * map our states to suitable linux states.
138 static char linux_state[] = "RRSTZDD";
141 * Filler function for proc/meminfo
144 linprocfs_domeminfo(PFS_FILL_ARGS)
146 unsigned long memtotal; /* total memory in bytes */
147 unsigned long memused; /* used memory in bytes */
148 unsigned long memfree; /* free memory in bytes */
149 unsigned long memshared; /* shared memory ??? */
150 unsigned long buffers, cached; /* buffer / cache memory ??? */
151 unsigned long long swaptotal; /* total swap space in bytes */
152 unsigned long long swapused; /* used swap space in bytes */
153 unsigned long long swapfree; /* free swap space in bytes */
157 memtotal = physmem * PAGE_SIZE;
159 * The correct thing here would be:
161 memfree = cnt.v_free_count * PAGE_SIZE;
162 memused = memtotal - memfree;
164 * but it might mislead linux binaries into thinking there
165 * is very little memory left, so we cheat and tell them that
166 * all memory that isn't wired down is free.
168 memused = cnt.v_wire_count * PAGE_SIZE;
169 memfree = memtotal - memused;
170 swap_pager_status(&i, &j);
171 swaptotal = (unsigned long long)i * PAGE_SIZE;
172 swapused = (unsigned long long)j * PAGE_SIZE;
173 swapfree = swaptotal - swapused;
175 mtx_lock(&vm_object_list_mtx);
176 TAILQ_FOREACH(object, &vm_object_list, object_list)
177 if (object->shadow_count > 1)
178 memshared += object->resident_page_count;
179 mtx_unlock(&vm_object_list_mtx);
180 memshared *= PAGE_SIZE;
182 * We'd love to be able to write:
186 * but bufspace is internal to vfs_bio.c and we don't feel
187 * like unstaticizing it just for linprocfs's sake.
190 cached = cnt.v_cache_count * PAGE_SIZE;
193 " total: used: free: shared: buffers: cached:\n"
194 "Mem: %lu %lu %lu %lu %lu %lu\n"
195 "Swap: %llu %llu %llu\n"
196 "MemTotal: %9lu kB\n"
198 "MemShared:%9lu kB\n"
201 "SwapTotal:%9llu kB\n"
202 "SwapFree: %9llu kB\n",
203 memtotal, memused, memfree, memshared, buffers, cached,
204 swaptotal, swapused, swapfree,
205 B2K(memtotal), B2K(memfree),
206 B2K(memshared), B2K(buffers), B2K(cached),
207 B2K(swaptotal), B2K(swapfree));
212 #if defined(__i386__) || defined(__amd64__)
214 * Filler function for proc/cpuinfo (i386 & amd64 version)
217 linprocfs_docpuinfo(PFS_FILL_ARGS)
223 int class, fqmhz, fqkhz;
227 * We default the flags to include all non-conflicting flags,
228 * and the Intel versions of conflicting flags.
230 static char *flags[] = {
231 "fpu", "vme", "de", "pse", "tsc",
232 "msr", "pae", "mce", "cx8", "apic",
233 "sep", "sep", "mtrr", "pge", "mca",
234 "cmov", "pat", "pse36", "pn", "b19",
235 "b20", "b21", "mmxext", "mmx", "fxsr",
236 "xmm", "sse2", "b27", "b28", "b29",
260 #else /* __amd64__ */
267 hw_model[0] = CTL_HW;
268 hw_model[1] = HW_MODEL;
270 size = sizeof(model);
271 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
272 strcpy(model, "unknown");
273 for (i = 0; i < mp_ncpus; ++i) {
276 "vendor_id\t: %.20s\n"
280 "stepping\t: %u\n\n",
281 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
282 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
283 /* XXX per-cpu vendor / class / model / id? */
286 sbuf_cat(sb, "flags\t\t:");
289 switch (cpu_vendor_id) {
294 case CPU_VENDOR_CYRIX:
300 for (i = 0; i < 32; i++)
301 if (cpu_feature & (1 << i))
302 sbuf_printf(sb, " %s", flags[i]);
304 freq = atomic_load_acq_64(&tsc_freq);
306 fqmhz = (freq + 4999) / 1000000;
307 fqkhz = ((freq + 4999) / 10000) % 100;
309 "cpu MHz\t\t: %d.%02d\n"
310 "bogomips\t: %d.%02d\n",
311 fqmhz, fqkhz, fqmhz, fqkhz);
316 #endif /* __i386__ || __amd64__ */
319 * Filler function for proc/mtab
321 * This file doesn't exist in Linux' procfs, but is included here so
322 * users can symlink /compat/linux/etc/mtab to /proc/mtab
325 linprocfs_domtab(PFS_FILL_ARGS)
330 char *dlep, *flep, *mntto, *mntfrom, *fstype;
334 /* resolve symlinks etc. in the emulation tree prefix */
335 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
338 lep = linux_emul_path;
340 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
344 lep_len = strlen(lep);
346 mtx_lock(&mountlist_mtx);
348 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
349 /* determine device name */
350 mntfrom = mp->mnt_stat.f_mntfromname;
352 /* determine mount point */
353 mntto = mp->mnt_stat.f_mntonname;
354 if (strncmp(mntto, lep, lep_len) == 0 &&
355 mntto[lep_len] == '/')
358 /* determine fs type */
359 fstype = mp->mnt_stat.f_fstypename;
360 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
361 mntfrom = fstype = "proc";
362 else if (strcmp(fstype, "procfs") == 0)
365 if (strcmp(fstype, "linsysfs") == 0) {
366 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
367 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
369 /* For Linux msdosfs is called vfat */
370 if (strcmp(fstype, "msdosfs") == 0)
372 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
373 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
375 #define ADD_OPTION(opt, name) \
376 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
377 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
378 ADD_OPTION(MNT_NOEXEC, "noexec");
379 ADD_OPTION(MNT_NOSUID, "nosuid");
380 ADD_OPTION(MNT_UNION, "union");
381 ADD_OPTION(MNT_ASYNC, "async");
382 ADD_OPTION(MNT_SUIDDIR, "suiddir");
383 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
384 ADD_OPTION(MNT_NOATIME, "noatime");
386 /* a real Linux mtab will also show NFS options */
387 sbuf_printf(sb, " 0 0\n");
389 mtx_unlock(&mountlist_mtx);
395 * Filler function for proc/partitions
399 linprocfs_dopartitions(PFS_FILL_ARGS)
403 struct g_provider *pp;
411 /* resolve symlinks etc. in the emulation tree prefix */
412 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
415 lep = linux_emul_path;
417 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
421 lep_len = strlen(lep);
425 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
426 "ruse wio wmerge wsect wuse running use aveq\n");
428 LIST_FOREACH(cp, &g_classes, class) {
429 if (strcmp(cp->name, "DISK") == 0 ||
430 strcmp(cp->name, "PART") == 0)
431 LIST_FOREACH(gp, &cp->geom, geom) {
432 LIST_FOREACH(pp, &gp->provider, provider) {
433 if (linux_driver_get_major_minor(
434 pp->name, &major, &minor) != 0) {
438 sbuf_printf(sb, "%d %d %lld %s "
440 "%d %d %d %d %d %d\n",
442 (long long)pp->mediasize, pp->name,
456 * Filler function for proc/stat
459 linprocfs_dostat(PFS_FILL_ARGS)
462 long cp_time[CPUSTATES];
466 read_cpu_time(cp_time);
467 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
468 T2J(cp_time[CP_USER]),
469 T2J(cp_time[CP_NICE]),
470 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
471 T2J(cp_time[CP_IDLE]));
474 cp = pcpu->pc_cp_time;
475 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
478 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
494 (long long)boottime.tv_sec);
499 linprocfs_doswaps(PFS_FILL_ARGS)
502 uintmax_t total, used;
504 char devname[SPECNAMELEN + 1];
506 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
509 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
511 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
512 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
515 * The space and not tab after the device name is on
516 * purpose. Linux does so.
518 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
519 devname, total, used);
526 * Filler function for proc/uptime
529 linprocfs_douptime(PFS_FILL_ARGS)
531 long cp_time[CPUSTATES];
535 read_cpu_time(cp_time);
536 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
537 (long long)tv.tv_sec, tv.tv_usec / 10000,
538 T2S(cp_time[CP_IDLE] / mp_ncpus),
539 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
547 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
553 strncpy(osbuild, version, 256);
555 cp1 = strstr(osbuild, "\n");
556 cp2 = strstr(osbuild, ":");
559 cp1 = strstr(osbuild, "#");
563 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
566 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
573 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
579 cp = strstr(version, "\n ");
581 strncpy(builder, cp + 5, 256);
583 cp = strstr(builder, ":");
588 sbuf_cat(sb, builder);
591 sbuf_cat(sb, "des@freebsd.org");
595 * Filler function for proc/version
598 linprocfs_doversion(PFS_FILL_ARGS)
600 char osname[LINUX_MAX_UTSNAME];
601 char osrelease[LINUX_MAX_UTSNAME];
603 linux_get_osname(td, osname);
604 linux_get_osrelease(td, osrelease);
605 sbuf_printf(sb, "%s version %s (", osname, osrelease);
606 linprocfs_osbuilder(td, sb);
607 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
608 linprocfs_osbuild(td, sb);
615 * Filler function for proc/loadavg
618 linprocfs_doloadavg(PFS_FILL_ARGS)
622 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
623 (int)(averunnable.ldavg[0] / averunnable.fscale),
624 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
625 (int)(averunnable.ldavg[1] / averunnable.fscale),
626 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
627 (int)(averunnable.ldavg[2] / averunnable.fscale),
628 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
629 1, /* number of running tasks */
630 nprocs, /* number of tasks */
631 lastpid /* the last pid */
637 * Filler function for proc/pid/stat
640 linprocfs_doprocstat(PFS_FILL_ARGS)
642 struct kinfo_proc kp;
644 static int ratelimit = 0;
645 vm_offset_t startcode, startdata;
648 fill_kinfo_proc(p, &kp);
650 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
651 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
656 sbuf_printf(sb, "%d", p->p_pid);
657 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
658 PS_ADD("comm", "(%s)", p->p_comm);
659 if (kp.ki_stat > sizeof(linux_state)) {
662 if (ratelimit == 0) {
663 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
664 kp.ki_stat, sizeof(linux_state));
668 state = linux_state[kp.ki_stat - 1];
669 PS_ADD("state", "%c", state);
670 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
671 PS_ADD("pgrp", "%d", p->p_pgid);
672 PS_ADD("session", "%d", p->p_session->s_sid);
674 PS_ADD("tty", "%d", kp.ki_tdev);
675 PS_ADD("tpgid", "%d", kp.ki_tpgid);
676 PS_ADD("flags", "%u", 0); /* XXX */
677 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
678 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
679 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
680 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
681 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
682 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
683 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
684 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
685 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
686 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
687 PS_ADD("0", "%d", 0); /* removed field */
688 PS_ADD("itrealvalue", "%d", 0); /* XXX */
689 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
690 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
691 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
692 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
693 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
694 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
695 PS_ADD("startstack", "%u", 0); /* XXX */
696 PS_ADD("kstkesp", "%u", 0); /* XXX */
697 PS_ADD("kstkeip", "%u", 0); /* XXX */
698 PS_ADD("signal", "%u", 0); /* XXX */
699 PS_ADD("blocked", "%u", 0); /* XXX */
700 PS_ADD("sigignore", "%u", 0); /* XXX */
701 PS_ADD("sigcatch", "%u", 0); /* XXX */
702 PS_ADD("wchan", "%u", 0); /* XXX */
703 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
704 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
705 PS_ADD("exitsignal", "%d", 0); /* XXX */
706 PS_ADD("processor", "%u", kp.ki_lastcpu);
707 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
708 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
716 * Filler function for proc/pid/statm
719 linprocfs_doprocstatm(PFS_FILL_ARGS)
721 struct kinfo_proc kp;
725 fill_kinfo_proc(p, &kp);
729 * See comments in linprocfs_doprocstatus() regarding the
730 * computation of lsize.
732 /* size resident share trs drs lrs dt */
733 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
734 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
735 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
736 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
737 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
738 lsize = B2P(kp.ki_size) - kp.ki_dsize -
739 kp.ki_ssize - kp.ki_tsize - 1;
740 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
741 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
747 * Filler function for proc/pid/status
750 linprocfs_doprocstatus(PFS_FILL_ARGS)
752 struct kinfo_proc kp;
760 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
762 if (P_SHOULDSTOP(p)) {
763 state = "T (stopped)";
770 if (p->p_flag & P_WEXIT) {
771 state = "X (exiting)";
774 switch(td2->td_state) {
776 state = "S (sleeping)";
780 state = "R (running)";
783 state = "? (unknown)";
788 state = "Z (zombie)";
791 state = "? (unknown)";
796 fill_kinfo_proc(p, &kp);
797 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
798 sbuf_printf(sb, "State:\t%s\n", state);
803 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
804 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
805 p->p_pptr->p_pid : 0);
806 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
808 p->p_ucred->cr_svuid,
809 /* FreeBSD doesn't have fsuid */
811 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
813 p->p_ucred->cr_svgid,
814 /* FreeBSD doesn't have fsgid */
816 sbuf_cat(sb, "Groups:\t");
817 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
818 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
825 * While our approximation of VmLib may not be accurate (I
826 * don't know of a simple way to verify it, and I'm not sure
827 * it has much meaning anyway), I believe it's good enough.
829 * The same code that could (I think) accurately compute VmLib
830 * could also compute VmLck, but I don't really care enough to
831 * implement it. Submissions are welcome.
833 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
834 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
835 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
836 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
837 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
838 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
839 lsize = B2P(kp.ki_size) - kp.ki_dsize -
840 kp.ki_ssize - kp.ki_tsize - 1;
841 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
846 * We support up to 128 signals, while Linux supports 32,
847 * but we only define 32 (the same 32 as Linux, to boot), so
848 * just show the lower 32 bits of each mask. XXX hack.
850 * NB: on certain platforms (Sparc at least) Linux actually
851 * supports 64 signals, but this code is a long way from
852 * running on anything but i386, so ignore that for now.
855 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
857 * I can't seem to find out where the signal mask is in
858 * relation to struct proc, so SigBlk is left unimplemented.
860 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
862 mtx_lock(&ps->ps_mtx);
863 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
864 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
865 mtx_unlock(&ps->ps_mtx);
869 * Linux also prints the capability masks, but we don't have
870 * capabilities yet, and when we do get them they're likely to
871 * be meaningless to Linux programs, so we lie. XXX
873 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
874 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
875 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
882 * Filler function for proc/pid/cwd
885 linprocfs_doproccwd(PFS_FILL_ARGS)
887 char *fullpath = "unknown";
888 char *freepath = NULL;
890 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
891 sbuf_printf(sb, "%s", fullpath);
893 free(freepath, M_TEMP);
898 * Filler function for proc/pid/root
901 linprocfs_doprocroot(PFS_FILL_ARGS)
904 char *fullpath = "unknown";
905 char *freepath = NULL;
907 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
908 vn_fullpath(td, rvp, &fullpath, &freepath);
909 sbuf_printf(sb, "%s", fullpath);
911 free(freepath, M_TEMP);
916 * Filler function for proc/pid/cmdline
919 linprocfs_doproccmdline(PFS_FILL_ARGS)
924 if ((ret = p_cansee(td, p)) != 0) {
930 * Mimic linux behavior and pass only processes with usermode
931 * address space as valid. Return zero silently otherwize.
933 if (p->p_vmspace == &vmspace0) {
937 if (p->p_args != NULL) {
938 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
943 if ((p->p_flag & P_SYSTEM) != 0) {
950 ret = proc_getargv(td, p, sb);
955 * Filler function for proc/pid/environ
958 linprocfs_doprocenviron(PFS_FILL_ARGS)
963 if ((ret = p_candebug(td, p)) != 0) {
969 * Mimic linux behavior and pass only processes with usermode
970 * address space as valid. Return zero silently otherwize.
972 if (p->p_vmspace == &vmspace0) {
977 if ((p->p_flag & P_SYSTEM) != 0) {
984 ret = proc_getenvv(td, p, sb);
989 * Filler function for proc/pid/maps
992 linprocfs_doprocmaps(PFS_FILL_ARGS)
996 vm_map_entry_t entry, tmp_entry;
997 vm_object_t obj, tobj, lobj;
998 vm_offset_t e_start, e_end;
999 vm_ooffset_t off = 0;
1001 unsigned int last_timestamp;
1002 char *name = "", *freename = NULL;
1004 int ref_count, shadow_count, flags;
1010 error = p_candebug(td, p);
1015 if (uio->uio_rw != UIO_READ)
1016 return (EOPNOTSUPP);
1019 vm = vmspace_acquire_ref(p);
1023 vm_map_lock_read(map);
1024 for (entry = map->header.next; entry != &map->header;
1025 entry = entry->next) {
1028 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1030 e_prot = entry->protection;
1031 e_start = entry->start;
1033 obj = entry->object.vm_object;
1034 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1035 VM_OBJECT_RLOCK(tobj);
1037 VM_OBJECT_RUNLOCK(lobj);
1040 last_timestamp = map->timestamp;
1041 vm_map_unlock_read(map);
1044 off = IDX_TO_OFF(lobj->size);
1045 if (lobj->type == OBJT_VNODE) {
1053 VM_OBJECT_RUNLOCK(lobj);
1055 ref_count = obj->ref_count;
1056 shadow_count = obj->shadow_count;
1057 VM_OBJECT_RUNLOCK(obj);
1059 vn_fullpath(td, vp, &name, &freename);
1060 vn_lock(vp, LK_SHARED | LK_RETRY);
1061 VOP_GETATTR(vp, &vat, td->td_ucred);
1062 ino = vat.va_fileid;
1073 * start, end, access, offset, major, minor, inode, name.
1075 error = sbuf_printf(sb,
1076 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1077 (u_long)e_start, (u_long)e_end,
1078 (e_prot & VM_PROT_READ)?"r":"-",
1079 (e_prot & VM_PROT_WRITE)?"w":"-",
1080 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1090 free(freename, M_TEMP);
1091 vm_map_lock_read(map);
1096 if (last_timestamp != map->timestamp) {
1098 * Look again for the entry because the map was
1099 * modified while it was unlocked. Specifically,
1100 * the entry may have been clipped, merged, or deleted.
1102 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1106 vm_map_unlock_read(map);
1113 * Filler function for proc/net/dev
1116 linprocfs_donetdev(PFS_FILL_ARGS)
1118 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1121 sbuf_printf(sb, "%6s|%58s|%s\n"
1123 "Inter-", " Receive", " Transmit",
1125 "bytes packets errs drop fifo frame compressed multicast",
1126 "bytes packets errs drop fifo colls carrier compressed");
1128 CURVNET_SET(TD_TO_VNET(curthread));
1130 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1131 linux_ifname(ifp, ifname, sizeof ifname);
1132 sbuf_printf(sb, "%6.6s: ", ifname);
1133 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1134 ifp->if_ibytes, /* rx_bytes */
1135 ifp->if_ipackets, /* rx_packets */
1136 ifp->if_ierrors, /* rx_errors */
1137 ifp->if_iqdrops, /* rx_dropped +
1138 * rx_missed_errors */
1139 0UL, /* rx_fifo_errors */
1140 0UL, /* rx_length_errors +
1143 * rx_frame_errors */
1144 0UL, /* rx_compressed */
1145 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1146 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1147 ifp->if_obytes, /* tx_bytes */
1148 ifp->if_opackets, /* tx_packets */
1149 ifp->if_oerrors, /* tx_errors */
1150 0UL, /* tx_dropped */
1151 0UL, /* tx_fifo_errors */
1152 ifp->if_collisions, /* collisions */
1153 0UL, /* tx_carrier_errors +
1154 * tx_aborted_errors +
1155 * tx_window_errors +
1156 * tx_heartbeat_errors */
1157 0UL); /* tx_compressed */
1166 * Filler function for proc/sys/kernel/osrelease
1169 linprocfs_doosrelease(PFS_FILL_ARGS)
1171 char osrelease[LINUX_MAX_UTSNAME];
1173 linux_get_osrelease(td, osrelease);
1174 sbuf_printf(sb, "%s\n", osrelease);
1180 * Filler function for proc/sys/kernel/ostype
1183 linprocfs_doostype(PFS_FILL_ARGS)
1185 char osname[LINUX_MAX_UTSNAME];
1187 linux_get_osname(td, osname);
1188 sbuf_printf(sb, "%s\n", osname);
1194 * Filler function for proc/sys/kernel/version
1197 linprocfs_doosbuild(PFS_FILL_ARGS)
1200 linprocfs_osbuild(td, sb);
1206 * Filler function for proc/sys/kernel/msgmni
1209 linprocfs_domsgmni(PFS_FILL_ARGS)
1212 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1217 * Filler function for proc/sys/kernel/pid_max
1220 linprocfs_dopid_max(PFS_FILL_ARGS)
1223 sbuf_printf(sb, "%i\n", PID_MAX);
1228 * Filler function for proc/sys/kernel/sem
1231 linprocfs_dosem(PFS_FILL_ARGS)
1234 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1235 seminfo.semopm, seminfo.semmni);
1240 * Filler function for proc/scsi/device_info
1243 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1250 * Filler function for proc/scsi/scsi
1253 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1259 extern struct cdevsw *cdevsw[];
1262 * Filler function for proc/devices
1265 linprocfs_dodevices(PFS_FILL_ARGS)
1268 sbuf_printf(sb, "Character devices:\n");
1270 char_devices = linux_get_char_devices();
1271 sbuf_printf(sb, "%s", char_devices);
1272 linux_free_get_char_devices(char_devices);
1274 sbuf_printf(sb, "\nBlock devices:\n");
1280 * Filler function for proc/cmdline
1283 linprocfs_docmdline(PFS_FILL_ARGS)
1286 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1287 sbuf_printf(sb, " ro root=302\n");
1292 * Filler function for proc/filesystems
1295 linprocfs_dofilesystems(PFS_FILL_ARGS)
1297 struct vfsconf *vfsp;
1300 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1301 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1302 sbuf_printf(sb, "nodev");
1303 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1311 * Filler function for proc/modules
1314 linprocfs_domodules(PFS_FILL_ARGS)
1316 struct linker_file *lf;
1318 TAILQ_FOREACH(lf, &linker_files, link) {
1319 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1320 (unsigned long)lf->size, lf->refs);
1327 * Filler function for proc/pid/fd
1330 linprocfs_dofdescfs(PFS_FILL_ARGS)
1334 sbuf_printf(sb, "/dev/fd");
1336 sbuf_printf(sb, "unknown");
1342 * Filler function for proc/sys/kernel/random/uuid
1345 linprocfs_douuid(PFS_FILL_ARGS)
1349 kern_uuidgen(&uuid, 1);
1350 sbuf_printf_uuid(sb, &uuid);
1351 sbuf_printf(sb, "\n");
1360 linprocfs_init(PFS_INIT_ARGS)
1362 struct pfs_node *root;
1363 struct pfs_node *dir;
1368 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1369 NULL, NULL, NULL, PFS_RD);
1370 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1371 NULL, NULL, NULL, PFS_RD);
1372 pfs_create_file(root, "devices", &linprocfs_dodevices,
1373 NULL, NULL, NULL, PFS_RD);
1374 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1375 NULL, NULL, NULL, PFS_RD);
1376 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1377 NULL, NULL, NULL, PFS_RD);
1378 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1379 NULL, NULL, NULL, PFS_RD);
1381 pfs_create_file(root, "modules", &linprocfs_domodules,
1382 NULL, NULL, NULL, PFS_RD);
1384 pfs_create_file(root, "mounts", &linprocfs_domtab,
1385 NULL, NULL, NULL, PFS_RD);
1386 pfs_create_file(root, "mtab", &linprocfs_domtab,
1387 NULL, NULL, NULL, PFS_RD);
1388 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1389 NULL, NULL, NULL, PFS_RD);
1390 pfs_create_link(root, "self", &procfs_docurproc,
1391 NULL, NULL, NULL, 0);
1392 pfs_create_file(root, "stat", &linprocfs_dostat,
1393 NULL, NULL, NULL, PFS_RD);
1394 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1395 NULL, NULL, NULL, PFS_RD);
1396 pfs_create_file(root, "uptime", &linprocfs_douptime,
1397 NULL, NULL, NULL, PFS_RD);
1398 pfs_create_file(root, "version", &linprocfs_doversion,
1399 NULL, NULL, NULL, PFS_RD);
1402 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1403 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1404 NULL, NULL, NULL, PFS_RD);
1406 /* /proc/<pid>/... */
1407 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1408 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1409 NULL, NULL, NULL, PFS_RD);
1410 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1411 NULL, NULL, NULL, 0);
1412 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1413 NULL, NULL, NULL, PFS_RD);
1414 pfs_create_link(dir, "exe", &procfs_doprocfile,
1415 NULL, &procfs_notsystem, NULL, 0);
1416 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1417 NULL, NULL, NULL, PFS_RD);
1418 pfs_create_file(dir, "mem", &procfs_doprocmem,
1419 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1420 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1421 NULL, NULL, NULL, 0);
1422 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1423 NULL, NULL, NULL, PFS_RD);
1424 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1425 NULL, NULL, NULL, PFS_RD);
1426 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1427 NULL, NULL, NULL, PFS_RD);
1428 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1429 NULL, NULL, NULL, 0);
1431 /* /proc/scsi/... */
1432 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1433 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1434 NULL, NULL, NULL, PFS_RD);
1435 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1436 NULL, NULL, NULL, PFS_RD);
1439 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1440 /* /proc/sys/kernel/... */
1441 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1442 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1443 NULL, NULL, NULL, PFS_RD);
1444 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1445 NULL, NULL, NULL, PFS_RD);
1446 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1447 NULL, NULL, NULL, PFS_RD);
1448 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1449 NULL, NULL, NULL, PFS_RD);
1450 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1451 NULL, NULL, NULL, PFS_RD);
1452 pfs_create_file(dir, "sem", &linprocfs_dosem,
1453 NULL, NULL, NULL, PFS_RD);
1455 /* /proc/sys/kernel/random/... */
1456 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1457 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1458 NULL, NULL, NULL, PFS_RD);
1467 linprocfs_uninit(PFS_INIT_ARGS)
1470 /* nothing to do, pseudofs will GC */
1474 PSEUDOFS(linprocfs, 1, 0);
1475 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1476 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1477 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1478 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);