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/resourcevar.h>
68 #include <sys/socket.h>
69 #include <sys/sysctl.h>
70 #include <sys/systm.h>
74 #include <sys/vmmeter.h>
75 #include <sys/vnode.h>
82 #include <vm/vm_extern.h>
84 #include <vm/vm_map.h>
85 #include <vm/vm_param.h>
86 #include <vm/vm_object.h>
87 #include <vm/swap_pager.h>
89 #include <machine/clock.h>
91 #include <geom/geom.h>
92 #include <geom/geom_int.h>
94 #if defined(__i386__) || defined(__amd64__)
95 #include <machine/cputypes.h>
96 #include <machine/md_var.h>
97 #endif /* __i386__ || __amd64__ */
99 #ifdef COMPAT_LINUX32 /* XXX */
100 #include <machine/../linux32/linux.h>
102 #include <machine/../linux/linux.h>
104 #include <compat/linux/linux_ioctl.h>
105 #include <compat/linux/linux_mib.h>
106 #include <compat/linux/linux_util.h>
107 #include <fs/pseudofs/pseudofs.h>
108 #include <fs/procfs/procfs.h>
111 * Various conversion macros
113 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
114 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
115 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
116 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
117 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
118 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
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)
218 int class, fqmhz, fqkhz;
222 * We default the flags to include all non-conflicting flags,
223 * and the Intel versions of conflicting flags.
225 static char *flags[] = {
226 "fpu", "vme", "de", "pse", "tsc",
227 "msr", "pae", "mce", "cx8", "apic",
228 "sep", "sep", "mtrr", "pge", "mca",
229 "cmov", "pat", "pse36", "pn", "b19",
230 "b20", "b21", "mmxext", "mmx", "fxsr",
231 "xmm", "sse2", "b27", "b28", "b29",
255 #else /* __amd64__ */
262 hw_model[0] = CTL_HW;
263 hw_model[1] = HW_MODEL;
265 size = sizeof(model);
266 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
267 strcpy(model, "unknown");
268 for (i = 0; i < mp_ncpus; ++i) {
271 "vendor_id\t: %.20s\n"
276 i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
277 /* XXX per-cpu vendor / class / model / id? */
280 sbuf_cat(sb, "flags\t\t:");
283 switch (cpu_vendor_id) {
288 case CPU_VENDOR_CYRIX:
294 for (i = 0; i < 32; i++)
295 if (cpu_feature & (1 << i))
296 sbuf_printf(sb, " %s", flags[i]);
299 fqmhz = (tsc_freq + 4999) / 1000000;
300 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
302 "cpu MHz\t\t: %d.%02d\n"
303 "bogomips\t: %d.%02d\n",
304 fqmhz, fqkhz, fqmhz, fqkhz);
309 #endif /* __i386__ || __amd64__ */
312 * Filler function for proc/mtab
314 * This file doesn't exist in Linux' procfs, but is included here so
315 * users can symlink /compat/linux/etc/mtab to /proc/mtab
318 linprocfs_domtab(PFS_FILL_ARGS)
323 char *dlep, *flep, *mntto, *mntfrom, *fstype;
327 /* resolve symlinks etc. in the emulation tree prefix */
328 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
331 lep = linux_emul_path;
333 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
336 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
338 lep_len = strlen(lep);
340 mtx_lock(&mountlist_mtx);
342 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
343 /* determine device name */
344 mntfrom = mp->mnt_stat.f_mntfromname;
346 /* determine mount point */
347 mntto = mp->mnt_stat.f_mntonname;
348 if (strncmp(mntto, lep, lep_len) == 0 &&
349 mntto[lep_len] == '/')
352 /* determine fs type */
353 fstype = mp->mnt_stat.f_fstypename;
354 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
355 mntfrom = fstype = "proc";
356 else if (strcmp(fstype, "procfs") == 0)
359 if (strcmp(fstype, "linsysfs") == 0) {
360 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
361 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
363 /* For Linux msdosfs is called vfat */
364 if (strcmp(fstype, "msdosfs") == 0)
366 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
367 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
369 #define ADD_OPTION(opt, name) \
370 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
371 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
372 ADD_OPTION(MNT_NOEXEC, "noexec");
373 ADD_OPTION(MNT_NOSUID, "nosuid");
374 ADD_OPTION(MNT_UNION, "union");
375 ADD_OPTION(MNT_ASYNC, "async");
376 ADD_OPTION(MNT_SUIDDIR, "suiddir");
377 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
378 ADD_OPTION(MNT_NOATIME, "noatime");
380 /* a real Linux mtab will also show NFS options */
381 sbuf_printf(sb, " 0 0\n");
383 mtx_unlock(&mountlist_mtx);
390 * Filler function for proc/partitions
394 linprocfs_dopartitions(PFS_FILL_ARGS)
398 struct g_provider *pp;
406 /* resolve symlinks etc. in the emulation tree prefix */
407 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
410 lep = linux_emul_path;
412 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
415 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
417 lep_len = strlen(lep);
421 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
422 "ruse wio wmerge wsect wuse running use aveq\n");
424 LIST_FOREACH(cp, &g_classes, class) {
425 if (strcmp(cp->name, "DISK") == 0 ||
426 strcmp(cp->name, "PART") == 0)
427 LIST_FOREACH(gp, &cp->geom, geom) {
428 LIST_FOREACH(pp, &gp->provider, provider) {
429 if (linux_driver_get_major_minor(
430 pp->name, &major, &minor) != 0) {
434 sbuf_printf(sb, "%d %d %lld %s "
436 "%d %d %d %d %d %d\n",
438 (long long)pp->mediasize, pp->name,
453 * Filler function for proc/stat
456 linprocfs_dostat(PFS_FILL_ARGS)
459 long cp_time[CPUSTATES];
463 read_cpu_time(cp_time);
464 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
465 T2J(cp_time[CP_USER]),
466 T2J(cp_time[CP_NICE]),
467 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
468 T2J(cp_time[CP_IDLE]));
469 for (i = 0; i <= mp_maxid; ++i) {
473 cp = pcpu->pc_cp_time;
474 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
477 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
493 (long long)boottime.tv_sec);
498 * Filler function for proc/uptime
501 linprocfs_douptime(PFS_FILL_ARGS)
503 long cp_time[CPUSTATES];
507 read_cpu_time(cp_time);
508 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
509 (long long)tv.tv_sec, tv.tv_usec / 10000,
510 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
518 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
524 strncpy(osbuild, version, 256);
526 cp1 = strstr(osbuild, "\n");
527 cp2 = strstr(osbuild, ":");
530 cp1 = strstr(osbuild, "#");
534 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
537 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
544 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
550 cp = strstr(version, "\n ");
552 strncpy(builder, cp + 5, 256);
554 cp = strstr(builder, ":");
559 sbuf_cat(sb, builder);
562 sbuf_cat(sb, "des@freebsd.org");
566 * Filler function for proc/version
569 linprocfs_doversion(PFS_FILL_ARGS)
571 char osname[LINUX_MAX_UTSNAME];
572 char osrelease[LINUX_MAX_UTSNAME];
574 linux_get_osname(td, osname);
575 linux_get_osrelease(td, osrelease);
576 sbuf_printf(sb, "%s version %s (", osname, osrelease);
577 linprocfs_osbuilder(td, sb);
578 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
579 linprocfs_osbuild(td, sb);
586 * Filler function for proc/loadavg
589 linprocfs_doloadavg(PFS_FILL_ARGS)
593 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
594 (int)(averunnable.ldavg[0] / averunnable.fscale),
595 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
596 (int)(averunnable.ldavg[1] / averunnable.fscale),
597 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
598 (int)(averunnable.ldavg[2] / averunnable.fscale),
599 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
600 1, /* number of running tasks */
601 nprocs, /* number of tasks */
602 lastpid /* the last pid */
608 * Filler function for proc/pid/stat
611 linprocfs_doprocstat(PFS_FILL_ARGS)
613 struct kinfo_proc kp;
615 static int ratelimit = 0;
618 fill_kinfo_proc(p, &kp);
619 sbuf_printf(sb, "%d", p->p_pid);
620 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
621 PS_ADD("comm", "(%s)", p->p_comm);
622 if (kp.ki_stat > sizeof(linux_state)) {
625 if (ratelimit == 0) {
626 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
627 kp.ki_stat, sizeof(linux_state));
631 state = linux_state[kp.ki_stat - 1];
632 PS_ADD("state", "%c", state);
633 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
634 PS_ADD("pgrp", "%d", p->p_pgid);
635 PS_ADD("session", "%d", p->p_session->s_sid);
637 PS_ADD("tty", "%d", 0); /* XXX */
638 PS_ADD("tpgid", "%d", kp.ki_tpgid);
639 PS_ADD("flags", "%u", 0); /* XXX */
640 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
641 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
642 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
643 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
644 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime)));
645 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime)));
646 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
647 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
648 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
649 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
650 PS_ADD("0", "%d", 0); /* removed field */
651 PS_ADD("itrealvalue", "%d", 0); /* XXX */
652 /* XXX: starttime is not right, it is the _same_ for _every_ process.
653 It should be the number of jiffies between system boot and process
655 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start)));
656 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
657 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
658 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
659 PS_ADD("startcode", "%u", (unsigned)0);
660 PS_ADD("endcode", "%u", 0); /* XXX */
661 PS_ADD("startstack", "%u", 0); /* XXX */
662 PS_ADD("kstkesp", "%u", 0); /* XXX */
663 PS_ADD("kstkeip", "%u", 0); /* XXX */
664 PS_ADD("signal", "%u", 0); /* XXX */
665 PS_ADD("blocked", "%u", 0); /* XXX */
666 PS_ADD("sigignore", "%u", 0); /* XXX */
667 PS_ADD("sigcatch", "%u", 0); /* XXX */
668 PS_ADD("wchan", "%u", 0); /* XXX */
669 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
670 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
671 PS_ADD("exitsignal", "%d", 0); /* XXX */
672 PS_ADD("processor", "%u", kp.ki_lastcpu);
673 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
674 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
682 * Filler function for proc/pid/statm
685 linprocfs_doprocstatm(PFS_FILL_ARGS)
687 struct kinfo_proc kp;
691 fill_kinfo_proc(p, &kp);
695 * See comments in linprocfs_doprocstatus() regarding the
696 * computation of lsize.
698 /* size resident share trs drs lrs dt */
699 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
700 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
701 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
702 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
703 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
704 lsize = B2P(kp.ki_size) - kp.ki_dsize -
705 kp.ki_ssize - kp.ki_tsize - 1;
706 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
707 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
713 * Filler function for proc/pid/status
716 linprocfs_doprocstatus(PFS_FILL_ARGS)
718 struct kinfo_proc kp;
726 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
728 if (P_SHOULDSTOP(p)) {
729 state = "T (stopped)";
737 if (p->p_flag & P_WEXIT) {
738 state = "X (exiting)";
741 switch(td2->td_state) {
743 state = "S (sleeping)";
747 state = "R (running)";
750 state = "? (unknown)";
755 state = "Z (zombie)";
758 state = "? (unknown)";
764 fill_kinfo_proc(p, &kp);
765 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
766 sbuf_printf(sb, "State:\t%s\n", state);
771 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
772 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
773 p->p_pptr->p_pid : 0);
774 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
776 p->p_ucred->cr_svuid,
777 /* FreeBSD doesn't have fsuid */
779 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
781 p->p_ucred->cr_svgid,
782 /* FreeBSD doesn't have fsgid */
784 sbuf_cat(sb, "Groups:\t");
785 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
786 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
793 * While our approximation of VmLib may not be accurate (I
794 * don't know of a simple way to verify it, and I'm not sure
795 * it has much meaning anyway), I believe it's good enough.
797 * The same code that could (I think) accurately compute VmLib
798 * could also compute VmLck, but I don't really care enough to
799 * implement it. Submissions are welcome.
801 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
802 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
803 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
804 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
805 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
806 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
807 lsize = B2P(kp.ki_size) - kp.ki_dsize -
808 kp.ki_ssize - kp.ki_tsize - 1;
809 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
814 * We support up to 128 signals, while Linux supports 32,
815 * but we only define 32 (the same 32 as Linux, to boot), so
816 * just show the lower 32 bits of each mask. XXX hack.
818 * NB: on certain platforms (Sparc at least) Linux actually
819 * supports 64 signals, but this code is a long way from
820 * running on anything but i386, so ignore that for now.
823 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
825 * I can't seem to find out where the signal mask is in
826 * relation to struct proc, so SigBlk is left unimplemented.
828 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
830 mtx_lock(&ps->ps_mtx);
831 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
832 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
833 mtx_unlock(&ps->ps_mtx);
837 * Linux also prints the capability masks, but we don't have
838 * capabilities yet, and when we do get them they're likely to
839 * be meaningless to Linux programs, so we lie. XXX
841 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
842 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
843 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
850 * Filler function for proc/pid/cwd
853 linprocfs_doproccwd(PFS_FILL_ARGS)
855 char *fullpath = "unknown";
856 char *freepath = NULL;
858 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
859 sbuf_printf(sb, "%s", fullpath);
861 free(freepath, M_TEMP);
866 * Filler function for proc/pid/root
869 linprocfs_doprocroot(PFS_FILL_ARGS)
872 char *fullpath = "unknown";
873 char *freepath = NULL;
875 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
876 vn_fullpath(td, rvp, &fullpath, &freepath);
877 sbuf_printf(sb, "%s", fullpath);
879 free(freepath, M_TEMP);
884 * Filler function for proc/pid/cmdline
887 linprocfs_doproccmdline(PFS_FILL_ARGS)
889 struct ps_strings pstr;
894 * If we are using the ps/cmdline caching, use that. Otherwise
895 * revert back to the old way which only implements full cmdline
896 * for the currept process and just p->p_comm for all other
898 * Note that if the argv is no longer available, we deliberately
899 * don't fall back on p->p_comm or return an error: the authentic
900 * Linux behaviour is to return zero-length in this case.
904 if (p->p_args && p_cansee(td, p) == 0) {
905 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
907 } else if (p != td->td_proc) {
909 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
912 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
916 if (pstr.ps_nargvstr > ARG_MAX)
918 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
920 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
921 pstr.ps_nargvstr * sizeof(char *));
923 free(ps_argvstr, M_TEMP);
926 for (i = 0; i < pstr.ps_nargvstr; i++) {
927 sbuf_copyin(sb, ps_argvstr[i], 0);
928 sbuf_printf(sb, "%c", '\0');
930 free(ps_argvstr, M_TEMP);
937 * Filler function for proc/pid/environ
940 linprocfs_doprocenviron(PFS_FILL_ARGS)
943 sbuf_printf(sb, "doprocenviron\n%c", '\0');
948 * Filler function for proc/pid/maps
951 linprocfs_doprocmaps(PFS_FILL_ARGS)
955 vm_map_entry_t entry, tmp_entry;
956 vm_object_t obj, tobj, lobj;
957 vm_offset_t e_start, e_end;
958 vm_ooffset_t off = 0;
960 unsigned int last_timestamp;
961 char *name = "", *freename = NULL;
963 int ref_count, shadow_count, flags;
970 error = p_candebug(td, p);
975 if (uio->uio_rw != UIO_READ)
979 vm = vmspace_acquire_ref(p);
983 vm_map_lock_read(map);
984 for (entry = map->header.next; entry != &map->header;
985 entry = entry->next) {
988 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
990 e_prot = entry->protection;
991 e_start = entry->start;
993 obj = entry->object.vm_object;
994 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
995 VM_OBJECT_LOCK(tobj);
997 VM_OBJECT_UNLOCK(lobj);
1000 last_timestamp = map->timestamp;
1001 vm_map_unlock_read(map);
1004 off = IDX_TO_OFF(lobj->size);
1005 if (lobj->type == OBJT_VNODE) {
1013 VM_OBJECT_UNLOCK(lobj);
1015 ref_count = obj->ref_count;
1016 shadow_count = obj->shadow_count;
1017 VM_OBJECT_UNLOCK(obj);
1019 vn_fullpath(td, vp, &name, &freename);
1020 locked = VFS_LOCK_GIANT(vp->v_mount);
1021 vn_lock(vp, LK_SHARED | LK_RETRY);
1022 VOP_GETATTR(vp, &vat, td->td_ucred);
1023 ino = vat.va_fileid;
1025 VFS_UNLOCK_GIANT(locked);
1035 * start, end, access, offset, major, minor, inode, name.
1037 error = sbuf_printf(sb,
1038 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1039 (u_long)e_start, (u_long)e_end,
1040 (e_prot & VM_PROT_READ)?"r":"-",
1041 (e_prot & VM_PROT_WRITE)?"w":"-",
1042 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1052 free(freename, M_TEMP);
1053 vm_map_lock_read(map);
1058 if (last_timestamp != map->timestamp) {
1060 * Look again for the entry because the map was
1061 * modified while it was unlocked. Specifically,
1062 * the entry may have been clipped, merged, or deleted.
1064 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1068 vm_map_unlock_read(map);
1075 * Filler function for proc/net/dev
1078 linprocfs_donetdev(PFS_FILL_ARGS)
1080 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1083 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1084 "Inter-", " Receive", " Transmit", " face",
1085 "bytes packets errs drop fifo frame compressed",
1086 "bytes packets errs drop fifo frame compressed");
1089 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1090 linux_ifname(ifp, ifname, sizeof ifname);
1091 sbuf_printf(sb, "%6.6s:", ifname);
1092 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1093 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1094 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1095 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1103 * Filler function for proc/sys/kernel/osrelease
1106 linprocfs_doosrelease(PFS_FILL_ARGS)
1108 char osrelease[LINUX_MAX_UTSNAME];
1110 linux_get_osrelease(td, osrelease);
1111 sbuf_printf(sb, "%s\n", osrelease);
1117 * Filler function for proc/sys/kernel/ostype
1120 linprocfs_doostype(PFS_FILL_ARGS)
1122 char osname[LINUX_MAX_UTSNAME];
1124 linux_get_osname(td, osname);
1125 sbuf_printf(sb, "%s\n", osname);
1131 * Filler function for proc/sys/kernel/version
1134 linprocfs_doosbuild(PFS_FILL_ARGS)
1137 linprocfs_osbuild(td, sb);
1143 * Filler function for proc/sys/kernel/msgmni
1146 linprocfs_domsgmni(PFS_FILL_ARGS)
1149 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1154 * Filler function for proc/sys/kernel/pid_max
1157 linprocfs_dopid_max(PFS_FILL_ARGS)
1160 sbuf_printf(sb, "%i\n", PID_MAX);
1165 * Filler function for proc/sys/kernel/sem
1168 linprocfs_dosem(PFS_FILL_ARGS)
1171 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1172 seminfo.semopm, seminfo.semmni);
1177 * Filler function for proc/scsi/device_info
1180 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1187 * Filler function for proc/scsi/scsi
1190 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1196 extern struct cdevsw *cdevsw[];
1199 * Filler function for proc/devices
1202 linprocfs_dodevices(PFS_FILL_ARGS)
1205 sbuf_printf(sb, "Character devices:\n");
1207 char_devices = linux_get_char_devices();
1208 sbuf_printf(sb, "%s", char_devices);
1209 linux_free_get_char_devices(char_devices);
1211 sbuf_printf(sb, "\nBlock devices:\n");
1217 * Filler function for proc/cmdline
1220 linprocfs_docmdline(PFS_FILL_ARGS)
1223 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1224 sbuf_printf(sb, " ro root=302\n");
1230 * Filler function for proc/modules
1233 linprocfs_domodules(PFS_FILL_ARGS)
1235 struct linker_file *lf;
1237 TAILQ_FOREACH(lf, &linker_files, link) {
1238 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1239 (unsigned long)lf->size, lf->refs);
1249 linprocfs_init(PFS_INIT_ARGS)
1251 struct pfs_node *root;
1252 struct pfs_node *dir;
1257 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1258 NULL, NULL, NULL, PFS_RD);
1259 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1260 NULL, NULL, NULL, PFS_RD);
1261 pfs_create_file(root, "devices", &linprocfs_dodevices,
1262 NULL, NULL, NULL, PFS_RD);
1263 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1264 NULL, NULL, NULL, PFS_RD);
1265 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1266 NULL, NULL, NULL, PFS_RD);
1268 pfs_create_file(root, "modules", &linprocfs_domodules,
1269 NULL, NULL, NULL, PFS_RD);
1271 pfs_create_file(root, "mounts", &linprocfs_domtab,
1272 NULL, NULL, NULL, PFS_RD);
1273 pfs_create_file(root, "mtab", &linprocfs_domtab,
1274 NULL, NULL, NULL, PFS_RD);
1275 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1276 NULL, NULL, NULL, PFS_RD);
1277 pfs_create_link(root, "self", &procfs_docurproc,
1278 NULL, NULL, NULL, 0);
1279 pfs_create_file(root, "stat", &linprocfs_dostat,
1280 NULL, NULL, NULL, PFS_RD);
1281 pfs_create_file(root, "uptime", &linprocfs_douptime,
1282 NULL, NULL, NULL, PFS_RD);
1283 pfs_create_file(root, "version", &linprocfs_doversion,
1284 NULL, NULL, NULL, PFS_RD);
1287 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1288 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1289 NULL, NULL, NULL, PFS_RD);
1291 /* /proc/<pid>/... */
1292 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1293 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1294 NULL, NULL, NULL, PFS_RD);
1295 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1296 NULL, NULL, NULL, 0);
1297 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1298 NULL, NULL, NULL, PFS_RD);
1299 pfs_create_link(dir, "exe", &procfs_doprocfile,
1300 NULL, &procfs_notsystem, NULL, 0);
1301 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1302 NULL, NULL, NULL, PFS_RD);
1303 pfs_create_file(dir, "mem", &procfs_doprocmem,
1304 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1305 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1306 NULL, NULL, NULL, 0);
1307 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1308 NULL, NULL, NULL, PFS_RD);
1309 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1310 NULL, NULL, NULL, PFS_RD);
1311 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1312 NULL, NULL, NULL, PFS_RD);
1314 /* /proc/scsi/... */
1315 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1316 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1317 NULL, NULL, NULL, PFS_RD);
1318 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1319 NULL, NULL, NULL, PFS_RD);
1322 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1323 /* /proc/sys/kernel/... */
1324 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1325 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1326 NULL, NULL, NULL, PFS_RD);
1327 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1328 NULL, NULL, NULL, PFS_RD);
1329 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1330 NULL, NULL, NULL, PFS_RD);
1331 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1332 NULL, NULL, NULL, PFS_RD);
1333 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1334 NULL, NULL, NULL, PFS_RD);
1335 pfs_create_file(dir, "sem", &linprocfs_dosem,
1336 NULL, NULL, NULL, PFS_RD);
1345 linprocfs_uninit(PFS_INIT_ARGS)
1348 /* nothing to do, pseudofs will GC */
1352 PSEUDOFS(linprocfs, 1);
1353 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1354 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1355 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1356 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);