2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
42 #include "opt_compat.h"
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
47 #include <sys/param.h>
48 #include <sys/queue.h>
49 #include <sys/blist.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
55 #include <sys/kernel.h>
56 #include <sys/linker.h>
58 #include <sys/malloc.h>
59 #include <sys/mount.h>
61 #include <sys/mutex.h>
62 #include <sys/namei.h>
64 #include <sys/ptrace.h>
65 #include <sys/resourcevar.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
71 #include <sys/systm.h>
76 #include <sys/vmmeter.h>
77 #include <sys/vnode.h>
84 #include <vm/vm_extern.h>
86 #include <vm/vm_map.h>
87 #include <vm/vm_param.h>
88 #include <vm/vm_object.h>
89 #include <vm/swap_pager.h>
91 #include <machine/clock.h>
93 #include <geom/geom.h>
94 #include <geom/geom_int.h>
96 #if defined(__i386__) || defined(__amd64__)
97 #include <machine/cputypes.h>
98 #include <machine/md_var.h>
99 #endif /* __i386__ || __amd64__ */
101 #ifdef COMPAT_FREEBSD32
102 #include <compat/freebsd32/freebsd32_util.h>
105 #ifdef COMPAT_LINUX32 /* XXX */
106 #include <machine/../linux32/linux.h>
108 #include <machine/../linux/linux.h>
110 #include <compat/linux/linux_ioctl.h>
111 #include <compat/linux/linux_mib.h>
112 #include <compat/linux/linux_util.h>
113 #include <fs/pseudofs/pseudofs.h>
114 #include <fs/procfs/procfs.h>
117 * Various conversion macros
119 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
120 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
121 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
122 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
123 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
124 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
125 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
126 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
129 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
131 * The linux procfs state field displays one of the characters RSDZTW to
132 * denote running, sleeping in an interruptible wait, waiting in an
133 * uninterruptible disk sleep, a zombie process, process is being traced
134 * or stopped, or process is paging respectively.
136 * Our struct kinfo_proc contains the variable ki_stat which contains a
137 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
139 * This character array is used with ki_stati-1 as an index and tries to
140 * map our states to suitable linux states.
142 static char linux_state[] = "RRSTZDD";
145 * Filler function for proc/meminfo
148 linprocfs_domeminfo(PFS_FILL_ARGS)
150 unsigned long memtotal; /* total memory in bytes */
151 unsigned long memused; /* used memory in bytes */
152 unsigned long memfree; /* free memory in bytes */
153 unsigned long memshared; /* shared memory ??? */
154 unsigned long buffers, cached; /* buffer / cache memory ??? */
155 unsigned long long swaptotal; /* total swap space in bytes */
156 unsigned long long swapused; /* used swap space in bytes */
157 unsigned long long swapfree; /* free swap space in bytes */
161 memtotal = physmem * PAGE_SIZE;
163 * The correct thing here would be:
165 memfree = cnt.v_free_count * PAGE_SIZE;
166 memused = memtotal - memfree;
168 * but it might mislead linux binaries into thinking there
169 * is very little memory left, so we cheat and tell them that
170 * all memory that isn't wired down is free.
172 memused = cnt.v_wire_count * PAGE_SIZE;
173 memfree = memtotal - memused;
174 swap_pager_status(&i, &j);
175 swaptotal = (unsigned long long)i * PAGE_SIZE;
176 swapused = (unsigned long long)j * PAGE_SIZE;
177 swapfree = swaptotal - swapused;
179 mtx_lock(&vm_object_list_mtx);
180 TAILQ_FOREACH(object, &vm_object_list, object_list)
181 if (object->shadow_count > 1)
182 memshared += object->resident_page_count;
183 mtx_unlock(&vm_object_list_mtx);
184 memshared *= PAGE_SIZE;
186 * We'd love to be able to write:
190 * but bufspace is internal to vfs_bio.c and we don't feel
191 * like unstaticizing it just for linprocfs's sake.
194 cached = cnt.v_cache_count * PAGE_SIZE;
197 " total: used: free: shared: buffers: cached:\n"
198 "Mem: %lu %lu %lu %lu %lu %lu\n"
199 "Swap: %llu %llu %llu\n"
200 "MemTotal: %9lu kB\n"
202 "MemShared:%9lu kB\n"
205 "SwapTotal:%9llu kB\n"
206 "SwapFree: %9llu kB\n",
207 memtotal, memused, memfree, memshared, buffers, cached,
208 swaptotal, swapused, swapfree,
209 B2K(memtotal), B2K(memfree),
210 B2K(memshared), B2K(buffers), B2K(cached),
211 B2K(swaptotal), B2K(swapfree));
216 #if defined(__i386__) || defined(__amd64__)
218 * Filler function for proc/cpuinfo (i386 & amd64 version)
221 linprocfs_docpuinfo(PFS_FILL_ARGS)
227 int class, fqmhz, fqkhz;
231 * We default the flags to include all non-conflicting flags,
232 * and the Intel versions of conflicting flags.
234 static char *flags[] = {
235 "fpu", "vme", "de", "pse", "tsc",
236 "msr", "pae", "mce", "cx8", "apic",
237 "sep", "sep", "mtrr", "pge", "mca",
238 "cmov", "pat", "pse36", "pn", "b19",
239 "b20", "b21", "mmxext", "mmx", "fxsr",
240 "xmm", "sse2", "b27", "b28", "b29",
264 #else /* __amd64__ */
271 hw_model[0] = CTL_HW;
272 hw_model[1] = HW_MODEL;
274 size = sizeof(model);
275 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
276 strcpy(model, "unknown");
277 for (i = 0; i < mp_ncpus; ++i) {
280 "vendor_id\t: %.20s\n"
284 "stepping\t: %u\n\n",
285 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
286 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
287 /* XXX per-cpu vendor / class / model / id? */
290 sbuf_cat(sb, "flags\t\t:");
293 switch (cpu_vendor_id) {
298 case CPU_VENDOR_CYRIX:
304 for (i = 0; i < 32; i++)
305 if (cpu_feature & (1 << i))
306 sbuf_printf(sb, " %s", flags[i]);
308 freq = atomic_load_acq_64(&tsc_freq);
310 fqmhz = (freq + 4999) / 1000000;
311 fqkhz = ((freq + 4999) / 10000) % 100;
313 "cpu MHz\t\t: %d.%02d\n"
314 "bogomips\t: %d.%02d\n",
315 fqmhz, fqkhz, fqmhz, fqkhz);
320 #endif /* __i386__ || __amd64__ */
323 * Filler function for proc/mtab
325 * This file doesn't exist in Linux' procfs, but is included here so
326 * users can symlink /compat/linux/etc/mtab to /proc/mtab
329 linprocfs_domtab(PFS_FILL_ARGS)
334 char *dlep, *flep, *mntto, *mntfrom, *fstype;
338 /* resolve symlinks etc. in the emulation tree prefix */
339 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
342 lep = linux_emul_path;
344 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
347 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
349 lep_len = strlen(lep);
351 mtx_lock(&mountlist_mtx);
353 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
354 /* determine device name */
355 mntfrom = mp->mnt_stat.f_mntfromname;
357 /* determine mount point */
358 mntto = mp->mnt_stat.f_mntonname;
359 if (strncmp(mntto, lep, lep_len) == 0 &&
360 mntto[lep_len] == '/')
363 /* determine fs type */
364 fstype = mp->mnt_stat.f_fstypename;
365 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
366 mntfrom = fstype = "proc";
367 else if (strcmp(fstype, "procfs") == 0)
370 if (strcmp(fstype, "linsysfs") == 0) {
371 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
372 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
374 /* For Linux msdosfs is called vfat */
375 if (strcmp(fstype, "msdosfs") == 0)
377 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
378 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
380 #define ADD_OPTION(opt, name) \
381 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
382 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
383 ADD_OPTION(MNT_NOEXEC, "noexec");
384 ADD_OPTION(MNT_NOSUID, "nosuid");
385 ADD_OPTION(MNT_UNION, "union");
386 ADD_OPTION(MNT_ASYNC, "async");
387 ADD_OPTION(MNT_SUIDDIR, "suiddir");
388 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
389 ADD_OPTION(MNT_NOATIME, "noatime");
391 /* a real Linux mtab will also show NFS options */
392 sbuf_printf(sb, " 0 0\n");
394 mtx_unlock(&mountlist_mtx);
401 * Filler function for proc/partitions
405 linprocfs_dopartitions(PFS_FILL_ARGS)
409 struct g_provider *pp;
417 /* resolve symlinks etc. in the emulation tree prefix */
418 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
421 lep = linux_emul_path;
423 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
426 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
428 lep_len = strlen(lep);
432 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
433 "ruse wio wmerge wsect wuse running use aveq\n");
435 LIST_FOREACH(cp, &g_classes, class) {
436 if (strcmp(cp->name, "DISK") == 0 ||
437 strcmp(cp->name, "PART") == 0)
438 LIST_FOREACH(gp, &cp->geom, geom) {
439 LIST_FOREACH(pp, &gp->provider, provider) {
440 if (linux_driver_get_major_minor(
441 pp->name, &major, &minor) != 0) {
445 sbuf_printf(sb, "%d %d %lld %s "
447 "%d %d %d %d %d %d\n",
449 (long long)pp->mediasize, pp->name,
464 * Filler function for proc/stat
467 linprocfs_dostat(PFS_FILL_ARGS)
470 long cp_time[CPUSTATES];
474 read_cpu_time(cp_time);
475 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
476 T2J(cp_time[CP_USER]),
477 T2J(cp_time[CP_NICE]),
478 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
479 T2J(cp_time[CP_IDLE]));
482 cp = pcpu->pc_cp_time;
483 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
486 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
502 (long long)boottime.tv_sec);
507 linprocfs_doswaps(PFS_FILL_ARGS)
510 uintmax_t total, used;
512 char devname[SPECNAMELEN + 1];
514 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
517 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
519 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
520 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
523 * The space and not tab after the device name is on
524 * purpose. Linux does so.
526 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
527 devname, total, used);
534 * Filler function for proc/uptime
537 linprocfs_douptime(PFS_FILL_ARGS)
539 long cp_time[CPUSTATES];
543 read_cpu_time(cp_time);
544 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
545 (long long)tv.tv_sec, tv.tv_usec / 10000,
546 T2S(cp_time[CP_IDLE] / mp_ncpus),
547 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
555 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
561 strncpy(osbuild, version, 256);
563 cp1 = strstr(osbuild, "\n");
564 cp2 = strstr(osbuild, ":");
567 cp1 = strstr(osbuild, "#");
571 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
574 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
581 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
587 cp = strstr(version, "\n ");
589 strncpy(builder, cp + 5, 256);
591 cp = strstr(builder, ":");
596 sbuf_cat(sb, builder);
599 sbuf_cat(sb, "des@freebsd.org");
603 * Filler function for proc/version
606 linprocfs_doversion(PFS_FILL_ARGS)
608 char osname[LINUX_MAX_UTSNAME];
609 char osrelease[LINUX_MAX_UTSNAME];
611 linux_get_osname(td, osname);
612 linux_get_osrelease(td, osrelease);
613 sbuf_printf(sb, "%s version %s (", osname, osrelease);
614 linprocfs_osbuilder(td, sb);
615 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
616 linprocfs_osbuild(td, sb);
623 * Filler function for proc/loadavg
626 linprocfs_doloadavg(PFS_FILL_ARGS)
630 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
631 (int)(averunnable.ldavg[0] / averunnable.fscale),
632 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
633 (int)(averunnable.ldavg[1] / averunnable.fscale),
634 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
635 (int)(averunnable.ldavg[2] / averunnable.fscale),
636 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
637 1, /* number of running tasks */
638 nprocs, /* number of tasks */
639 lastpid /* the last pid */
645 * Filler function for proc/pid/stat
648 linprocfs_doprocstat(PFS_FILL_ARGS)
650 struct kinfo_proc kp;
652 static int ratelimit = 0;
653 vm_offset_t startcode, startdata;
656 fill_kinfo_proc(p, &kp);
658 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
659 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
664 sbuf_printf(sb, "%d", p->p_pid);
665 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
666 PS_ADD("comm", "(%s)", p->p_comm);
667 if (kp.ki_stat > sizeof(linux_state)) {
670 if (ratelimit == 0) {
671 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
672 kp.ki_stat, sizeof(linux_state));
676 state = linux_state[kp.ki_stat - 1];
677 PS_ADD("state", "%c", state);
678 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
679 PS_ADD("pgrp", "%d", p->p_pgid);
680 PS_ADD("session", "%d", p->p_session->s_sid);
682 PS_ADD("tty", "%d", kp.ki_tdev);
683 PS_ADD("tpgid", "%d", kp.ki_tpgid);
684 PS_ADD("flags", "%u", 0); /* XXX */
685 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
686 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
687 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
688 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
689 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
690 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
691 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
692 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
693 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
694 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
695 PS_ADD("0", "%d", 0); /* removed field */
696 PS_ADD("itrealvalue", "%d", 0); /* XXX */
697 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
698 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
699 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
700 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
701 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
702 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
703 PS_ADD("startstack", "%u", 0); /* XXX */
704 PS_ADD("kstkesp", "%u", 0); /* XXX */
705 PS_ADD("kstkeip", "%u", 0); /* XXX */
706 PS_ADD("signal", "%u", 0); /* XXX */
707 PS_ADD("blocked", "%u", 0); /* XXX */
708 PS_ADD("sigignore", "%u", 0); /* XXX */
709 PS_ADD("sigcatch", "%u", 0); /* XXX */
710 PS_ADD("wchan", "%u", 0); /* XXX */
711 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
712 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
713 PS_ADD("exitsignal", "%d", 0); /* XXX */
714 PS_ADD("processor", "%u", kp.ki_lastcpu);
715 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
716 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
724 * Filler function for proc/pid/statm
727 linprocfs_doprocstatm(PFS_FILL_ARGS)
729 struct kinfo_proc kp;
733 fill_kinfo_proc(p, &kp);
737 * See comments in linprocfs_doprocstatus() regarding the
738 * computation of lsize.
740 /* size resident share trs drs lrs dt */
741 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
742 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
743 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
744 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
745 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
746 lsize = B2P(kp.ki_size) - kp.ki_dsize -
747 kp.ki_ssize - kp.ki_tsize - 1;
748 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
749 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
755 * Filler function for proc/pid/status
758 linprocfs_doprocstatus(PFS_FILL_ARGS)
760 struct kinfo_proc kp;
768 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
770 if (P_SHOULDSTOP(p)) {
771 state = "T (stopped)";
778 if (p->p_flag & P_WEXIT) {
779 state = "X (exiting)";
782 switch(td2->td_state) {
784 state = "S (sleeping)";
788 state = "R (running)";
791 state = "? (unknown)";
796 state = "Z (zombie)";
799 state = "? (unknown)";
804 fill_kinfo_proc(p, &kp);
805 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
806 sbuf_printf(sb, "State:\t%s\n", state);
811 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
812 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
813 p->p_pptr->p_pid : 0);
814 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
816 p->p_ucred->cr_svuid,
817 /* FreeBSD doesn't have fsuid */
819 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
821 p->p_ucred->cr_svgid,
822 /* FreeBSD doesn't have fsgid */
824 sbuf_cat(sb, "Groups:\t");
825 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
826 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
833 * While our approximation of VmLib may not be accurate (I
834 * don't know of a simple way to verify it, and I'm not sure
835 * it has much meaning anyway), I believe it's good enough.
837 * The same code that could (I think) accurately compute VmLib
838 * could also compute VmLck, but I don't really care enough to
839 * implement it. Submissions are welcome.
841 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
842 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
843 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
844 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
845 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
846 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
847 lsize = B2P(kp.ki_size) - kp.ki_dsize -
848 kp.ki_ssize - kp.ki_tsize - 1;
849 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
854 * We support up to 128 signals, while Linux supports 32,
855 * but we only define 32 (the same 32 as Linux, to boot), so
856 * just show the lower 32 bits of each mask. XXX hack.
858 * NB: on certain platforms (Sparc at least) Linux actually
859 * supports 64 signals, but this code is a long way from
860 * running on anything but i386, so ignore that for now.
863 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
865 * I can't seem to find out where the signal mask is in
866 * relation to struct proc, so SigBlk is left unimplemented.
868 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
870 mtx_lock(&ps->ps_mtx);
871 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
872 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
873 mtx_unlock(&ps->ps_mtx);
877 * Linux also prints the capability masks, but we don't have
878 * capabilities yet, and when we do get them they're likely to
879 * be meaningless to Linux programs, so we lie. XXX
881 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
882 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
883 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
890 * Filler function for proc/pid/cwd
893 linprocfs_doproccwd(PFS_FILL_ARGS)
895 char *fullpath = "unknown";
896 char *freepath = NULL;
898 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
899 sbuf_printf(sb, "%s", fullpath);
901 free(freepath, M_TEMP);
906 * Filler function for proc/pid/root
909 linprocfs_doprocroot(PFS_FILL_ARGS)
912 char *fullpath = "unknown";
913 char *freepath = NULL;
915 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
916 vn_fullpath(td, rvp, &fullpath, &freepath);
917 sbuf_printf(sb, "%s", fullpath);
919 free(freepath, M_TEMP);
924 * Filler function for proc/pid/cmdline
927 linprocfs_doproccmdline(PFS_FILL_ARGS)
932 if ((ret = p_cansee(td, p)) != 0) {
938 * Mimic linux behavior and pass only processes with usermode
939 * address space as valid. Return zero silently otherwize.
941 if (p->p_vmspace == &vmspace0) {
945 if (p->p_args != NULL) {
946 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
951 if ((p->p_flag & P_SYSTEM) != 0) {
958 ret = proc_getargv(td, p, sb);
963 * Filler function for proc/pid/environ
966 linprocfs_doprocenviron(PFS_FILL_ARGS)
971 if ((ret = p_candebug(td, p)) != 0) {
977 * Mimic linux behavior and pass only processes with usermode
978 * address space as valid. Return zero silently otherwize.
980 if (p->p_vmspace == &vmspace0) {
985 if ((p->p_flag & P_SYSTEM) != 0) {
992 ret = proc_getenvv(td, p, sb);
997 * Filler function for proc/pid/maps
1000 linprocfs_doprocmaps(PFS_FILL_ARGS)
1004 vm_map_entry_t entry, tmp_entry;
1005 vm_object_t obj, tobj, lobj;
1006 vm_offset_t e_start, e_end;
1007 vm_ooffset_t off = 0;
1009 unsigned int last_timestamp;
1010 char *name = "", *freename = NULL;
1012 int ref_count, shadow_count, flags;
1019 error = p_candebug(td, p);
1024 if (uio->uio_rw != UIO_READ)
1025 return (EOPNOTSUPP);
1028 vm = vmspace_acquire_ref(p);
1032 vm_map_lock_read(map);
1033 for (entry = map->header.next; entry != &map->header;
1034 entry = entry->next) {
1037 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1039 e_prot = entry->protection;
1040 e_start = entry->start;
1042 obj = entry->object.vm_object;
1043 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1044 VM_OBJECT_LOCK(tobj);
1046 VM_OBJECT_UNLOCK(lobj);
1049 last_timestamp = map->timestamp;
1050 vm_map_unlock_read(map);
1053 off = IDX_TO_OFF(lobj->size);
1054 if (lobj->type == OBJT_VNODE) {
1062 VM_OBJECT_UNLOCK(lobj);
1064 ref_count = obj->ref_count;
1065 shadow_count = obj->shadow_count;
1066 VM_OBJECT_UNLOCK(obj);
1068 vn_fullpath(td, vp, &name, &freename);
1069 locked = VFS_LOCK_GIANT(vp->v_mount);
1070 vn_lock(vp, LK_SHARED | LK_RETRY);
1071 VOP_GETATTR(vp, &vat, td->td_ucred);
1072 ino = vat.va_fileid;
1074 VFS_UNLOCK_GIANT(locked);
1084 * start, end, access, offset, major, minor, inode, name.
1086 error = sbuf_printf(sb,
1087 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1088 (u_long)e_start, (u_long)e_end,
1089 (e_prot & VM_PROT_READ)?"r":"-",
1090 (e_prot & VM_PROT_WRITE)?"w":"-",
1091 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1101 free(freename, M_TEMP);
1102 vm_map_lock_read(map);
1107 if (last_timestamp != map->timestamp) {
1109 * Look again for the entry because the map was
1110 * modified while it was unlocked. Specifically,
1111 * the entry may have been clipped, merged, or deleted.
1113 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1117 vm_map_unlock_read(map);
1124 * Filler function for proc/net/dev
1127 linprocfs_donetdev(PFS_FILL_ARGS)
1129 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1132 sbuf_printf(sb, "%6s|%58s|%s\n"
1134 "Inter-", " Receive", " Transmit",
1136 "bytes packets errs drop fifo frame compressed multicast",
1137 "bytes packets errs drop fifo colls carrier compressed");
1139 CURVNET_SET(TD_TO_VNET(curthread));
1141 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1142 linux_ifname(ifp, ifname, sizeof ifname);
1143 sbuf_printf(sb, "%6.6s: ", ifname);
1144 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1145 ifp->if_ibytes, /* rx_bytes */
1146 ifp->if_ipackets, /* rx_packets */
1147 ifp->if_ierrors, /* rx_errors */
1148 ifp->if_iqdrops, /* rx_dropped +
1149 * rx_missed_errors */
1150 0UL, /* rx_fifo_errors */
1151 0UL, /* rx_length_errors +
1154 * rx_frame_errors */
1155 0UL, /* rx_compressed */
1156 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1157 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1158 ifp->if_obytes, /* tx_bytes */
1159 ifp->if_opackets, /* tx_packets */
1160 ifp->if_oerrors, /* tx_errors */
1161 0UL, /* tx_dropped */
1162 0UL, /* tx_fifo_errors */
1163 ifp->if_collisions, /* collisions */
1164 0UL, /* tx_carrier_errors +
1165 * tx_aborted_errors +
1166 * tx_window_errors +
1167 * tx_heartbeat_errors */
1168 0UL); /* tx_compressed */
1177 * Filler function for proc/sys/kernel/osrelease
1180 linprocfs_doosrelease(PFS_FILL_ARGS)
1182 char osrelease[LINUX_MAX_UTSNAME];
1184 linux_get_osrelease(td, osrelease);
1185 sbuf_printf(sb, "%s\n", osrelease);
1191 * Filler function for proc/sys/kernel/ostype
1194 linprocfs_doostype(PFS_FILL_ARGS)
1196 char osname[LINUX_MAX_UTSNAME];
1198 linux_get_osname(td, osname);
1199 sbuf_printf(sb, "%s\n", osname);
1205 * Filler function for proc/sys/kernel/version
1208 linprocfs_doosbuild(PFS_FILL_ARGS)
1211 linprocfs_osbuild(td, sb);
1217 * Filler function for proc/sys/kernel/msgmni
1220 linprocfs_domsgmni(PFS_FILL_ARGS)
1223 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1228 * Filler function for proc/sys/kernel/pid_max
1231 linprocfs_dopid_max(PFS_FILL_ARGS)
1234 sbuf_printf(sb, "%i\n", PID_MAX);
1239 * Filler function for proc/sys/kernel/sem
1242 linprocfs_dosem(PFS_FILL_ARGS)
1245 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1246 seminfo.semopm, seminfo.semmni);
1251 * Filler function for proc/scsi/device_info
1254 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1261 * Filler function for proc/scsi/scsi
1264 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1270 extern struct cdevsw *cdevsw[];
1273 * Filler function for proc/devices
1276 linprocfs_dodevices(PFS_FILL_ARGS)
1279 sbuf_printf(sb, "Character devices:\n");
1281 char_devices = linux_get_char_devices();
1282 sbuf_printf(sb, "%s", char_devices);
1283 linux_free_get_char_devices(char_devices);
1285 sbuf_printf(sb, "\nBlock devices:\n");
1291 * Filler function for proc/cmdline
1294 linprocfs_docmdline(PFS_FILL_ARGS)
1297 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1298 sbuf_printf(sb, " ro root=302\n");
1303 * Filler function for proc/filesystems
1306 linprocfs_dofilesystems(PFS_FILL_ARGS)
1308 struct vfsconf *vfsp;
1311 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1312 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1313 sbuf_printf(sb, "nodev");
1314 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1322 * Filler function for proc/modules
1325 linprocfs_domodules(PFS_FILL_ARGS)
1327 struct linker_file *lf;
1329 TAILQ_FOREACH(lf, &linker_files, link) {
1330 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1331 (unsigned long)lf->size, lf->refs);
1338 * Filler function for proc/pid/fd
1341 linprocfs_dofdescfs(PFS_FILL_ARGS)
1345 sbuf_printf(sb, "/dev/fd");
1347 sbuf_printf(sb, "unknown");
1353 * Filler function for proc/sys/kernel/random/uuid
1356 linprocfs_douuid(PFS_FILL_ARGS)
1360 kern_uuidgen(&uuid, 1);
1361 sbuf_printf_uuid(sb, &uuid);
1362 sbuf_printf(sb, "\n");
1371 linprocfs_init(PFS_INIT_ARGS)
1373 struct pfs_node *root;
1374 struct pfs_node *dir;
1379 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1380 NULL, NULL, NULL, PFS_RD);
1381 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1382 NULL, NULL, NULL, PFS_RD);
1383 pfs_create_file(root, "devices", &linprocfs_dodevices,
1384 NULL, NULL, NULL, PFS_RD);
1385 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1386 NULL, NULL, NULL, PFS_RD);
1387 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1388 NULL, NULL, NULL, PFS_RD);
1389 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1390 NULL, NULL, NULL, PFS_RD);
1392 pfs_create_file(root, "modules", &linprocfs_domodules,
1393 NULL, NULL, NULL, PFS_RD);
1395 pfs_create_file(root, "mounts", &linprocfs_domtab,
1396 NULL, NULL, NULL, PFS_RD);
1397 pfs_create_file(root, "mtab", &linprocfs_domtab,
1398 NULL, NULL, NULL, PFS_RD);
1399 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1400 NULL, NULL, NULL, PFS_RD);
1401 pfs_create_link(root, "self", &procfs_docurproc,
1402 NULL, NULL, NULL, 0);
1403 pfs_create_file(root, "stat", &linprocfs_dostat,
1404 NULL, NULL, NULL, PFS_RD);
1405 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1406 NULL, NULL, NULL, PFS_RD);
1407 pfs_create_file(root, "uptime", &linprocfs_douptime,
1408 NULL, NULL, NULL, PFS_RD);
1409 pfs_create_file(root, "version", &linprocfs_doversion,
1410 NULL, NULL, NULL, PFS_RD);
1413 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1414 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1415 NULL, NULL, NULL, PFS_RD);
1417 /* /proc/<pid>/... */
1418 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1419 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1420 NULL, NULL, NULL, PFS_RD);
1421 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1422 NULL, NULL, NULL, 0);
1423 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1424 NULL, NULL, NULL, PFS_RD);
1425 pfs_create_link(dir, "exe", &procfs_doprocfile,
1426 NULL, &procfs_notsystem, NULL, 0);
1427 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1428 NULL, NULL, NULL, PFS_RD);
1429 pfs_create_file(dir, "mem", &procfs_doprocmem,
1430 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1431 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1432 NULL, NULL, NULL, 0);
1433 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1434 NULL, NULL, NULL, PFS_RD);
1435 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1436 NULL, NULL, NULL, PFS_RD);
1437 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1438 NULL, NULL, NULL, PFS_RD);
1439 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1440 NULL, NULL, NULL, 0);
1442 /* /proc/scsi/... */
1443 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1444 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1445 NULL, NULL, NULL, PFS_RD);
1446 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1447 NULL, NULL, NULL, PFS_RD);
1450 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1451 /* /proc/sys/kernel/... */
1452 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1453 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1454 NULL, NULL, NULL, PFS_RD);
1455 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1456 NULL, NULL, NULL, PFS_RD);
1457 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1458 NULL, NULL, NULL, PFS_RD);
1459 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1460 NULL, NULL, NULL, PFS_RD);
1461 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1462 NULL, NULL, NULL, PFS_RD);
1463 pfs_create_file(dir, "sem", &linprocfs_dosem,
1464 NULL, NULL, NULL, PFS_RD);
1466 /* /proc/sys/kernel/random/... */
1467 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1468 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1469 NULL, NULL, NULL, PFS_RD);
1478 linprocfs_uninit(PFS_INIT_ARGS)
1481 /* nothing to do, pseudofs will GC */
1485 PSEUDOFS(linprocfs, 1, 0);
1486 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1487 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1488 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1489 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);