2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/systm.h>
48 #include <sys/blist.h>
51 #include <sys/fcntl.h>
52 #include <sys/filedesc.h>
54 #include <sys/kernel.h>
55 #include <sys/limits.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/sysent.h>
72 #include <sys/systm.h>
77 #include <sys/vmmeter.h>
78 #include <sys/vnode.h>
82 #include <net/if_types.h>
85 #include <vm/vm_extern.h>
87 #include <vm/vm_map.h>
88 #include <vm/vm_param.h>
89 #include <vm/vm_object.h>
90 #include <vm/swap_pager.h>
92 #include <machine/clock.h>
94 #include <geom/geom.h>
95 #include <geom/geom_int.h>
97 #if defined(__i386__) || defined(__amd64__)
98 #include <machine/cputypes.h>
99 #include <machine/md_var.h>
100 #endif /* __i386__ || __amd64__ */
102 #include <compat/linux/linux_mib.h>
103 #include <compat/linux/linux_misc.h>
104 #include <compat/linux/linux_util.h>
105 #include <fs/pseudofs/pseudofs.h>
106 #include <fs/procfs/procfs.h>
109 * Various conversion macros
111 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
112 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
113 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
114 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
115 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
116 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
117 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
118 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
121 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
123 * The linux procfs state field displays one of the characters RSDZTW to
124 * denote running, sleeping in an interruptible wait, waiting in an
125 * uninterruptible disk sleep, a zombie process, process is being traced
126 * or stopped, or process is paging respectively.
128 * Our struct kinfo_proc contains the variable ki_stat which contains a
129 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
131 * This character array is used with ki_stati-1 as an index and tries to
132 * map our states to suitable linux states.
134 static char linux_state[] = "RRSTZDD";
137 * Filler function for proc/meminfo
140 linprocfs_domeminfo(PFS_FILL_ARGS)
142 unsigned long memtotal; /* total memory in bytes */
143 unsigned long memused; /* used memory in bytes */
144 unsigned long memfree; /* free memory in bytes */
145 unsigned long memshared; /* shared memory ??? */
146 unsigned long buffers, cached; /* buffer / cache memory ??? */
147 unsigned long long swaptotal; /* total swap space in bytes */
148 unsigned long long swapused; /* used swap space in bytes */
149 unsigned long long swapfree; /* free swap space in bytes */
153 memtotal = physmem * PAGE_SIZE;
155 * The correct thing here would be:
157 memfree = cnt.v_free_count * PAGE_SIZE;
158 memused = memtotal - memfree;
160 * but it might mislead linux binaries into thinking there
161 * is very little memory left, so we cheat and tell them that
162 * all memory that isn't wired down is free.
164 memused = cnt.v_wire_count * PAGE_SIZE;
165 memfree = memtotal - memused;
166 swap_pager_status(&i, &j);
167 swaptotal = (unsigned long long)i * PAGE_SIZE;
168 swapused = (unsigned long long)j * PAGE_SIZE;
169 swapfree = swaptotal - swapused;
171 mtx_lock(&vm_object_list_mtx);
172 TAILQ_FOREACH(object, &vm_object_list, object_list)
173 if (object->shadow_count > 1)
174 memshared += object->resident_page_count;
175 mtx_unlock(&vm_object_list_mtx);
176 memshared *= PAGE_SIZE;
178 * We'd love to be able to write:
182 * but bufspace is internal to vfs_bio.c and we don't feel
183 * like unstaticizing it just for linprocfs's sake.
186 cached = cnt.v_cache_count * PAGE_SIZE;
189 " total: used: free: shared: buffers: cached:\n"
190 "Mem: %lu %lu %lu %lu %lu %lu\n"
191 "Swap: %llu %llu %llu\n"
192 "MemTotal: %9lu kB\n"
194 "MemShared:%9lu kB\n"
197 "SwapTotal:%9llu kB\n"
198 "SwapFree: %9llu kB\n",
199 memtotal, memused, memfree, memshared, buffers, cached,
200 swaptotal, swapused, swapfree,
201 B2K(memtotal), B2K(memfree),
202 B2K(memshared), B2K(buffers), B2K(cached),
203 B2K(swaptotal), B2K(swapfree));
208 #if defined(__i386__) || defined(__amd64__)
210 * Filler function for proc/cpuinfo (i386 & amd64 version)
213 linprocfs_docpuinfo(PFS_FILL_ARGS)
219 int class, fqmhz, fqkhz;
223 * We default the flags to include all non-conflicting flags,
224 * and the Intel versions of conflicting flags.
226 static char *flags[] = {
227 "fpu", "vme", "de", "pse", "tsc",
228 "msr", "pae", "mce", "cx8", "apic",
229 "sep", "sep", "mtrr", "pge", "mca",
230 "cmov", "pat", "pse36", "pn", "b19",
231 "b20", "b21", "mmxext", "mmx", "fxsr",
232 "xmm", "sse2", "b27", "b28", "b29",
256 #else /* __amd64__ */
263 hw_model[0] = CTL_HW;
264 hw_model[1] = HW_MODEL;
266 size = sizeof(model);
267 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
268 strcpy(model, "unknown");
269 for (i = 0; i < mp_ncpus; ++i) {
272 "vendor_id\t: %.20s\n"
276 "stepping\t: %u\n\n",
277 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
278 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
279 /* XXX per-cpu vendor / class / model / id? */
282 sbuf_cat(sb, "flags\t\t:");
285 switch (cpu_vendor_id) {
290 case CPU_VENDOR_CYRIX:
296 for (i = 0; i < 32; i++)
297 if (cpu_feature & (1 << i))
298 sbuf_printf(sb, " %s", flags[i]);
300 freq = atomic_load_acq_64(&tsc_freq);
302 fqmhz = (freq + 4999) / 1000000;
303 fqkhz = ((freq + 4999) / 10000) % 100;
305 "cpu MHz\t\t: %d.%02d\n"
306 "bogomips\t: %d.%02d\n",
307 fqmhz, fqkhz, fqmhz, fqkhz);
312 #endif /* __i386__ || __amd64__ */
315 * Filler function for proc/mtab
317 * This file doesn't exist in Linux' procfs, but is included here so
318 * users can symlink /compat/linux/etc/mtab to /proc/mtab
321 linprocfs_domtab(PFS_FILL_ARGS)
326 char *dlep, *flep, *mntto, *mntfrom, *fstype;
330 /* resolve symlinks etc. in the emulation tree prefix */
331 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
334 lep = linux_emul_path;
336 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
340 lep_len = strlen(lep);
342 mtx_lock(&mountlist_mtx);
344 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
345 /* determine device name */
346 mntfrom = mp->mnt_stat.f_mntfromname;
348 /* determine mount point */
349 mntto = mp->mnt_stat.f_mntonname;
350 if (strncmp(mntto, lep, lep_len) == 0 &&
351 mntto[lep_len] == '/')
354 /* determine fs type */
355 fstype = mp->mnt_stat.f_fstypename;
356 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
357 mntfrom = fstype = "proc";
358 else if (strcmp(fstype, "procfs") == 0)
361 if (strcmp(fstype, "linsysfs") == 0) {
362 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
363 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
365 /* For Linux msdosfs is called vfat */
366 if (strcmp(fstype, "msdosfs") == 0)
368 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
369 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
371 #define ADD_OPTION(opt, name) \
372 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
373 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
374 ADD_OPTION(MNT_NOEXEC, "noexec");
375 ADD_OPTION(MNT_NOSUID, "nosuid");
376 ADD_OPTION(MNT_UNION, "union");
377 ADD_OPTION(MNT_ASYNC, "async");
378 ADD_OPTION(MNT_SUIDDIR, "suiddir");
379 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
380 ADD_OPTION(MNT_NOATIME, "noatime");
382 /* a real Linux mtab will also show NFS options */
383 sbuf_printf(sb, " 0 0\n");
385 mtx_unlock(&mountlist_mtx);
391 * Filler function for proc/partitions
394 linprocfs_dopartitions(PFS_FILL_ARGS)
398 struct g_provider *pp;
402 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
403 "ruse wio wmerge wsect wuse running use aveq\n");
405 LIST_FOREACH(cp, &g_classes, class) {
406 if (strcmp(cp->name, "DISK") == 0 ||
407 strcmp(cp->name, "PART") == 0)
408 LIST_FOREACH(gp, &cp->geom, geom) {
409 LIST_FOREACH(pp, &gp->provider, provider) {
410 if (linux_driver_get_major_minor(
411 pp->name, &major, &minor) != 0) {
415 sbuf_printf(sb, "%d %d %lld %s "
417 "%d %d %d %d %d %d\n",
419 (long long)pp->mediasize, pp->name,
432 * Filler function for proc/stat
435 linprocfs_dostat(PFS_FILL_ARGS)
438 long cp_time[CPUSTATES];
442 read_cpu_time(cp_time);
443 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
444 T2J(cp_time[CP_USER]),
445 T2J(cp_time[CP_NICE]),
446 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
447 T2J(cp_time[CP_IDLE]));
450 cp = pcpu->pc_cp_time;
451 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
454 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
470 (long long)boottime.tv_sec);
475 linprocfs_doswaps(PFS_FILL_ARGS)
478 uintmax_t total, used;
480 char devname[SPECNAMELEN + 1];
482 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
485 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
487 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
488 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
491 * The space and not tab after the device name is on
492 * purpose. Linux does so.
494 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
495 devname, total, used);
502 * Filler function for proc/uptime
505 linprocfs_douptime(PFS_FILL_ARGS)
507 long cp_time[CPUSTATES];
511 read_cpu_time(cp_time);
512 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
513 (long long)tv.tv_sec, tv.tv_usec / 10000,
514 T2S(cp_time[CP_IDLE] / mp_ncpus),
515 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
523 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
529 strncpy(osbuild, version, 256);
531 cp1 = strstr(osbuild, "\n");
532 cp2 = strstr(osbuild, ":");
535 cp1 = strstr(osbuild, "#");
539 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
542 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
549 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
555 cp = strstr(version, "\n ");
557 strncpy(builder, cp + 5, 256);
559 cp = strstr(builder, ":");
564 sbuf_cat(sb, builder);
567 sbuf_cat(sb, "des@freebsd.org");
571 * Filler function for proc/version
574 linprocfs_doversion(PFS_FILL_ARGS)
576 char osname[LINUX_MAX_UTSNAME];
577 char osrelease[LINUX_MAX_UTSNAME];
579 linux_get_osname(td, osname);
580 linux_get_osrelease(td, osrelease);
581 sbuf_printf(sb, "%s version %s (", osname, osrelease);
582 linprocfs_osbuilder(td, sb);
583 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
584 linprocfs_osbuild(td, sb);
591 * Filler function for proc/loadavg
594 linprocfs_doloadavg(PFS_FILL_ARGS)
598 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
599 (int)(averunnable.ldavg[0] / averunnable.fscale),
600 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
601 (int)(averunnable.ldavg[1] / averunnable.fscale),
602 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
603 (int)(averunnable.ldavg[2] / averunnable.fscale),
604 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
605 1, /* number of running tasks */
606 nprocs, /* number of tasks */
607 lastpid /* the last pid */
613 * Filler function for proc/pid/stat
616 linprocfs_doprocstat(PFS_FILL_ARGS)
618 struct kinfo_proc kp;
620 static int ratelimit = 0;
621 vm_offset_t startcode, startdata;
624 fill_kinfo_proc(p, &kp);
626 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
627 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
632 sbuf_printf(sb, "%d", p->p_pid);
633 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
634 PS_ADD("comm", "(%s)", p->p_comm);
635 if (kp.ki_stat > sizeof(linux_state)) {
638 if (ratelimit == 0) {
639 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
640 kp.ki_stat, sizeof(linux_state));
644 state = linux_state[kp.ki_stat - 1];
645 PS_ADD("state", "%c", state);
646 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
647 PS_ADD("pgrp", "%d", p->p_pgid);
648 PS_ADD("session", "%d", p->p_session->s_sid);
650 PS_ADD("tty", "%d", kp.ki_tdev);
651 PS_ADD("tpgid", "%d", kp.ki_tpgid);
652 PS_ADD("flags", "%u", 0); /* XXX */
653 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
654 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
655 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
656 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
657 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
658 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
659 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
660 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
661 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
662 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
663 PS_ADD("0", "%d", 0); /* removed field */
664 PS_ADD("itrealvalue", "%d", 0); /* XXX */
665 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
666 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
667 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
668 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
669 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
670 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
671 PS_ADD("startstack", "%u", 0); /* XXX */
672 PS_ADD("kstkesp", "%u", 0); /* XXX */
673 PS_ADD("kstkeip", "%u", 0); /* XXX */
674 PS_ADD("signal", "%u", 0); /* XXX */
675 PS_ADD("blocked", "%u", 0); /* XXX */
676 PS_ADD("sigignore", "%u", 0); /* XXX */
677 PS_ADD("sigcatch", "%u", 0); /* XXX */
678 PS_ADD("wchan", "%u", 0); /* XXX */
679 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
680 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
681 PS_ADD("exitsignal", "%d", 0); /* XXX */
682 PS_ADD("processor", "%u", kp.ki_lastcpu);
683 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
684 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
692 * Filler function for proc/pid/statm
695 linprocfs_doprocstatm(PFS_FILL_ARGS)
697 struct kinfo_proc kp;
701 fill_kinfo_proc(p, &kp);
705 * See comments in linprocfs_doprocstatus() regarding the
706 * computation of lsize.
708 /* size resident share trs drs lrs dt */
709 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
710 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
711 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
712 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
713 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
714 lsize = B2P(kp.ki_size) - kp.ki_dsize -
715 kp.ki_ssize - kp.ki_tsize - 1;
716 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
717 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
723 * Filler function for proc/pid/status
726 linprocfs_doprocstatus(PFS_FILL_ARGS)
728 struct kinfo_proc kp;
736 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
738 if (P_SHOULDSTOP(p)) {
739 state = "T (stopped)";
746 if (p->p_flag & P_WEXIT) {
747 state = "X (exiting)";
750 switch(td2->td_state) {
752 state = "S (sleeping)";
756 state = "R (running)";
759 state = "? (unknown)";
764 state = "Z (zombie)";
767 state = "? (unknown)";
772 fill_kinfo_proc(p, &kp);
773 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
774 sbuf_printf(sb, "State:\t%s\n", state);
779 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
780 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
781 p->p_pptr->p_pid : 0);
782 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
784 p->p_ucred->cr_svuid,
785 /* FreeBSD doesn't have fsuid */
787 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
789 p->p_ucred->cr_svgid,
790 /* FreeBSD doesn't have fsgid */
792 sbuf_cat(sb, "Groups:\t");
793 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
794 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
801 * While our approximation of VmLib may not be accurate (I
802 * don't know of a simple way to verify it, and I'm not sure
803 * it has much meaning anyway), I believe it's good enough.
805 * The same code that could (I think) accurately compute VmLib
806 * could also compute VmLck, but I don't really care enough to
807 * implement it. Submissions are welcome.
809 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
810 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
811 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
812 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
813 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
814 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
815 lsize = B2P(kp.ki_size) - kp.ki_dsize -
816 kp.ki_ssize - kp.ki_tsize - 1;
817 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
822 * We support up to 128 signals, while Linux supports 32,
823 * but we only define 32 (the same 32 as Linux, to boot), so
824 * just show the lower 32 bits of each mask. XXX hack.
826 * NB: on certain platforms (Sparc at least) Linux actually
827 * supports 64 signals, but this code is a long way from
828 * running on anything but i386, so ignore that for now.
831 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
833 * I can't seem to find out where the signal mask is in
834 * relation to struct proc, so SigBlk is left unimplemented.
836 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
838 mtx_lock(&ps->ps_mtx);
839 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
840 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
841 mtx_unlock(&ps->ps_mtx);
845 * Linux also prints the capability masks, but we don't have
846 * capabilities yet, and when we do get them they're likely to
847 * be meaningless to Linux programs, so we lie. XXX
849 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
850 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
851 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
858 * Filler function for proc/pid/cwd
861 linprocfs_doproccwd(PFS_FILL_ARGS)
863 char *fullpath = "unknown";
864 char *freepath = NULL;
866 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
867 sbuf_printf(sb, "%s", fullpath);
869 free(freepath, M_TEMP);
874 * Filler function for proc/pid/root
877 linprocfs_doprocroot(PFS_FILL_ARGS)
880 char *fullpath = "unknown";
881 char *freepath = NULL;
883 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
884 vn_fullpath(td, rvp, &fullpath, &freepath);
885 sbuf_printf(sb, "%s", fullpath);
887 free(freepath, M_TEMP);
892 * Filler function for proc/pid/cmdline
895 linprocfs_doproccmdline(PFS_FILL_ARGS)
900 if ((ret = p_cansee(td, p)) != 0) {
906 * Mimic linux behavior and pass only processes with usermode
907 * address space as valid. Return zero silently otherwize.
909 if (p->p_vmspace == &vmspace0) {
913 if (p->p_args != NULL) {
914 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
919 if ((p->p_flag & P_SYSTEM) != 0) {
926 ret = proc_getargv(td, p, sb);
931 * Filler function for proc/pid/environ
934 linprocfs_doprocenviron(PFS_FILL_ARGS)
939 if ((ret = p_candebug(td, p)) != 0) {
945 * Mimic linux behavior and pass only processes with usermode
946 * address space as valid. Return zero silently otherwize.
948 if (p->p_vmspace == &vmspace0) {
953 if ((p->p_flag & P_SYSTEM) != 0) {
960 ret = proc_getenvv(td, p, sb);
964 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
965 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
966 static char vdso_str[] = " [vdso]";
967 static char stack_str[] = " [stack]";
970 * Filler function for proc/pid/maps
973 linprocfs_doprocmaps(PFS_FILL_ARGS)
977 vm_map_entry_t entry, tmp_entry;
978 vm_object_t obj, tobj, lobj;
979 vm_offset_t e_start, e_end;
980 vm_ooffset_t off = 0;
982 unsigned int last_timestamp;
983 char *name = "", *freename = NULL;
984 const char *l_map_str;
986 int ref_count, shadow_count, flags;
992 error = p_candebug(td, p);
997 if (uio->uio_rw != UIO_READ)
1001 vm = vmspace_acquire_ref(p);
1005 if (SV_CURPROC_FLAG(SV_LP64))
1006 l_map_str = l64_map_str;
1008 l_map_str = l32_map_str;
1010 vm_map_lock_read(map);
1011 for (entry = map->header.next; entry != &map->header;
1012 entry = entry->next) {
1015 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1017 e_prot = entry->protection;
1018 e_start = entry->start;
1020 obj = entry->object.vm_object;
1021 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1022 VM_OBJECT_RLOCK(tobj);
1024 VM_OBJECT_RUNLOCK(lobj);
1027 last_timestamp = map->timestamp;
1028 vm_map_unlock_read(map);
1031 off = IDX_TO_OFF(lobj->size);
1032 vp = vm_object_vnode(lobj);
1036 VM_OBJECT_RUNLOCK(lobj);
1038 ref_count = obj->ref_count;
1039 shadow_count = obj->shadow_count;
1040 VM_OBJECT_RUNLOCK(obj);
1042 vn_fullpath(td, vp, &name, &freename);
1043 vn_lock(vp, LK_SHARED | LK_RETRY);
1044 VOP_GETATTR(vp, &vat, td->td_ucred);
1045 ino = vat.va_fileid;
1047 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1048 if (e_start == p->p_sysent->sv_shared_page_base)
1050 if (e_end == p->p_sysent->sv_usrstack)
1061 * start, end, access, offset, major, minor, inode, name.
1063 error = sbuf_printf(sb, l_map_str,
1064 (u_long)e_start, (u_long)e_end,
1065 (e_prot & VM_PROT_READ)?"r":"-",
1066 (e_prot & VM_PROT_WRITE)?"w":"-",
1067 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1077 free(freename, M_TEMP);
1078 vm_map_lock_read(map);
1083 if (last_timestamp != map->timestamp) {
1085 * Look again for the entry because the map was
1086 * modified while it was unlocked. Specifically,
1087 * the entry may have been clipped, merged, or deleted.
1089 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1093 vm_map_unlock_read(map);
1100 * Criteria for interface name translation
1102 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1105 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1107 struct ifnet *ifscan;
1110 IFNET_RLOCK_ASSERT();
1112 /* Short-circuit non ethernet interfaces */
1113 if (!IFP_IS_ETH(ifp))
1114 return (strlcpy(buffer, ifp->if_xname, buflen));
1116 /* Determine the (relative) unit number for ethernet interfaces */
1118 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1120 return (snprintf(buffer, buflen, "eth%d", ethno));
1121 if (IFP_IS_ETH(ifscan))
1129 * Filler function for proc/net/dev
1132 linprocfs_donetdev(PFS_FILL_ARGS)
1134 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1137 sbuf_printf(sb, "%6s|%58s|%s\n"
1139 "Inter-", " Receive", " Transmit",
1141 "bytes packets errs drop fifo frame compressed multicast",
1142 "bytes packets errs drop fifo colls carrier compressed");
1144 CURVNET_SET(TD_TO_VNET(curthread));
1146 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1147 linux_ifname(ifp, ifname, sizeof ifname);
1148 sbuf_printf(sb, "%6.6s: ", ifname);
1149 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1150 ifp->if_ibytes, /* rx_bytes */
1151 ifp->if_ipackets, /* rx_packets */
1152 ifp->if_ierrors, /* rx_errors */
1153 ifp->if_iqdrops, /* rx_dropped +
1154 * rx_missed_errors */
1155 0UL, /* rx_fifo_errors */
1156 0UL, /* rx_length_errors +
1159 * rx_frame_errors */
1160 0UL, /* rx_compressed */
1161 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1162 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1163 ifp->if_obytes, /* tx_bytes */
1164 ifp->if_opackets, /* tx_packets */
1165 ifp->if_oerrors, /* tx_errors */
1166 0UL, /* tx_dropped */
1167 0UL, /* tx_fifo_errors */
1168 ifp->if_collisions, /* collisions */
1169 0UL, /* tx_carrier_errors +
1170 * tx_aborted_errors +
1171 * tx_window_errors +
1172 * tx_heartbeat_errors */
1173 0UL); /* tx_compressed */
1182 * Filler function for proc/sys/kernel/osrelease
1185 linprocfs_doosrelease(PFS_FILL_ARGS)
1187 char osrelease[LINUX_MAX_UTSNAME];
1189 linux_get_osrelease(td, osrelease);
1190 sbuf_printf(sb, "%s\n", osrelease);
1196 * Filler function for proc/sys/kernel/ostype
1199 linprocfs_doostype(PFS_FILL_ARGS)
1201 char osname[LINUX_MAX_UTSNAME];
1203 linux_get_osname(td, osname);
1204 sbuf_printf(sb, "%s\n", osname);
1210 * Filler function for proc/sys/kernel/version
1213 linprocfs_doosbuild(PFS_FILL_ARGS)
1216 linprocfs_osbuild(td, sb);
1222 * Filler function for proc/sys/kernel/msgmni
1225 linprocfs_domsgmni(PFS_FILL_ARGS)
1228 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1233 * Filler function for proc/sys/kernel/pid_max
1236 linprocfs_dopid_max(PFS_FILL_ARGS)
1239 sbuf_printf(sb, "%i\n", PID_MAX);
1244 * Filler function for proc/sys/kernel/sem
1247 linprocfs_dosem(PFS_FILL_ARGS)
1250 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1251 seminfo.semopm, seminfo.semmni);
1256 * Filler function for proc/scsi/device_info
1259 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1266 * Filler function for proc/scsi/scsi
1269 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1276 * Filler function for proc/devices
1279 linprocfs_dodevices(PFS_FILL_ARGS)
1282 sbuf_printf(sb, "Character devices:\n");
1284 char_devices = linux_get_char_devices();
1285 sbuf_printf(sb, "%s", char_devices);
1286 linux_free_get_char_devices(char_devices);
1288 sbuf_printf(sb, "\nBlock devices:\n");
1294 * Filler function for proc/cmdline
1297 linprocfs_docmdline(PFS_FILL_ARGS)
1300 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1301 sbuf_printf(sb, " ro root=302\n");
1306 * Filler function for proc/filesystems
1309 linprocfs_dofilesystems(PFS_FILL_ARGS)
1311 struct vfsconf *vfsp;
1314 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1315 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1316 sbuf_printf(sb, "nodev");
1317 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1325 * Filler function for proc/modules
1328 linprocfs_domodules(PFS_FILL_ARGS)
1330 struct linker_file *lf;
1332 TAILQ_FOREACH(lf, &linker_files, link) {
1333 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1334 (unsigned long)lf->size, lf->refs);
1341 * Filler function for proc/pid/fd
1344 linprocfs_dofdescfs(PFS_FILL_ARGS)
1348 sbuf_printf(sb, "/dev/fd");
1350 sbuf_printf(sb, "unknown");
1356 * Filler function for proc/sys/kernel/random/uuid
1359 linprocfs_douuid(PFS_FILL_ARGS)
1363 kern_uuidgen(&uuid, 1);
1364 sbuf_printf_uuid(sb, &uuid);
1365 sbuf_printf(sb, "\n");
1370 * Filler function for proc/pid/auxv
1373 linprocfs_doauxv(PFS_FILL_ARGS)
1376 off_t buflen, resid;
1380 * Mimic linux behavior and pass only processes with usermode
1381 * address space as valid. Return zero silently otherwise.
1383 if (p->p_vmspace == &vmspace0)
1386 if (uio->uio_resid == 0)
1388 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1391 asb = sbuf_new_auto();
1394 error = proc_getauxv(td, p, asb);
1396 error = sbuf_finish(asb);
1398 resid = sbuf_len(asb) - uio->uio_offset;
1399 if (resid > uio->uio_resid)
1400 buflen = uio->uio_resid;
1403 if (buflen > IOSIZE_MAX)
1405 if (buflen > MAXPHYS)
1411 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1420 linprocfs_init(PFS_INIT_ARGS)
1422 struct pfs_node *root;
1423 struct pfs_node *dir;
1428 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1429 NULL, NULL, NULL, PFS_RD);
1430 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1431 NULL, NULL, NULL, PFS_RD);
1432 pfs_create_file(root, "devices", &linprocfs_dodevices,
1433 NULL, NULL, NULL, PFS_RD);
1434 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1435 NULL, NULL, NULL, PFS_RD);
1436 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1437 NULL, NULL, NULL, PFS_RD);
1438 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1439 NULL, NULL, NULL, PFS_RD);
1441 pfs_create_file(root, "modules", &linprocfs_domodules,
1442 NULL, NULL, NULL, PFS_RD);
1444 pfs_create_file(root, "mounts", &linprocfs_domtab,
1445 NULL, NULL, NULL, PFS_RD);
1446 pfs_create_file(root, "mtab", &linprocfs_domtab,
1447 NULL, NULL, NULL, PFS_RD);
1448 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1449 NULL, NULL, NULL, PFS_RD);
1450 pfs_create_link(root, "self", &procfs_docurproc,
1451 NULL, NULL, NULL, 0);
1452 pfs_create_file(root, "stat", &linprocfs_dostat,
1453 NULL, NULL, NULL, PFS_RD);
1454 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1455 NULL, NULL, NULL, PFS_RD);
1456 pfs_create_file(root, "uptime", &linprocfs_douptime,
1457 NULL, NULL, NULL, PFS_RD);
1458 pfs_create_file(root, "version", &linprocfs_doversion,
1459 NULL, NULL, NULL, PFS_RD);
1462 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1463 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1464 NULL, NULL, NULL, PFS_RD);
1466 /* /proc/<pid>/... */
1467 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1468 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1469 NULL, NULL, NULL, PFS_RD);
1470 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1471 NULL, NULL, NULL, 0);
1472 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1473 NULL, NULL, NULL, PFS_RD);
1474 pfs_create_link(dir, "exe", &procfs_doprocfile,
1475 NULL, &procfs_notsystem, NULL, 0);
1476 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1477 NULL, NULL, NULL, PFS_RD);
1478 pfs_create_file(dir, "mem", &procfs_doprocmem,
1479 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1480 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1481 NULL, NULL, NULL, 0);
1482 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1483 NULL, NULL, NULL, PFS_RD);
1484 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1485 NULL, NULL, NULL, PFS_RD);
1486 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1487 NULL, NULL, NULL, PFS_RD);
1488 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1489 NULL, NULL, NULL, 0);
1490 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1491 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1493 /* /proc/scsi/... */
1494 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1495 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1496 NULL, NULL, NULL, PFS_RD);
1497 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1498 NULL, NULL, NULL, PFS_RD);
1501 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1502 /* /proc/sys/kernel/... */
1503 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1504 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1505 NULL, NULL, NULL, PFS_RD);
1506 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1507 NULL, NULL, NULL, PFS_RD);
1508 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1509 NULL, NULL, NULL, PFS_RD);
1510 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1511 NULL, NULL, NULL, PFS_RD);
1512 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1513 NULL, NULL, NULL, PFS_RD);
1514 pfs_create_file(dir, "sem", &linprocfs_dosem,
1515 NULL, NULL, NULL, PFS_RD);
1517 /* /proc/sys/kernel/random/... */
1518 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1519 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1520 NULL, NULL, NULL, PFS_RD);
1529 linprocfs_uninit(PFS_INIT_ARGS)
1532 /* nothing to do, pseudofs will GC */
1536 PSEUDOFS(linprocfs, 1, 0);
1537 #if defined(__amd64__)
1538 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1540 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1542 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1543 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1544 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);