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)
225 int class, fqmhz, fqkhz;
229 * We default the flags to include all non-conflicting flags,
230 * and the Intel versions of conflicting flags.
232 static char *flags[] = {
233 "fpu", "vme", "de", "pse", "tsc",
234 "msr", "pae", "mce", "cx8", "apic",
235 "sep", "sep", "mtrr", "pge", "mca",
236 "cmov", "pat", "pse36", "pn", "b19",
237 "b20", "b21", "mmxext", "mmx", "fxsr",
238 "xmm", "sse2", "b27", "b28", "b29",
262 #else /* __amd64__ */
269 hw_model[0] = CTL_HW;
270 hw_model[1] = HW_MODEL;
272 size = sizeof(model);
273 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
274 strcpy(model, "unknown");
275 for (i = 0; i < mp_ncpus; ++i) {
278 "vendor_id\t: %.20s\n"
283 i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
284 /* XXX per-cpu vendor / class / model / id? */
287 sbuf_cat(sb, "flags\t\t:");
290 switch (cpu_vendor_id) {
295 case CPU_VENDOR_CYRIX:
301 for (i = 0; i < 32; i++)
302 if (cpu_feature & (1 << i))
303 sbuf_printf(sb, " %s", flags[i]);
306 fqmhz = (tsc_freq + 4999) / 1000000;
307 fqkhz = ((tsc_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 | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
338 lep = linux_emul_path;
340 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
343 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
345 lep_len = strlen(lep);
347 mtx_lock(&mountlist_mtx);
349 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
350 /* determine device name */
351 mntfrom = mp->mnt_stat.f_mntfromname;
353 /* determine mount point */
354 mntto = mp->mnt_stat.f_mntonname;
355 if (strncmp(mntto, lep, lep_len) == 0 &&
356 mntto[lep_len] == '/')
359 /* determine fs type */
360 fstype = mp->mnt_stat.f_fstypename;
361 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
362 mntfrom = fstype = "proc";
363 else if (strcmp(fstype, "procfs") == 0)
366 if (strcmp(fstype, "linsysfs") == 0) {
367 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
368 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
370 /* For Linux msdosfs is called vfat */
371 if (strcmp(fstype, "msdosfs") == 0)
373 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
374 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
376 #define ADD_OPTION(opt, name) \
377 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
378 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
379 ADD_OPTION(MNT_NOEXEC, "noexec");
380 ADD_OPTION(MNT_NOSUID, "nosuid");
381 ADD_OPTION(MNT_UNION, "union");
382 ADD_OPTION(MNT_ASYNC, "async");
383 ADD_OPTION(MNT_SUIDDIR, "suiddir");
384 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
385 ADD_OPTION(MNT_NOATIME, "noatime");
387 /* a real Linux mtab will also show NFS options */
388 sbuf_printf(sb, " 0 0\n");
390 mtx_unlock(&mountlist_mtx);
397 * Filler function for proc/partitions
401 linprocfs_dopartitions(PFS_FILL_ARGS)
405 struct g_provider *pp;
413 /* resolve symlinks etc. in the emulation tree prefix */
414 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
417 lep = linux_emul_path;
419 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
422 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
424 lep_len = strlen(lep);
428 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
429 "ruse wio wmerge wsect wuse running use aveq\n");
431 LIST_FOREACH(cp, &g_classes, class) {
432 if (strcmp(cp->name, "DISK") == 0 ||
433 strcmp(cp->name, "PART") == 0)
434 LIST_FOREACH(gp, &cp->geom, geom) {
435 LIST_FOREACH(pp, &gp->provider, provider) {
436 if (linux_driver_get_major_minor(
437 pp->name, &major, &minor) != 0) {
441 sbuf_printf(sb, "%d %d %lld %s "
443 "%d %d %d %d %d %d\n",
445 (long long)pp->mediasize, pp->name,
460 * Filler function for proc/stat
463 linprocfs_dostat(PFS_FILL_ARGS)
466 long cp_time[CPUSTATES];
470 read_cpu_time(cp_time);
471 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
472 T2J(cp_time[CP_USER]),
473 T2J(cp_time[CP_NICE]),
474 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
475 T2J(cp_time[CP_IDLE]));
476 for (i = 0; i <= mp_maxid; ++i) {
480 cp = pcpu->pc_cp_time;
481 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
484 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
500 (long long)boottime.tv_sec);
505 * Filler function for proc/uptime
508 linprocfs_douptime(PFS_FILL_ARGS)
510 long cp_time[CPUSTATES];
514 read_cpu_time(cp_time);
515 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
516 (long long)tv.tv_sec, tv.tv_usec / 10000,
517 T2S(cp_time[CP_IDLE] / mp_ncpus),
518 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
526 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
532 strncpy(osbuild, version, 256);
534 cp1 = strstr(osbuild, "\n");
535 cp2 = strstr(osbuild, ":");
538 cp1 = strstr(osbuild, "#");
542 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
545 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
552 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
558 cp = strstr(version, "\n ");
560 strncpy(builder, cp + 5, 256);
562 cp = strstr(builder, ":");
567 sbuf_cat(sb, builder);
570 sbuf_cat(sb, "des@freebsd.org");
574 * Filler function for proc/version
577 linprocfs_doversion(PFS_FILL_ARGS)
579 char osname[LINUX_MAX_UTSNAME];
580 char osrelease[LINUX_MAX_UTSNAME];
582 linux_get_osname(td, osname);
583 linux_get_osrelease(td, osrelease);
584 sbuf_printf(sb, "%s version %s (", osname, osrelease);
585 linprocfs_osbuilder(td, sb);
586 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
587 linprocfs_osbuild(td, sb);
594 * Filler function for proc/loadavg
597 linprocfs_doloadavg(PFS_FILL_ARGS)
601 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
602 (int)(averunnable.ldavg[0] / averunnable.fscale),
603 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
604 (int)(averunnable.ldavg[1] / averunnable.fscale),
605 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
606 (int)(averunnable.ldavg[2] / averunnable.fscale),
607 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
608 1, /* number of running tasks */
609 nprocs, /* number of tasks */
610 lastpid /* the last pid */
616 * Filler function for proc/pid/stat
619 linprocfs_doprocstat(PFS_FILL_ARGS)
621 struct kinfo_proc kp;
623 static int ratelimit = 0;
624 vm_offset_t startcode, startdata;
627 fill_kinfo_proc(p, &kp);
629 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
630 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
635 sbuf_printf(sb, "%d", p->p_pid);
636 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
637 PS_ADD("comm", "(%s)", p->p_comm);
638 if (kp.ki_stat > sizeof(linux_state)) {
641 if (ratelimit == 0) {
642 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
643 kp.ki_stat, sizeof(linux_state));
647 state = linux_state[kp.ki_stat - 1];
648 PS_ADD("state", "%c", state);
649 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
650 PS_ADD("pgrp", "%d", p->p_pgid);
651 PS_ADD("session", "%d", p->p_session->s_sid);
653 PS_ADD("tty", "%d", kp.ki_tdev);
654 PS_ADD("tpgid", "%d", kp.ki_tpgid);
655 PS_ADD("flags", "%u", 0); /* XXX */
656 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
657 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
658 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
659 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
660 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
661 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
662 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
663 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
664 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
665 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
666 PS_ADD("0", "%d", 0); /* removed field */
667 PS_ADD("itrealvalue", "%d", 0); /* XXX */
668 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
669 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
670 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
671 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
672 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
673 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
674 PS_ADD("startstack", "%u", 0); /* XXX */
675 PS_ADD("kstkesp", "%u", 0); /* XXX */
676 PS_ADD("kstkeip", "%u", 0); /* XXX */
677 PS_ADD("signal", "%u", 0); /* XXX */
678 PS_ADD("blocked", "%u", 0); /* XXX */
679 PS_ADD("sigignore", "%u", 0); /* XXX */
680 PS_ADD("sigcatch", "%u", 0); /* XXX */
681 PS_ADD("wchan", "%u", 0); /* XXX */
682 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
683 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
684 PS_ADD("exitsignal", "%d", 0); /* XXX */
685 PS_ADD("processor", "%u", kp.ki_lastcpu);
686 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
687 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
695 * Filler function for proc/pid/statm
698 linprocfs_doprocstatm(PFS_FILL_ARGS)
700 struct kinfo_proc kp;
704 fill_kinfo_proc(p, &kp);
708 * See comments in linprocfs_doprocstatus() regarding the
709 * computation of lsize.
711 /* size resident share trs drs lrs dt */
712 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
713 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
714 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
715 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
716 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
717 lsize = B2P(kp.ki_size) - kp.ki_dsize -
718 kp.ki_ssize - kp.ki_tsize - 1;
719 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
720 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
726 * Filler function for proc/pid/status
729 linprocfs_doprocstatus(PFS_FILL_ARGS)
731 struct kinfo_proc kp;
739 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
741 if (P_SHOULDSTOP(p)) {
742 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)";
777 fill_kinfo_proc(p, &kp);
778 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
779 sbuf_printf(sb, "State:\t%s\n", state);
784 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
785 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
786 p->p_pptr->p_pid : 0);
787 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
789 p->p_ucred->cr_svuid,
790 /* FreeBSD doesn't have fsuid */
792 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
794 p->p_ucred->cr_svgid,
795 /* FreeBSD doesn't have fsgid */
797 sbuf_cat(sb, "Groups:\t");
798 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
799 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
806 * While our approximation of VmLib may not be accurate (I
807 * don't know of a simple way to verify it, and I'm not sure
808 * it has much meaning anyway), I believe it's good enough.
810 * The same code that could (I think) accurately compute VmLib
811 * could also compute VmLck, but I don't really care enough to
812 * implement it. Submissions are welcome.
814 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
815 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
816 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
817 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
818 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
819 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
820 lsize = B2P(kp.ki_size) - kp.ki_dsize -
821 kp.ki_ssize - kp.ki_tsize - 1;
822 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
827 * We support up to 128 signals, while Linux supports 32,
828 * but we only define 32 (the same 32 as Linux, to boot), so
829 * just show the lower 32 bits of each mask. XXX hack.
831 * NB: on certain platforms (Sparc at least) Linux actually
832 * supports 64 signals, but this code is a long way from
833 * running on anything but i386, so ignore that for now.
836 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
838 * I can't seem to find out where the signal mask is in
839 * relation to struct proc, so SigBlk is left unimplemented.
841 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
843 mtx_lock(&ps->ps_mtx);
844 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
845 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
846 mtx_unlock(&ps->ps_mtx);
850 * Linux also prints the capability masks, but we don't have
851 * capabilities yet, and when we do get them they're likely to
852 * be meaningless to Linux programs, so we lie. XXX
854 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
855 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
856 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
863 * Filler function for proc/pid/cwd
866 linprocfs_doproccwd(PFS_FILL_ARGS)
868 char *fullpath = "unknown";
869 char *freepath = NULL;
871 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
872 sbuf_printf(sb, "%s", fullpath);
874 free(freepath, M_TEMP);
879 * Filler function for proc/pid/root
882 linprocfs_doprocroot(PFS_FILL_ARGS)
885 char *fullpath = "unknown";
886 char *freepath = NULL;
888 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
889 vn_fullpath(td, rvp, &fullpath, &freepath);
890 sbuf_printf(sb, "%s", fullpath);
892 free(freepath, M_TEMP);
896 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */
897 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */
900 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
901 void (*resolver)(const struct ps_strings, u_long *, int *))
905 struct ps_strings pss;
906 int ret, i, n_elements, elm_len;
908 char **env_vector, *envp;
909 char env_string[UIO_CHUNK_SZ];
910 #ifdef COMPAT_FREEBSD32
911 struct freebsd32_ps_strings pss32;
912 uint32_t *env_vector32;
915 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \
917 iov.iov_base = (caddr_t)(base); \
918 iov.iov_len = (len); \
919 uio.uio_iov = &(iov); \
920 uio.uio_iovcnt = (cnt); \
921 uio.uio_offset = (off_t)(offset); \
922 uio.uio_resid = (sz); \
923 uio.uio_segflg = (flg); \
928 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
930 #ifdef COMPAT_FREEBSD32
932 if ((p->p_sysent->sv_flags & SV_ILP32) != 0) {
933 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
935 elm_len = sizeof(int32_t);
936 envp = (char *)env_vector32;
938 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
939 (off_t)(p->p_sysent->sv_psstrings),
940 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
941 ret = proc_rwmem(p, &tmp_uio);
944 pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
945 pss.ps_nargvstr = pss32.ps_nargvstr;
946 pss.ps_envstr = PTRIN(pss32.ps_envstr);
947 pss.ps_nenvstr = pss32.ps_nenvstr;
950 elm_len = sizeof(char *);
951 envp = (char *)env_vector;
953 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
954 (off_t)(p->p_sysent->sv_psstrings),
955 sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
956 ret = proc_rwmem(p, &tmp_uio);
959 #ifdef COMPAT_FREEBSD32
963 /* Get the array address and the number of elements */
964 resolver(pss, &addr, &n_elements);
966 /* Consistent with lib/libkvm/kvm_proc.c */
967 if (n_elements > MAX_ARGV_STR) {
972 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
973 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
974 ret = proc_rwmem(p, &tmp_uio);
977 #ifdef COMPAT_FREEBSD32
978 if (env_vector32 != NULL) {
979 for (i = 0; i < n_elements; i++)
980 env_vector[i] = PTRIN(env_vector32[i]);
984 /* Now we can iterate through the list of strings */
985 for (i = 0; i < n_elements; i++) {
986 pbegin = (vm_offset_t)env_vector[i];
988 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
989 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
990 ret = proc_rwmem(p, &tmp_uio);
994 if (!strvalid(env_string, UIO_CHUNK_SZ)) {
996 * We didn't find the end of the string.
997 * Add the string to the buffer and move
998 * the pointer. But do not allow strings
999 * of unlimited length.
1001 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1002 if (sbuf_len(sb) >= ARG_MAX) {
1006 pbegin += UIO_CHUNK_SZ;
1008 sbuf_cat(sb, env_string);
1012 sbuf_bcat(sb, "", 1);
1017 free(env_vector, M_TEMP);
1018 #ifdef COMPAT_FREEBSD32
1019 free(env_vector32, M_TEMP);
1025 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1028 *addr = (u_long) ps.ps_argvstr;
1029 *n = ps.ps_nargvstr;
1033 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1036 *addr = (u_long) ps.ps_envstr;
1041 * Filler function for proc/pid/cmdline
1044 linprocfs_doproccmdline(PFS_FILL_ARGS)
1049 if ((ret = p_cansee(td, p)) != 0) {
1053 if (p->p_args != NULL) {
1054 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1060 ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1065 * Filler function for proc/pid/environ
1068 linprocfs_doprocenviron(PFS_FILL_ARGS)
1073 if ((ret = p_cansee(td, p)) != 0) {
1079 ret = linprocfs_doargv(td, p, sb, ps_string_env);
1084 * Filler function for proc/pid/maps
1087 linprocfs_doprocmaps(PFS_FILL_ARGS)
1091 vm_map_entry_t entry, tmp_entry;
1092 vm_object_t obj, tobj, lobj;
1093 vm_offset_t e_start, e_end;
1094 vm_ooffset_t off = 0;
1096 unsigned int last_timestamp;
1097 char *name = "", *freename = NULL;
1099 int ref_count, shadow_count, flags;
1106 error = p_candebug(td, p);
1111 if (uio->uio_rw != UIO_READ)
1112 return (EOPNOTSUPP);
1115 vm = vmspace_acquire_ref(p);
1119 vm_map_lock_read(map);
1120 for (entry = map->header.next; entry != &map->header;
1121 entry = entry->next) {
1124 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1126 e_prot = entry->protection;
1127 e_start = entry->start;
1129 obj = entry->object.vm_object;
1130 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1131 VM_OBJECT_LOCK(tobj);
1133 VM_OBJECT_UNLOCK(lobj);
1136 last_timestamp = map->timestamp;
1137 vm_map_unlock_read(map);
1140 off = IDX_TO_OFF(lobj->size);
1141 if (lobj->type == OBJT_VNODE) {
1149 VM_OBJECT_UNLOCK(lobj);
1151 ref_count = obj->ref_count;
1152 shadow_count = obj->shadow_count;
1153 VM_OBJECT_UNLOCK(obj);
1155 vn_fullpath(td, vp, &name, &freename);
1156 locked = VFS_LOCK_GIANT(vp->v_mount);
1157 vn_lock(vp, LK_SHARED | LK_RETRY);
1158 VOP_GETATTR(vp, &vat, td->td_ucred);
1159 ino = vat.va_fileid;
1161 VFS_UNLOCK_GIANT(locked);
1171 * start, end, access, offset, major, minor, inode, name.
1173 error = sbuf_printf(sb,
1174 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1175 (u_long)e_start, (u_long)e_end,
1176 (e_prot & VM_PROT_READ)?"r":"-",
1177 (e_prot & VM_PROT_WRITE)?"w":"-",
1178 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1188 free(freename, M_TEMP);
1189 vm_map_lock_read(map);
1194 if (last_timestamp != map->timestamp) {
1196 * Look again for the entry because the map was
1197 * modified while it was unlocked. Specifically,
1198 * the entry may have been clipped, merged, or deleted.
1200 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1204 vm_map_unlock_read(map);
1211 * Filler function for proc/net/dev
1214 linprocfs_donetdev(PFS_FILL_ARGS)
1216 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1219 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1220 "Inter-", " Receive", " Transmit", " face",
1221 "bytes packets errs drop fifo frame compressed",
1222 "bytes packets errs drop fifo frame compressed");
1224 CURVNET_SET(TD_TO_VNET(curthread));
1226 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1227 linux_ifname(ifp, ifname, sizeof ifname);
1228 sbuf_printf(sb, "%6.6s:", ifname);
1229 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1230 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1231 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1232 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1241 * Filler function for proc/sys/kernel/osrelease
1244 linprocfs_doosrelease(PFS_FILL_ARGS)
1246 char osrelease[LINUX_MAX_UTSNAME];
1248 linux_get_osrelease(td, osrelease);
1249 sbuf_printf(sb, "%s\n", osrelease);
1255 * Filler function for proc/sys/kernel/ostype
1258 linprocfs_doostype(PFS_FILL_ARGS)
1260 char osname[LINUX_MAX_UTSNAME];
1262 linux_get_osname(td, osname);
1263 sbuf_printf(sb, "%s\n", osname);
1269 * Filler function for proc/sys/kernel/version
1272 linprocfs_doosbuild(PFS_FILL_ARGS)
1275 linprocfs_osbuild(td, sb);
1281 * Filler function for proc/sys/kernel/msgmni
1284 linprocfs_domsgmni(PFS_FILL_ARGS)
1287 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1292 * Filler function for proc/sys/kernel/pid_max
1295 linprocfs_dopid_max(PFS_FILL_ARGS)
1298 sbuf_printf(sb, "%i\n", PID_MAX);
1303 * Filler function for proc/sys/kernel/sem
1306 linprocfs_dosem(PFS_FILL_ARGS)
1309 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1310 seminfo.semopm, seminfo.semmni);
1315 * Filler function for proc/scsi/device_info
1318 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1325 * Filler function for proc/scsi/scsi
1328 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1334 extern struct cdevsw *cdevsw[];
1337 * Filler function for proc/devices
1340 linprocfs_dodevices(PFS_FILL_ARGS)
1343 sbuf_printf(sb, "Character devices:\n");
1345 char_devices = linux_get_char_devices();
1346 sbuf_printf(sb, "%s", char_devices);
1347 linux_free_get_char_devices(char_devices);
1349 sbuf_printf(sb, "\nBlock devices:\n");
1355 * Filler function for proc/cmdline
1358 linprocfs_docmdline(PFS_FILL_ARGS)
1361 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1362 sbuf_printf(sb, " ro root=302\n");
1368 * Filler function for proc/modules
1371 linprocfs_domodules(PFS_FILL_ARGS)
1373 struct linker_file *lf;
1375 TAILQ_FOREACH(lf, &linker_files, link) {
1376 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1377 (unsigned long)lf->size, lf->refs);
1387 linprocfs_init(PFS_INIT_ARGS)
1389 struct pfs_node *root;
1390 struct pfs_node *dir;
1395 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1396 NULL, NULL, NULL, PFS_RD);
1397 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1398 NULL, NULL, NULL, PFS_RD);
1399 pfs_create_file(root, "devices", &linprocfs_dodevices,
1400 NULL, NULL, NULL, PFS_RD);
1401 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1402 NULL, NULL, NULL, PFS_RD);
1403 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1404 NULL, NULL, NULL, PFS_RD);
1406 pfs_create_file(root, "modules", &linprocfs_domodules,
1407 NULL, NULL, NULL, PFS_RD);
1409 pfs_create_file(root, "mounts", &linprocfs_domtab,
1410 NULL, NULL, NULL, PFS_RD);
1411 pfs_create_file(root, "mtab", &linprocfs_domtab,
1412 NULL, NULL, NULL, PFS_RD);
1413 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1414 NULL, NULL, NULL, PFS_RD);
1415 pfs_create_link(root, "self", &procfs_docurproc,
1416 NULL, NULL, NULL, 0);
1417 pfs_create_file(root, "stat", &linprocfs_dostat,
1418 NULL, NULL, NULL, PFS_RD);
1419 pfs_create_file(root, "uptime", &linprocfs_douptime,
1420 NULL, NULL, NULL, PFS_RD);
1421 pfs_create_file(root, "version", &linprocfs_doversion,
1422 NULL, NULL, NULL, PFS_RD);
1425 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1426 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1427 NULL, NULL, NULL, PFS_RD);
1429 /* /proc/<pid>/... */
1430 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1431 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1432 NULL, NULL, NULL, PFS_RD);
1433 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1434 NULL, NULL, NULL, 0);
1435 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1436 NULL, NULL, NULL, PFS_RD);
1437 pfs_create_link(dir, "exe", &procfs_doprocfile,
1438 NULL, &procfs_notsystem, NULL, 0);
1439 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1440 NULL, NULL, NULL, PFS_RD);
1441 pfs_create_file(dir, "mem", &procfs_doprocmem,
1442 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1443 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1444 NULL, NULL, NULL, 0);
1445 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1446 NULL, NULL, NULL, PFS_RD);
1447 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1448 NULL, NULL, NULL, PFS_RD);
1449 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1450 NULL, NULL, NULL, PFS_RD);
1452 /* /proc/scsi/... */
1453 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1454 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1455 NULL, NULL, NULL, PFS_RD);
1456 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1457 NULL, NULL, NULL, PFS_RD);
1460 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1461 /* /proc/sys/kernel/... */
1462 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1463 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1464 NULL, NULL, NULL, PFS_RD);
1465 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1466 NULL, NULL, NULL, PFS_RD);
1467 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1468 NULL, NULL, NULL, PFS_RD);
1469 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1470 NULL, NULL, NULL, PFS_RD);
1471 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1472 NULL, NULL, NULL, PFS_RD);
1473 pfs_create_file(dir, "sem", &linprocfs_dosem,
1474 NULL, NULL, NULL, PFS_RD);
1483 linprocfs_uninit(PFS_INIT_ARGS)
1486 /* nothing to do, pseudofs will GC */
1490 PSEUDOFS(linprocfs, 1);
1491 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);