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]));
478 cp = pcpu->pc_cp_time;
479 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
482 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
498 (long long)boottime.tv_sec);
503 linprocfs_doswaps(PFS_FILL_ARGS)
506 uintmax_t total, used;
508 char devname[SPECNAMELEN + 1];
510 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
513 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
515 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
516 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
519 * The space and not tab after the device name is on
520 * purpose. Linux does so.
522 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
523 devname, total, used);
530 * Filler function for proc/uptime
533 linprocfs_douptime(PFS_FILL_ARGS)
535 long cp_time[CPUSTATES];
539 read_cpu_time(cp_time);
540 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
541 (long long)tv.tv_sec, tv.tv_usec / 10000,
542 T2S(cp_time[CP_IDLE] / mp_ncpus),
543 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
551 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
557 strncpy(osbuild, version, 256);
559 cp1 = strstr(osbuild, "\n");
560 cp2 = strstr(osbuild, ":");
563 cp1 = strstr(osbuild, "#");
567 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
570 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
577 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
583 cp = strstr(version, "\n ");
585 strncpy(builder, cp + 5, 256);
587 cp = strstr(builder, ":");
592 sbuf_cat(sb, builder);
595 sbuf_cat(sb, "des@freebsd.org");
599 * Filler function for proc/version
602 linprocfs_doversion(PFS_FILL_ARGS)
604 char osname[LINUX_MAX_UTSNAME];
605 char osrelease[LINUX_MAX_UTSNAME];
607 linux_get_osname(td, osname);
608 linux_get_osrelease(td, osrelease);
609 sbuf_printf(sb, "%s version %s (", osname, osrelease);
610 linprocfs_osbuilder(td, sb);
611 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
612 linprocfs_osbuild(td, sb);
619 * Filler function for proc/loadavg
622 linprocfs_doloadavg(PFS_FILL_ARGS)
626 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
627 (int)(averunnable.ldavg[0] / averunnable.fscale),
628 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
629 (int)(averunnable.ldavg[1] / averunnable.fscale),
630 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
631 (int)(averunnable.ldavg[2] / averunnable.fscale),
632 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
633 1, /* number of running tasks */
634 nprocs, /* number of tasks */
635 lastpid /* the last pid */
641 * Filler function for proc/pid/stat
644 linprocfs_doprocstat(PFS_FILL_ARGS)
646 struct kinfo_proc kp;
648 static int ratelimit = 0;
649 vm_offset_t startcode, startdata;
652 fill_kinfo_proc(p, &kp);
654 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
655 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
660 sbuf_printf(sb, "%d", p->p_pid);
661 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
662 PS_ADD("comm", "(%s)", p->p_comm);
663 if (kp.ki_stat > sizeof(linux_state)) {
666 if (ratelimit == 0) {
667 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
668 kp.ki_stat, sizeof(linux_state));
672 state = linux_state[kp.ki_stat - 1];
673 PS_ADD("state", "%c", state);
674 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
675 PS_ADD("pgrp", "%d", p->p_pgid);
676 PS_ADD("session", "%d", p->p_session->s_sid);
678 PS_ADD("tty", "%d", kp.ki_tdev);
679 PS_ADD("tpgid", "%d", kp.ki_tpgid);
680 PS_ADD("flags", "%u", 0); /* XXX */
681 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
682 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
683 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
684 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
685 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
686 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
687 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
688 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
689 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
690 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
691 PS_ADD("0", "%d", 0); /* removed field */
692 PS_ADD("itrealvalue", "%d", 0); /* XXX */
693 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
694 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
695 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
696 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
697 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
698 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
699 PS_ADD("startstack", "%u", 0); /* XXX */
700 PS_ADD("kstkesp", "%u", 0); /* XXX */
701 PS_ADD("kstkeip", "%u", 0); /* XXX */
702 PS_ADD("signal", "%u", 0); /* XXX */
703 PS_ADD("blocked", "%u", 0); /* XXX */
704 PS_ADD("sigignore", "%u", 0); /* XXX */
705 PS_ADD("sigcatch", "%u", 0); /* XXX */
706 PS_ADD("wchan", "%u", 0); /* XXX */
707 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
708 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
709 PS_ADD("exitsignal", "%d", 0); /* XXX */
710 PS_ADD("processor", "%u", kp.ki_lastcpu);
711 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
712 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
720 * Filler function for proc/pid/statm
723 linprocfs_doprocstatm(PFS_FILL_ARGS)
725 struct kinfo_proc kp;
729 fill_kinfo_proc(p, &kp);
733 * See comments in linprocfs_doprocstatus() regarding the
734 * computation of lsize.
736 /* size resident share trs drs lrs dt */
737 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
738 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
739 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
740 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
741 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
742 lsize = B2P(kp.ki_size) - kp.ki_dsize -
743 kp.ki_ssize - kp.ki_tsize - 1;
744 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
745 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
751 * Filler function for proc/pid/status
754 linprocfs_doprocstatus(PFS_FILL_ARGS)
756 struct kinfo_proc kp;
764 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
766 if (P_SHOULDSTOP(p)) {
767 state = "T (stopped)";
774 if (p->p_flag & P_WEXIT) {
775 state = "X (exiting)";
778 switch(td2->td_state) {
780 state = "S (sleeping)";
784 state = "R (running)";
787 state = "? (unknown)";
792 state = "Z (zombie)";
795 state = "? (unknown)";
800 fill_kinfo_proc(p, &kp);
801 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
802 sbuf_printf(sb, "State:\t%s\n", state);
807 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
808 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
809 p->p_pptr->p_pid : 0);
810 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
812 p->p_ucred->cr_svuid,
813 /* FreeBSD doesn't have fsuid */
815 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
817 p->p_ucred->cr_svgid,
818 /* FreeBSD doesn't have fsgid */
820 sbuf_cat(sb, "Groups:\t");
821 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
822 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
829 * While our approximation of VmLib may not be accurate (I
830 * don't know of a simple way to verify it, and I'm not sure
831 * it has much meaning anyway), I believe it's good enough.
833 * The same code that could (I think) accurately compute VmLib
834 * could also compute VmLck, but I don't really care enough to
835 * implement it. Submissions are welcome.
837 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
838 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
839 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
840 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
841 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
842 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
843 lsize = B2P(kp.ki_size) - kp.ki_dsize -
844 kp.ki_ssize - kp.ki_tsize - 1;
845 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
850 * We support up to 128 signals, while Linux supports 32,
851 * but we only define 32 (the same 32 as Linux, to boot), so
852 * just show the lower 32 bits of each mask. XXX hack.
854 * NB: on certain platforms (Sparc at least) Linux actually
855 * supports 64 signals, but this code is a long way from
856 * running on anything but i386, so ignore that for now.
859 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
861 * I can't seem to find out where the signal mask is in
862 * relation to struct proc, so SigBlk is left unimplemented.
864 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
866 mtx_lock(&ps->ps_mtx);
867 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
868 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
869 mtx_unlock(&ps->ps_mtx);
873 * Linux also prints the capability masks, but we don't have
874 * capabilities yet, and when we do get them they're likely to
875 * be meaningless to Linux programs, so we lie. XXX
877 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
878 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
879 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
886 * Filler function for proc/pid/cwd
889 linprocfs_doproccwd(PFS_FILL_ARGS)
891 char *fullpath = "unknown";
892 char *freepath = NULL;
894 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
895 sbuf_printf(sb, "%s", fullpath);
897 free(freepath, M_TEMP);
902 * Filler function for proc/pid/root
905 linprocfs_doprocroot(PFS_FILL_ARGS)
908 char *fullpath = "unknown";
909 char *freepath = NULL;
911 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
912 vn_fullpath(td, rvp, &fullpath, &freepath);
913 sbuf_printf(sb, "%s", fullpath);
915 free(freepath, M_TEMP);
919 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */
920 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */
923 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
924 void (*resolver)(const struct ps_strings, u_long *, int *))
928 struct ps_strings pss;
929 int ret, i, n_elements, elm_len;
931 char **env_vector, *envp;
932 char env_string[UIO_CHUNK_SZ];
933 #ifdef COMPAT_FREEBSD32
934 struct freebsd32_ps_strings pss32;
935 uint32_t *env_vector32;
938 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \
940 iov.iov_base = (caddr_t)(base); \
941 iov.iov_len = (len); \
942 uio.uio_iov = &(iov); \
943 uio.uio_iovcnt = (cnt); \
944 uio.uio_offset = (off_t)(offset); \
945 uio.uio_resid = (sz); \
946 uio.uio_segflg = (flg); \
951 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
953 #ifdef COMPAT_FREEBSD32
955 if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
956 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
958 elm_len = sizeof(int32_t);
959 envp = (char *)env_vector32;
961 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
962 (off_t)(p->p_sysent->sv_psstrings),
963 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
964 ret = proc_rwmem(p, &tmp_uio);
967 pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
968 pss.ps_nargvstr = pss32.ps_nargvstr;
969 pss.ps_envstr = PTRIN(pss32.ps_envstr);
970 pss.ps_nenvstr = pss32.ps_nenvstr;
973 elm_len = sizeof(char *);
974 envp = (char *)env_vector;
976 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
977 (off_t)(p->p_sysent->sv_psstrings),
978 sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
979 ret = proc_rwmem(p, &tmp_uio);
982 #ifdef COMPAT_FREEBSD32
986 /* Get the array address and the number of elements */
987 resolver(pss, &addr, &n_elements);
989 /* Consistent with lib/libkvm/kvm_proc.c */
990 if (n_elements > MAX_ARGV_STR) {
995 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
996 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
997 ret = proc_rwmem(p, &tmp_uio);
1000 #ifdef COMPAT_FREEBSD32
1001 if (env_vector32 != NULL) {
1002 for (i = 0; i < n_elements; i++)
1003 env_vector[i] = PTRIN(env_vector32[i]);
1007 /* Now we can iterate through the list of strings */
1008 for (i = 0; i < n_elements; i++) {
1009 pbegin = (vm_offset_t)env_vector[i];
1011 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
1012 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
1013 ret = proc_rwmem(p, &tmp_uio);
1017 if (!strvalid(env_string, UIO_CHUNK_SZ)) {
1019 * We didn't find the end of the string.
1020 * Add the string to the buffer and move
1021 * the pointer. But do not allow strings
1022 * of unlimited length.
1024 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1025 if (sbuf_len(sb) >= ARG_MAX) {
1029 pbegin += UIO_CHUNK_SZ;
1031 sbuf_cat(sb, env_string);
1035 sbuf_bcat(sb, "", 1);
1040 free(env_vector, M_TEMP);
1041 #ifdef COMPAT_FREEBSD32
1042 free(env_vector32, M_TEMP);
1048 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1051 *addr = (u_long) ps.ps_argvstr;
1052 *n = ps.ps_nargvstr;
1056 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1059 *addr = (u_long) ps.ps_envstr;
1064 * Filler function for proc/pid/cmdline
1067 linprocfs_doproccmdline(PFS_FILL_ARGS)
1072 if ((ret = p_cansee(td, p)) != 0) {
1078 * Mimic linux behavior and pass only processes with usermode
1079 * address space as valid. Return zero silently otherwize.
1081 if (p->p_vmspace == &vmspace0) {
1085 if (p->p_args != NULL) {
1086 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1092 ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1097 * Filler function for proc/pid/environ
1100 linprocfs_doprocenviron(PFS_FILL_ARGS)
1105 if ((ret = p_candebug(td, p)) != 0) {
1111 * Mimic linux behavior and pass only processes with usermode
1112 * address space as valid. Return zero silently otherwize.
1114 if (p->p_vmspace == &vmspace0) {
1120 ret = linprocfs_doargv(td, p, sb, ps_string_env);
1125 * Filler function for proc/pid/maps
1128 linprocfs_doprocmaps(PFS_FILL_ARGS)
1132 vm_map_entry_t entry, tmp_entry;
1133 vm_object_t obj, tobj, lobj;
1134 vm_offset_t e_start, e_end;
1135 vm_ooffset_t off = 0;
1137 unsigned int last_timestamp;
1138 char *name = "", *freename = NULL;
1140 int ref_count, shadow_count, flags;
1147 error = p_candebug(td, p);
1152 if (uio->uio_rw != UIO_READ)
1153 return (EOPNOTSUPP);
1156 vm = vmspace_acquire_ref(p);
1160 vm_map_lock_read(map);
1161 for (entry = map->header.next; entry != &map->header;
1162 entry = entry->next) {
1165 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1167 e_prot = entry->protection;
1168 e_start = entry->start;
1170 obj = entry->object.vm_object;
1171 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1172 VM_OBJECT_LOCK(tobj);
1174 VM_OBJECT_UNLOCK(lobj);
1177 last_timestamp = map->timestamp;
1178 vm_map_unlock_read(map);
1181 off = IDX_TO_OFF(lobj->size);
1182 if (lobj->type == OBJT_VNODE) {
1190 VM_OBJECT_UNLOCK(lobj);
1192 ref_count = obj->ref_count;
1193 shadow_count = obj->shadow_count;
1194 VM_OBJECT_UNLOCK(obj);
1196 vn_fullpath(td, vp, &name, &freename);
1197 locked = VFS_LOCK_GIANT(vp->v_mount);
1198 vn_lock(vp, LK_SHARED | LK_RETRY);
1199 VOP_GETATTR(vp, &vat, td->td_ucred);
1200 ino = vat.va_fileid;
1202 VFS_UNLOCK_GIANT(locked);
1212 * start, end, access, offset, major, minor, inode, name.
1214 error = sbuf_printf(sb,
1215 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1216 (u_long)e_start, (u_long)e_end,
1217 (e_prot & VM_PROT_READ)?"r":"-",
1218 (e_prot & VM_PROT_WRITE)?"w":"-",
1219 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1229 free(freename, M_TEMP);
1230 vm_map_lock_read(map);
1235 if (last_timestamp != map->timestamp) {
1237 * Look again for the entry because the map was
1238 * modified while it was unlocked. Specifically,
1239 * the entry may have been clipped, merged, or deleted.
1241 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1245 vm_map_unlock_read(map);
1252 * Filler function for proc/net/dev
1255 linprocfs_donetdev(PFS_FILL_ARGS)
1257 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1260 sbuf_printf(sb, "%6s|%58s|%s\n"
1262 "Inter-", " Receive", " Transmit",
1264 "bytes packets errs drop fifo frame compressed multicast",
1265 "bytes packets errs drop fifo colls carrier compressed");
1267 CURVNET_SET(TD_TO_VNET(curthread));
1269 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1270 linux_ifname(ifp, ifname, sizeof ifname);
1271 sbuf_printf(sb, "%6.6s: ", ifname);
1272 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1273 ifp->if_ibytes, /* rx_bytes */
1274 ifp->if_ipackets, /* rx_packets */
1275 ifp->if_ierrors, /* rx_errors */
1276 ifp->if_iqdrops, /* rx_dropped +
1277 * rx_missed_errors */
1278 0UL, /* rx_fifo_errors */
1279 0UL, /* rx_length_errors +
1282 * rx_frame_errors */
1283 0UL, /* rx_compressed */
1284 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1285 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1286 ifp->if_obytes, /* tx_bytes */
1287 ifp->if_opackets, /* tx_packets */
1288 ifp->if_oerrors, /* tx_errors */
1289 0UL, /* tx_dropped */
1290 0UL, /* tx_fifo_errors */
1291 ifp->if_collisions, /* collisions */
1292 0UL, /* tx_carrier_errors +
1293 * tx_aborted_errors +
1294 * tx_window_errors +
1295 * tx_heartbeat_errors */
1296 0UL); /* tx_compressed */
1305 * Filler function for proc/sys/kernel/osrelease
1308 linprocfs_doosrelease(PFS_FILL_ARGS)
1310 char osrelease[LINUX_MAX_UTSNAME];
1312 linux_get_osrelease(td, osrelease);
1313 sbuf_printf(sb, "%s\n", osrelease);
1319 * Filler function for proc/sys/kernel/ostype
1322 linprocfs_doostype(PFS_FILL_ARGS)
1324 char osname[LINUX_MAX_UTSNAME];
1326 linux_get_osname(td, osname);
1327 sbuf_printf(sb, "%s\n", osname);
1333 * Filler function for proc/sys/kernel/version
1336 linprocfs_doosbuild(PFS_FILL_ARGS)
1339 linprocfs_osbuild(td, sb);
1345 * Filler function for proc/sys/kernel/msgmni
1348 linprocfs_domsgmni(PFS_FILL_ARGS)
1351 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1356 * Filler function for proc/sys/kernel/pid_max
1359 linprocfs_dopid_max(PFS_FILL_ARGS)
1362 sbuf_printf(sb, "%i\n", PID_MAX);
1367 * Filler function for proc/sys/kernel/sem
1370 linprocfs_dosem(PFS_FILL_ARGS)
1373 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1374 seminfo.semopm, seminfo.semmni);
1379 * Filler function for proc/scsi/device_info
1382 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1389 * Filler function for proc/scsi/scsi
1392 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1398 extern struct cdevsw *cdevsw[];
1401 * Filler function for proc/devices
1404 linprocfs_dodevices(PFS_FILL_ARGS)
1407 sbuf_printf(sb, "Character devices:\n");
1409 char_devices = linux_get_char_devices();
1410 sbuf_printf(sb, "%s", char_devices);
1411 linux_free_get_char_devices(char_devices);
1413 sbuf_printf(sb, "\nBlock devices:\n");
1419 * Filler function for proc/cmdline
1422 linprocfs_docmdline(PFS_FILL_ARGS)
1425 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1426 sbuf_printf(sb, " ro root=302\n");
1432 * Filler function for proc/modules
1435 linprocfs_domodules(PFS_FILL_ARGS)
1437 struct linker_file *lf;
1439 TAILQ_FOREACH(lf, &linker_files, link) {
1440 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1441 (unsigned long)lf->size, lf->refs);
1451 linprocfs_init(PFS_INIT_ARGS)
1453 struct pfs_node *root;
1454 struct pfs_node *dir;
1459 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1460 NULL, NULL, NULL, PFS_RD);
1461 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1462 NULL, NULL, NULL, PFS_RD);
1463 pfs_create_file(root, "devices", &linprocfs_dodevices,
1464 NULL, NULL, NULL, PFS_RD);
1465 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1466 NULL, NULL, NULL, PFS_RD);
1467 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1468 NULL, NULL, NULL, PFS_RD);
1470 pfs_create_file(root, "modules", &linprocfs_domodules,
1471 NULL, NULL, NULL, PFS_RD);
1473 pfs_create_file(root, "mounts", &linprocfs_domtab,
1474 NULL, NULL, NULL, PFS_RD);
1475 pfs_create_file(root, "mtab", &linprocfs_domtab,
1476 NULL, NULL, NULL, PFS_RD);
1477 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1478 NULL, NULL, NULL, PFS_RD);
1479 pfs_create_link(root, "self", &procfs_docurproc,
1480 NULL, NULL, NULL, 0);
1481 pfs_create_file(root, "stat", &linprocfs_dostat,
1482 NULL, NULL, NULL, PFS_RD);
1483 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1484 NULL, NULL, NULL, PFS_RD);
1485 pfs_create_file(root, "uptime", &linprocfs_douptime,
1486 NULL, NULL, NULL, PFS_RD);
1487 pfs_create_file(root, "version", &linprocfs_doversion,
1488 NULL, NULL, NULL, PFS_RD);
1491 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1492 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1493 NULL, NULL, NULL, PFS_RD);
1495 /* /proc/<pid>/... */
1496 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1497 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1498 NULL, NULL, NULL, PFS_RD);
1499 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1500 NULL, NULL, NULL, 0);
1501 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1502 NULL, NULL, NULL, PFS_RD);
1503 pfs_create_link(dir, "exe", &procfs_doprocfile,
1504 NULL, &procfs_notsystem, NULL, 0);
1505 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1506 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_file(dir, "mem", &procfs_doprocmem,
1508 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1509 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1510 NULL, NULL, NULL, 0);
1511 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1512 NULL, NULL, NULL, PFS_RD);
1513 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1514 NULL, NULL, NULL, PFS_RD);
1515 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1516 NULL, NULL, NULL, PFS_RD);
1518 /* /proc/scsi/... */
1519 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1520 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1521 NULL, NULL, NULL, PFS_RD);
1522 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1523 NULL, NULL, NULL, PFS_RD);
1526 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1527 /* /proc/sys/kernel/... */
1528 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1529 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1530 NULL, NULL, NULL, PFS_RD);
1531 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1532 NULL, NULL, NULL, PFS_RD);
1533 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1534 NULL, NULL, NULL, PFS_RD);
1535 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1536 NULL, NULL, NULL, PFS_RD);
1537 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1538 NULL, NULL, NULL, PFS_RD);
1539 pfs_create_file(dir, "sem", &linprocfs_dosem,
1540 NULL, NULL, NULL, PFS_RD);
1549 linprocfs_uninit(PFS_INIT_ARGS)
1552 /* nothing to do, pseudofs will GC */
1556 PSEUDOFS(linprocfs, 1);
1557 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1558 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1559 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1560 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);