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>
75 #include <sys/vmmeter.h>
76 #include <sys/vnode.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 #ifdef COMPAT_FREEBSD32
101 #include <compat/freebsd32/freebsd32_util.h>
104 #ifdef COMPAT_LINUX32 /* XXX */
105 #include <machine/../linux32/linux.h>
107 #include <machine/../linux/linux.h>
109 #include <compat/linux/linux_ioctl.h>
110 #include <compat/linux/linux_mib.h>
111 #include <compat/linux/linux_util.h>
112 #include <fs/pseudofs/pseudofs.h>
113 #include <fs/procfs/procfs.h>
116 * Various conversion macros
118 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
119 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
120 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
121 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
122 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
123 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
124 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
125 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
128 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
130 * The linux procfs state field displays one of the characters RSDZTW to
131 * denote running, sleeping in an interruptible wait, waiting in an
132 * uninterruptible disk sleep, a zombie process, process is being traced
133 * or stopped, or process is paging respectively.
135 * Our struct kinfo_proc contains the variable ki_stat which contains a
136 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
138 * This character array is used with ki_stati-1 as an index and tries to
139 * map our states to suitable linux states.
141 static char linux_state[] = "RRSTZDD";
144 * Filler function for proc/meminfo
147 linprocfs_domeminfo(PFS_FILL_ARGS)
149 unsigned long memtotal; /* total memory in bytes */
150 unsigned long memused; /* used memory in bytes */
151 unsigned long memfree; /* free memory in bytes */
152 unsigned long memshared; /* shared memory ??? */
153 unsigned long buffers, cached; /* buffer / cache memory ??? */
154 unsigned long long swaptotal; /* total swap space in bytes */
155 unsigned long long swapused; /* used swap space in bytes */
156 unsigned long long swapfree; /* free swap space in bytes */
160 memtotal = physmem * PAGE_SIZE;
162 * The correct thing here would be:
164 memfree = cnt.v_free_count * PAGE_SIZE;
165 memused = memtotal - memfree;
167 * but it might mislead linux binaries into thinking there
168 * is very little memory left, so we cheat and tell them that
169 * all memory that isn't wired down is free.
171 memused = cnt.v_wire_count * PAGE_SIZE;
172 memfree = memtotal - memused;
173 swap_pager_status(&i, &j);
174 swaptotal = (unsigned long long)i * PAGE_SIZE;
175 swapused = (unsigned long long)j * PAGE_SIZE;
176 swapfree = swaptotal - swapused;
178 mtx_lock(&vm_object_list_mtx);
179 TAILQ_FOREACH(object, &vm_object_list, object_list)
180 if (object->shadow_count > 1)
181 memshared += object->resident_page_count;
182 mtx_unlock(&vm_object_list_mtx);
183 memshared *= PAGE_SIZE;
185 * We'd love to be able to write:
189 * but bufspace is internal to vfs_bio.c and we don't feel
190 * like unstaticizing it just for linprocfs's sake.
193 cached = cnt.v_cache_count * PAGE_SIZE;
196 " total: used: free: shared: buffers: cached:\n"
197 "Mem: %lu %lu %lu %lu %lu %lu\n"
198 "Swap: %llu %llu %llu\n"
199 "MemTotal: %9lu kB\n"
201 "MemShared:%9lu kB\n"
204 "SwapTotal:%9llu kB\n"
205 "SwapFree: %9llu kB\n",
206 memtotal, memused, memfree, memshared, buffers, cached,
207 swaptotal, swapused, swapfree,
208 B2K(memtotal), B2K(memfree),
209 B2K(memshared), B2K(buffers), B2K(cached),
210 B2K(swaptotal), B2K(swapfree));
215 #if defined(__i386__) || defined(__amd64__)
217 * Filler function for proc/cpuinfo (i386 & amd64 version)
220 linprocfs_docpuinfo(PFS_FILL_ARGS)
226 int class, fqmhz, fqkhz;
230 * We default the flags to include all non-conflicting flags,
231 * and the Intel versions of conflicting flags.
233 static char *flags[] = {
234 "fpu", "vme", "de", "pse", "tsc",
235 "msr", "pae", "mce", "cx8", "apic",
236 "sep", "sep", "mtrr", "pge", "mca",
237 "cmov", "pat", "pse36", "pn", "b19",
238 "b20", "b21", "mmxext", "mmx", "fxsr",
239 "xmm", "sse2", "b27", "b28", "b29",
263 #else /* __amd64__ */
270 hw_model[0] = CTL_HW;
271 hw_model[1] = HW_MODEL;
273 size = sizeof(model);
274 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
275 strcpy(model, "unknown");
276 for (i = 0; i < mp_ncpus; ++i) {
279 "vendor_id\t: %.20s\n"
283 "stepping\t: %u\n\n",
284 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
285 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
286 /* XXX per-cpu vendor / class / model / id? */
289 sbuf_cat(sb, "flags\t\t:");
292 switch (cpu_vendor_id) {
297 case CPU_VENDOR_CYRIX:
303 for (i = 0; i < 32; i++)
304 if (cpu_feature & (1 << i))
305 sbuf_printf(sb, " %s", flags[i]);
307 freq = atomic_load_acq_64(&tsc_freq);
309 fqmhz = (freq + 4999) / 1000000;
310 fqkhz = ((freq + 4999) / 10000) % 100;
312 "cpu MHz\t\t: %d.%02d\n"
313 "bogomips\t: %d.%02d\n",
314 fqmhz, fqkhz, fqmhz, fqkhz);
319 #endif /* __i386__ || __amd64__ */
322 * Filler function for proc/mtab
324 * This file doesn't exist in Linux' procfs, but is included here so
325 * users can symlink /compat/linux/etc/mtab to /proc/mtab
328 linprocfs_domtab(PFS_FILL_ARGS)
333 char *dlep, *flep, *mntto, *mntfrom, *fstype;
337 /* resolve symlinks etc. in the emulation tree prefix */
338 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
341 lep = linux_emul_path;
343 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
346 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
348 lep_len = strlen(lep);
350 mtx_lock(&mountlist_mtx);
352 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
353 /* determine device name */
354 mntfrom = mp->mnt_stat.f_mntfromname;
356 /* determine mount point */
357 mntto = mp->mnt_stat.f_mntonname;
358 if (strncmp(mntto, lep, lep_len) == 0 &&
359 mntto[lep_len] == '/')
362 /* determine fs type */
363 fstype = mp->mnt_stat.f_fstypename;
364 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365 mntfrom = fstype = "proc";
366 else if (strcmp(fstype, "procfs") == 0)
369 if (strcmp(fstype, "linsysfs") == 0) {
370 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
373 /* For Linux msdosfs is called vfat */
374 if (strcmp(fstype, "msdosfs") == 0)
376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
379 #define ADD_OPTION(opt, name) \
380 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
381 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
382 ADD_OPTION(MNT_NOEXEC, "noexec");
383 ADD_OPTION(MNT_NOSUID, "nosuid");
384 ADD_OPTION(MNT_UNION, "union");
385 ADD_OPTION(MNT_ASYNC, "async");
386 ADD_OPTION(MNT_SUIDDIR, "suiddir");
387 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
388 ADD_OPTION(MNT_NOATIME, "noatime");
390 /* a real Linux mtab will also show NFS options */
391 sbuf_printf(sb, " 0 0\n");
393 mtx_unlock(&mountlist_mtx);
400 * Filler function for proc/partitions
404 linprocfs_dopartitions(PFS_FILL_ARGS)
408 struct g_provider *pp;
416 /* resolve symlinks etc. in the emulation tree prefix */
417 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
420 lep = linux_emul_path;
422 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
425 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
427 lep_len = strlen(lep);
431 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
432 "ruse wio wmerge wsect wuse running use aveq\n");
434 LIST_FOREACH(cp, &g_classes, class) {
435 if (strcmp(cp->name, "DISK") == 0 ||
436 strcmp(cp->name, "PART") == 0)
437 LIST_FOREACH(gp, &cp->geom, geom) {
438 LIST_FOREACH(pp, &gp->provider, provider) {
439 if (linux_driver_get_major_minor(
440 pp->name, &major, &minor) != 0) {
444 sbuf_printf(sb, "%d %d %lld %s "
446 "%d %d %d %d %d %d\n",
448 (long long)pp->mediasize, pp->name,
463 * Filler function for proc/stat
466 linprocfs_dostat(PFS_FILL_ARGS)
469 long cp_time[CPUSTATES];
473 read_cpu_time(cp_time);
474 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
475 T2J(cp_time[CP_USER]),
476 T2J(cp_time[CP_NICE]),
477 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
478 T2J(cp_time[CP_IDLE]));
481 cp = pcpu->pc_cp_time;
482 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
485 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
501 (long long)boottime.tv_sec);
506 * Filler function for proc/uptime
509 linprocfs_douptime(PFS_FILL_ARGS)
511 long cp_time[CPUSTATES];
515 read_cpu_time(cp_time);
516 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
517 (long long)tv.tv_sec, tv.tv_usec / 10000,
518 T2S(cp_time[CP_IDLE] / mp_ncpus),
519 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
527 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
533 strncpy(osbuild, version, 256);
535 cp1 = strstr(osbuild, "\n");
536 cp2 = strstr(osbuild, ":");
539 cp1 = strstr(osbuild, "#");
543 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
546 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
553 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
559 cp = strstr(version, "\n ");
561 strncpy(builder, cp + 5, 256);
563 cp = strstr(builder, ":");
568 sbuf_cat(sb, builder);
571 sbuf_cat(sb, "des@freebsd.org");
575 * Filler function for proc/version
578 linprocfs_doversion(PFS_FILL_ARGS)
580 char osname[LINUX_MAX_UTSNAME];
581 char osrelease[LINUX_MAX_UTSNAME];
583 linux_get_osname(td, osname);
584 linux_get_osrelease(td, osrelease);
585 sbuf_printf(sb, "%s version %s (", osname, osrelease);
586 linprocfs_osbuilder(td, sb);
587 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
588 linprocfs_osbuild(td, sb);
595 * Filler function for proc/loadavg
598 linprocfs_doloadavg(PFS_FILL_ARGS)
602 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
603 (int)(averunnable.ldavg[0] / averunnable.fscale),
604 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
605 (int)(averunnable.ldavg[1] / averunnable.fscale),
606 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
607 (int)(averunnable.ldavg[2] / averunnable.fscale),
608 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
609 1, /* number of running tasks */
610 nprocs, /* number of tasks */
611 lastpid /* the last pid */
617 * Filler function for proc/pid/stat
620 linprocfs_doprocstat(PFS_FILL_ARGS)
622 struct kinfo_proc kp;
624 static int ratelimit = 0;
625 vm_offset_t startcode, startdata;
628 fill_kinfo_proc(p, &kp);
630 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
631 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
636 sbuf_printf(sb, "%d", p->p_pid);
637 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
638 PS_ADD("comm", "(%s)", p->p_comm);
639 if (kp.ki_stat > sizeof(linux_state)) {
642 if (ratelimit == 0) {
643 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
644 kp.ki_stat, sizeof(linux_state));
648 state = linux_state[kp.ki_stat - 1];
649 PS_ADD("state", "%c", state);
650 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
651 PS_ADD("pgrp", "%d", p->p_pgid);
652 PS_ADD("session", "%d", p->p_session->s_sid);
654 PS_ADD("tty", "%d", kp.ki_tdev);
655 PS_ADD("tpgid", "%d", kp.ki_tpgid);
656 PS_ADD("flags", "%u", 0); /* XXX */
657 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
658 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
659 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
660 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
661 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
662 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
663 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
664 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
665 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
666 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
667 PS_ADD("0", "%d", 0); /* removed field */
668 PS_ADD("itrealvalue", "%d", 0); /* XXX */
669 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
670 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
671 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
672 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
673 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
674 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
675 PS_ADD("startstack", "%u", 0); /* XXX */
676 PS_ADD("kstkesp", "%u", 0); /* XXX */
677 PS_ADD("kstkeip", "%u", 0); /* XXX */
678 PS_ADD("signal", "%u", 0); /* XXX */
679 PS_ADD("blocked", "%u", 0); /* XXX */
680 PS_ADD("sigignore", "%u", 0); /* XXX */
681 PS_ADD("sigcatch", "%u", 0); /* XXX */
682 PS_ADD("wchan", "%u", 0); /* XXX */
683 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
684 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
685 PS_ADD("exitsignal", "%d", 0); /* XXX */
686 PS_ADD("processor", "%u", kp.ki_lastcpu);
687 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
688 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
696 * Filler function for proc/pid/statm
699 linprocfs_doprocstatm(PFS_FILL_ARGS)
701 struct kinfo_proc kp;
705 fill_kinfo_proc(p, &kp);
709 * See comments in linprocfs_doprocstatus() regarding the
710 * computation of lsize.
712 /* size resident share trs drs lrs dt */
713 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
714 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
715 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
716 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
717 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
718 lsize = B2P(kp.ki_size) - kp.ki_dsize -
719 kp.ki_ssize - kp.ki_tsize - 1;
720 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
721 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
727 * Filler function for proc/pid/status
730 linprocfs_doprocstatus(PFS_FILL_ARGS)
732 struct kinfo_proc kp;
740 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
742 if (P_SHOULDSTOP(p)) {
743 state = "T (stopped)";
750 if (p->p_flag & P_WEXIT) {
751 state = "X (exiting)";
754 switch(td2->td_state) {
756 state = "S (sleeping)";
760 state = "R (running)";
763 state = "? (unknown)";
768 state = "Z (zombie)";
771 state = "? (unknown)";
776 fill_kinfo_proc(p, &kp);
777 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
778 sbuf_printf(sb, "State:\t%s\n", state);
783 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
784 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
785 p->p_pptr->p_pid : 0);
786 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
788 p->p_ucred->cr_svuid,
789 /* FreeBSD doesn't have fsuid */
791 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
793 p->p_ucred->cr_svgid,
794 /* FreeBSD doesn't have fsgid */
796 sbuf_cat(sb, "Groups:\t");
797 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
798 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
805 * While our approximation of VmLib may not be accurate (I
806 * don't know of a simple way to verify it, and I'm not sure
807 * it has much meaning anyway), I believe it's good enough.
809 * The same code that could (I think) accurately compute VmLib
810 * could also compute VmLck, but I don't really care enough to
811 * implement it. Submissions are welcome.
813 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
814 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
815 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
816 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
817 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
818 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
819 lsize = B2P(kp.ki_size) - kp.ki_dsize -
820 kp.ki_ssize - kp.ki_tsize - 1;
821 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
826 * We support up to 128 signals, while Linux supports 32,
827 * but we only define 32 (the same 32 as Linux, to boot), so
828 * just show the lower 32 bits of each mask. XXX hack.
830 * NB: on certain platforms (Sparc at least) Linux actually
831 * supports 64 signals, but this code is a long way from
832 * running on anything but i386, so ignore that for now.
835 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
837 * I can't seem to find out where the signal mask is in
838 * relation to struct proc, so SigBlk is left unimplemented.
840 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
842 mtx_lock(&ps->ps_mtx);
843 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
844 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
845 mtx_unlock(&ps->ps_mtx);
849 * Linux also prints the capability masks, but we don't have
850 * capabilities yet, and when we do get them they're likely to
851 * be meaningless to Linux programs, so we lie. XXX
853 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
854 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
855 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
862 * Filler function for proc/pid/cwd
865 linprocfs_doproccwd(PFS_FILL_ARGS)
867 char *fullpath = "unknown";
868 char *freepath = NULL;
870 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
871 sbuf_printf(sb, "%s", fullpath);
873 free(freepath, M_TEMP);
878 * Filler function for proc/pid/root
881 linprocfs_doprocroot(PFS_FILL_ARGS)
884 char *fullpath = "unknown";
885 char *freepath = NULL;
887 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
888 vn_fullpath(td, rvp, &fullpath, &freepath);
889 sbuf_printf(sb, "%s", fullpath);
891 free(freepath, M_TEMP);
895 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */
896 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */
899 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
900 void (*resolver)(const struct ps_strings, u_long *, int *))
904 struct ps_strings pss;
905 int ret, i, n_elements, elm_len;
907 char **env_vector, *envp;
908 char env_string[UIO_CHUNK_SZ];
909 #ifdef COMPAT_FREEBSD32
910 struct freebsd32_ps_strings pss32;
911 uint32_t *env_vector32;
914 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \
916 iov.iov_base = (caddr_t)(base); \
917 iov.iov_len = (len); \
918 uio.uio_iov = &(iov); \
919 uio.uio_iovcnt = (cnt); \
920 uio.uio_offset = (off_t)(offset); \
921 uio.uio_resid = (sz); \
922 uio.uio_segflg = (flg); \
927 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
929 #ifdef COMPAT_FREEBSD32
931 if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
932 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
934 elm_len = sizeof(int32_t);
935 envp = (char *)env_vector32;
937 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
938 (off_t)(p->p_sysent->sv_psstrings),
939 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
940 ret = proc_rwmem(p, &tmp_uio);
943 pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
944 pss.ps_nargvstr = pss32.ps_nargvstr;
945 pss.ps_envstr = PTRIN(pss32.ps_envstr);
946 pss.ps_nenvstr = pss32.ps_nenvstr;
949 elm_len = sizeof(char *);
950 envp = (char *)env_vector;
952 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
953 (off_t)(p->p_sysent->sv_psstrings),
954 sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
955 ret = proc_rwmem(p, &tmp_uio);
958 #ifdef COMPAT_FREEBSD32
962 /* Get the array address and the number of elements */
963 resolver(pss, &addr, &n_elements);
965 /* Consistent with lib/libkvm/kvm_proc.c */
966 if (n_elements > MAX_ARGV_STR) {
971 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
972 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
973 ret = proc_rwmem(p, &tmp_uio);
976 #ifdef COMPAT_FREEBSD32
977 if (env_vector32 != NULL) {
978 for (i = 0; i < n_elements; i++)
979 env_vector[i] = PTRIN(env_vector32[i]);
983 /* Now we can iterate through the list of strings */
984 for (i = 0; i < n_elements; i++) {
985 pbegin = (vm_offset_t)env_vector[i];
987 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
988 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
989 ret = proc_rwmem(p, &tmp_uio);
993 if (!strvalid(env_string, UIO_CHUNK_SZ)) {
995 * We didn't find the end of the string.
996 * Add the string to the buffer and move
997 * the pointer. But do not allow strings
998 * of unlimited length.
1000 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1001 if (sbuf_len(sb) >= ARG_MAX) {
1005 pbegin += UIO_CHUNK_SZ;
1007 sbuf_cat(sb, env_string);
1011 sbuf_bcat(sb, "", 1);
1016 free(env_vector, M_TEMP);
1017 #ifdef COMPAT_FREEBSD32
1018 free(env_vector32, M_TEMP);
1024 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1027 *addr = (u_long) ps.ps_argvstr;
1028 *n = ps.ps_nargvstr;
1032 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1035 *addr = (u_long) ps.ps_envstr;
1040 * Filler function for proc/pid/cmdline
1043 linprocfs_doproccmdline(PFS_FILL_ARGS)
1048 if ((ret = p_cansee(td, p)) != 0) {
1052 if (p->p_args != NULL) {
1053 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1059 ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1064 * Filler function for proc/pid/environ
1067 linprocfs_doprocenviron(PFS_FILL_ARGS)
1072 if ((ret = p_cansee(td, p)) != 0) {
1078 ret = linprocfs_doargv(td, p, sb, ps_string_env);
1083 * Filler function for proc/pid/maps
1086 linprocfs_doprocmaps(PFS_FILL_ARGS)
1090 vm_map_entry_t entry, tmp_entry;
1091 vm_object_t obj, tobj, lobj;
1092 vm_offset_t e_start, e_end;
1093 vm_ooffset_t off = 0;
1095 unsigned int last_timestamp;
1096 char *name = "", *freename = NULL;
1098 int ref_count, shadow_count, flags;
1105 error = p_candebug(td, p);
1110 if (uio->uio_rw != UIO_READ)
1111 return (EOPNOTSUPP);
1114 vm = vmspace_acquire_ref(p);
1118 vm_map_lock_read(map);
1119 for (entry = map->header.next; entry != &map->header;
1120 entry = entry->next) {
1123 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1125 e_prot = entry->protection;
1126 e_start = entry->start;
1128 obj = entry->object.vm_object;
1129 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1130 VM_OBJECT_LOCK(tobj);
1132 VM_OBJECT_UNLOCK(lobj);
1135 last_timestamp = map->timestamp;
1136 vm_map_unlock_read(map);
1139 off = IDX_TO_OFF(lobj->size);
1140 if (lobj->type == OBJT_VNODE) {
1148 VM_OBJECT_UNLOCK(lobj);
1150 ref_count = obj->ref_count;
1151 shadow_count = obj->shadow_count;
1152 VM_OBJECT_UNLOCK(obj);
1154 vn_fullpath(td, vp, &name, &freename);
1155 locked = VFS_LOCK_GIANT(vp->v_mount);
1156 vn_lock(vp, LK_SHARED | LK_RETRY);
1157 VOP_GETATTR(vp, &vat, td->td_ucred);
1158 ino = vat.va_fileid;
1160 VFS_UNLOCK_GIANT(locked);
1170 * start, end, access, offset, major, minor, inode, name.
1172 error = sbuf_printf(sb,
1173 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1174 (u_long)e_start, (u_long)e_end,
1175 (e_prot & VM_PROT_READ)?"r":"-",
1176 (e_prot & VM_PROT_WRITE)?"w":"-",
1177 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1187 free(freename, M_TEMP);
1188 vm_map_lock_read(map);
1193 if (last_timestamp != map->timestamp) {
1195 * Look again for the entry because the map was
1196 * modified while it was unlocked. Specifically,
1197 * the entry may have been clipped, merged, or deleted.
1199 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1203 vm_map_unlock_read(map);
1210 * Filler function for proc/net/dev
1213 linprocfs_donetdev(PFS_FILL_ARGS)
1215 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1218 sbuf_printf(sb, "%6s|%58s|%s\n"
1220 "Inter-", " Receive", " Transmit",
1222 "bytes packets errs drop fifo frame compressed multicast",
1223 "bytes packets errs drop fifo colls carrier compressed");
1225 CURVNET_SET(TD_TO_VNET(curthread));
1227 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1228 linux_ifname(ifp, ifname, sizeof ifname);
1229 sbuf_printf(sb, "%6.6s: ", ifname);
1230 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1231 ifp->if_ibytes, /* rx_bytes */
1232 ifp->if_ipackets, /* rx_packets */
1233 ifp->if_ierrors, /* rx_errors */
1234 ifp->if_iqdrops, /* rx_dropped +
1235 * rx_missed_errors */
1236 0UL, /* rx_fifo_errors */
1237 0UL, /* rx_length_errors +
1240 * rx_frame_errors */
1241 0UL, /* rx_compressed */
1242 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1243 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1244 ifp->if_obytes, /* tx_bytes */
1245 ifp->if_opackets, /* tx_packets */
1246 ifp->if_oerrors, /* tx_errors */
1247 0UL, /* tx_dropped */
1248 0UL, /* tx_fifo_errors */
1249 ifp->if_collisions, /* collisions */
1250 0UL, /* tx_carrier_errors +
1251 * tx_aborted_errors +
1252 * tx_window_errors +
1253 * tx_heartbeat_errors */
1254 0UL); /* tx_compressed */
1263 * Filler function for proc/sys/kernel/osrelease
1266 linprocfs_doosrelease(PFS_FILL_ARGS)
1268 char osrelease[LINUX_MAX_UTSNAME];
1270 linux_get_osrelease(td, osrelease);
1271 sbuf_printf(sb, "%s\n", osrelease);
1277 * Filler function for proc/sys/kernel/ostype
1280 linprocfs_doostype(PFS_FILL_ARGS)
1282 char osname[LINUX_MAX_UTSNAME];
1284 linux_get_osname(td, osname);
1285 sbuf_printf(sb, "%s\n", osname);
1291 * Filler function for proc/sys/kernel/version
1294 linprocfs_doosbuild(PFS_FILL_ARGS)
1297 linprocfs_osbuild(td, sb);
1303 * Filler function for proc/sys/kernel/msgmni
1306 linprocfs_domsgmni(PFS_FILL_ARGS)
1309 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1314 * Filler function for proc/sys/kernel/pid_max
1317 linprocfs_dopid_max(PFS_FILL_ARGS)
1320 sbuf_printf(sb, "%i\n", PID_MAX);
1325 * Filler function for proc/sys/kernel/sem
1328 linprocfs_dosem(PFS_FILL_ARGS)
1331 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1332 seminfo.semopm, seminfo.semmni);
1337 * Filler function for proc/scsi/device_info
1340 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1347 * Filler function for proc/scsi/scsi
1350 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1356 extern struct cdevsw *cdevsw[];
1359 * Filler function for proc/devices
1362 linprocfs_dodevices(PFS_FILL_ARGS)
1365 sbuf_printf(sb, "Character devices:\n");
1367 char_devices = linux_get_char_devices();
1368 sbuf_printf(sb, "%s", char_devices);
1369 linux_free_get_char_devices(char_devices);
1371 sbuf_printf(sb, "\nBlock devices:\n");
1377 * Filler function for proc/cmdline
1380 linprocfs_docmdline(PFS_FILL_ARGS)
1383 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1384 sbuf_printf(sb, " ro root=302\n");
1389 * Filler function for proc/filesystems
1392 linprocfs_dofilesystems(PFS_FILL_ARGS)
1394 struct vfsconf *vfsp;
1397 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1398 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1399 sbuf_printf(sb, "nodev");
1400 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1408 * Filler function for proc/modules
1411 linprocfs_domodules(PFS_FILL_ARGS)
1413 struct linker_file *lf;
1415 TAILQ_FOREACH(lf, &linker_files, link) {
1416 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1417 (unsigned long)lf->size, lf->refs);
1424 * Filler function for proc/pid/fd
1427 linprocfs_dofdescfs(PFS_FILL_ARGS)
1431 sbuf_printf(sb, "/dev/fd");
1433 sbuf_printf(sb, "unknown");
1441 linprocfs_init(PFS_INIT_ARGS)
1443 struct pfs_node *root;
1444 struct pfs_node *dir;
1449 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1450 NULL, NULL, NULL, PFS_RD);
1451 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1452 NULL, NULL, NULL, PFS_RD);
1453 pfs_create_file(root, "devices", &linprocfs_dodevices,
1454 NULL, NULL, NULL, PFS_RD);
1455 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1456 NULL, NULL, NULL, PFS_RD);
1457 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1458 NULL, NULL, NULL, PFS_RD);
1459 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1460 NULL, NULL, NULL, PFS_RD);
1462 pfs_create_file(root, "modules", &linprocfs_domodules,
1463 NULL, NULL, NULL, PFS_RD);
1465 pfs_create_file(root, "mounts", &linprocfs_domtab,
1466 NULL, NULL, NULL, PFS_RD);
1467 pfs_create_file(root, "mtab", &linprocfs_domtab,
1468 NULL, NULL, NULL, PFS_RD);
1469 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1470 NULL, NULL, NULL, PFS_RD);
1471 pfs_create_link(root, "self", &procfs_docurproc,
1472 NULL, NULL, NULL, 0);
1473 pfs_create_file(root, "stat", &linprocfs_dostat,
1474 NULL, NULL, NULL, PFS_RD);
1475 pfs_create_file(root, "uptime", &linprocfs_douptime,
1476 NULL, NULL, NULL, PFS_RD);
1477 pfs_create_file(root, "version", &linprocfs_doversion,
1478 NULL, NULL, NULL, PFS_RD);
1481 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1482 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1483 NULL, NULL, NULL, PFS_RD);
1485 /* /proc/<pid>/... */
1486 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1487 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1488 NULL, NULL, NULL, PFS_RD);
1489 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1490 NULL, NULL, NULL, 0);
1491 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1492 NULL, NULL, NULL, PFS_RD);
1493 pfs_create_link(dir, "exe", &procfs_doprocfile,
1494 NULL, &procfs_notsystem, NULL, 0);
1495 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1496 NULL, NULL, NULL, PFS_RD);
1497 pfs_create_file(dir, "mem", &procfs_doprocmem,
1498 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1499 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1500 NULL, NULL, NULL, 0);
1501 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1502 NULL, NULL, NULL, PFS_RD);
1503 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1504 NULL, NULL, NULL, PFS_RD);
1505 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1506 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1508 NULL, NULL, NULL, 0);
1510 /* /proc/scsi/... */
1511 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1512 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1513 NULL, NULL, NULL, PFS_RD);
1514 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1515 NULL, NULL, NULL, PFS_RD);
1518 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1519 /* /proc/sys/kernel/... */
1520 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1521 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1522 NULL, NULL, NULL, PFS_RD);
1523 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1524 NULL, NULL, NULL, PFS_RD);
1525 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1526 NULL, NULL, NULL, PFS_RD);
1527 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1528 NULL, NULL, NULL, PFS_RD);
1529 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1530 NULL, NULL, NULL, PFS_RD);
1531 pfs_create_file(dir, "sem", &linprocfs_dosem,
1532 NULL, NULL, NULL, PFS_RD);
1541 linprocfs_uninit(PFS_INIT_ARGS)
1544 /* nothing to do, pseudofs will GC */
1548 PSEUDOFS(linprocfs, 1);
1549 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1550 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1551 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1552 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);