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) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
114 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
115 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
116 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
117 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
118 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
119 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
120 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
123 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
125 * The linux procfs state field displays one of the characters RSDZTW to
126 * denote running, sleeping in an interruptible wait, waiting in an
127 * uninterruptible disk sleep, a zombie process, process is being traced
128 * or stopped, or process is paging respectively.
130 * Our struct kinfo_proc contains the variable ki_stat which contains a
131 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
133 * This character array is used with ki_stati-1 as an index and tries to
134 * map our states to suitable linux states.
136 static char linux_state[] = "RRSTZDD";
139 * Filler function for proc/meminfo
142 linprocfs_domeminfo(PFS_FILL_ARGS)
144 unsigned long memtotal; /* total memory in bytes */
145 unsigned long memused; /* used memory in bytes */
146 unsigned long memfree; /* free memory in bytes */
147 unsigned long memshared; /* shared memory ??? */
148 unsigned long buffers, cached; /* buffer / cache memory ??? */
149 unsigned long long swaptotal; /* total swap space in bytes */
150 unsigned long long swapused; /* used swap space in bytes */
151 unsigned long long swapfree; /* free swap space in bytes */
155 memtotal = physmem * PAGE_SIZE;
157 * The correct thing here would be:
159 memfree = cnt.v_free_count * PAGE_SIZE;
160 memused = memtotal - memfree;
162 * but it might mislead linux binaries into thinking there
163 * is very little memory left, so we cheat and tell them that
164 * all memory that isn't wired down is free.
166 memused = cnt.v_wire_count * PAGE_SIZE;
167 memfree = memtotal - memused;
168 swap_pager_status(&i, &j);
169 swaptotal = (unsigned long long)i * PAGE_SIZE;
170 swapused = (unsigned long long)j * PAGE_SIZE;
171 swapfree = swaptotal - swapused;
173 mtx_lock(&vm_object_list_mtx);
174 TAILQ_FOREACH(object, &vm_object_list, object_list)
175 if (object->shadow_count > 1)
176 memshared += object->resident_page_count;
177 mtx_unlock(&vm_object_list_mtx);
178 memshared *= PAGE_SIZE;
180 * We'd love to be able to write:
184 * but bufspace is internal to vfs_bio.c and we don't feel
185 * like unstaticizing it just for linprocfs's sake.
188 cached = cnt.v_cache_count * PAGE_SIZE;
191 " total: used: free: shared: buffers: cached:\n"
192 "Mem: %lu %lu %lu %lu %lu %lu\n"
193 "Swap: %llu %llu %llu\n"
194 "MemTotal: %9lu kB\n"
196 "MemShared:%9lu kB\n"
199 "SwapTotal:%9llu kB\n"
200 "SwapFree: %9llu kB\n",
201 memtotal, memused, memfree, memshared, buffers, cached,
202 swaptotal, swapused, swapfree,
203 B2K(memtotal), B2K(memfree),
204 B2K(memshared), B2K(buffers), B2K(cached),
205 B2K(swaptotal), B2K(swapfree));
210 #if defined(__i386__) || defined(__amd64__)
212 * Filler function for proc/cpuinfo (i386 & amd64 version)
215 linprocfs_docpuinfo(PFS_FILL_ARGS)
220 int class, fqmhz, fqkhz;
224 * We default the flags to include all non-conflicting flags,
225 * and the Intel versions of conflicting flags.
227 static char *flags[] = {
228 "fpu", "vme", "de", "pse", "tsc",
229 "msr", "pae", "mce", "cx8", "apic",
230 "sep", "sep", "mtrr", "pge", "mca",
231 "cmov", "pat", "pse36", "pn", "b19",
232 "b20", "b21", "mmxext", "mmx", "fxsr",
233 "xmm", "sse2", "b27", "b28", "b29",
257 #else /* __amd64__ */
264 hw_model[0] = CTL_HW;
265 hw_model[1] = HW_MODEL;
267 size = sizeof(model);
268 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
269 strcpy(model, "unknown");
270 for (i = 0; i < mp_ncpus; ++i) {
273 "vendor_id\t: %.20s\n"
277 "stepping\t: %d\n\n",
278 i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
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]);
301 fqmhz = (tsc_freq + 4999) / 1000000;
302 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
304 "cpu MHz\t\t: %d.%02d\n"
305 "bogomips\t: %d.%02d\n",
306 fqmhz, fqkhz, fqmhz, fqkhz);
311 #endif /* __i386__ || __amd64__ */
314 * Filler function for proc/mtab
316 * This file doesn't exist in Linux' procfs, but is included here so
317 * users can symlink /compat/linux/etc/mtab to /proc/mtab
320 linprocfs_domtab(PFS_FILL_ARGS)
325 char *dlep, *flep, *mntto, *mntfrom, *fstype;
329 /* resolve symlinks etc. in the emulation tree prefix */
330 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
333 lep = linux_emul_path;
335 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
338 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
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);
392 * Filler function for proc/partitions
396 linprocfs_dopartitions(PFS_FILL_ARGS)
400 struct g_provider *pp;
408 /* resolve symlinks etc. in the emulation tree prefix */
409 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
412 lep = linux_emul_path;
414 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
417 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
419 lep_len = strlen(lep);
423 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
424 "ruse wio wmerge wsect wuse running use aveq\n");
426 LIST_FOREACH(cp, &g_classes, class) {
427 if (strcmp(cp->name, "DISK") == 0 ||
428 strcmp(cp->name, "PART") == 0)
429 LIST_FOREACH(gp, &cp->geom, geom) {
430 LIST_FOREACH(pp, &gp->provider, provider) {
431 if (linux_driver_get_major_minor(
432 pp->name, &major, &minor) != 0) {
436 sbuf_printf(sb, "%d %d %lld %s "
438 "%d %d %d %d %d %d\n",
440 (long long)pp->mediasize, pp->name,
455 * Filler function for proc/stat
458 linprocfs_dostat(PFS_FILL_ARGS)
461 long cp_time[CPUSTATES];
465 read_cpu_time(cp_time);
466 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
467 T2J(cp_time[CP_USER]),
468 T2J(cp_time[CP_NICE]),
469 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
470 T2J(cp_time[CP_IDLE]));
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.%02lu\n",
509 (long long)tv.tv_sec, tv.tv_usec / 10000,
510 T2S(cp_time[CP_IDLE] / mp_ncpus),
511 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
519 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
525 strncpy(osbuild, version, 256);
527 cp1 = strstr(osbuild, "\n");
528 cp2 = strstr(osbuild, ":");
531 cp1 = strstr(osbuild, "#");
535 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
538 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
545 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
551 cp = strstr(version, "\n ");
553 strncpy(builder, cp + 5, 256);
555 cp = strstr(builder, ":");
560 sbuf_cat(sb, builder);
563 sbuf_cat(sb, "des@freebsd.org");
567 * Filler function for proc/version
570 linprocfs_doversion(PFS_FILL_ARGS)
572 char osname[LINUX_MAX_UTSNAME];
573 char osrelease[LINUX_MAX_UTSNAME];
575 linux_get_osname(td, osname);
576 linux_get_osrelease(td, osrelease);
577 sbuf_printf(sb, "%s version %s (", osname, osrelease);
578 linprocfs_osbuilder(td, sb);
579 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
580 linprocfs_osbuild(td, sb);
587 * Filler function for proc/loadavg
590 linprocfs_doloadavg(PFS_FILL_ARGS)
594 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
595 (int)(averunnable.ldavg[0] / averunnable.fscale),
596 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
597 (int)(averunnable.ldavg[1] / averunnable.fscale),
598 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
599 (int)(averunnable.ldavg[2] / averunnable.fscale),
600 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
601 1, /* number of running tasks */
602 nprocs, /* number of tasks */
603 lastpid /* the last pid */
609 * Filler function for proc/pid/stat
612 linprocfs_doprocstat(PFS_FILL_ARGS)
614 struct kinfo_proc kp;
616 static int ratelimit = 0;
617 vm_offset_t startcode, startdata;
620 fill_kinfo_proc(p, &kp);
622 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
623 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
628 sbuf_printf(sb, "%d", p->p_pid);
629 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
630 PS_ADD("comm", "(%s)", p->p_comm);
631 if (kp.ki_stat > sizeof(linux_state)) {
634 if (ratelimit == 0) {
635 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
636 kp.ki_stat, sizeof(linux_state));
640 state = linux_state[kp.ki_stat - 1];
641 PS_ADD("state", "%c", state);
642 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
643 PS_ADD("pgrp", "%d", p->p_pgid);
644 PS_ADD("session", "%d", p->p_session->s_sid);
646 PS_ADD("tty", "%d", kp.ki_tdev);
647 PS_ADD("tpgid", "%d", kp.ki_tpgid);
648 PS_ADD("flags", "%u", 0); /* XXX */
649 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
650 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
651 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
652 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
653 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
654 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
655 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
656 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
657 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
658 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
659 PS_ADD("0", "%d", 0); /* removed field */
660 PS_ADD("itrealvalue", "%d", 0); /* XXX */
661 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
662 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
663 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
664 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
665 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
666 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
667 PS_ADD("startstack", "%u", 0); /* XXX */
668 PS_ADD("kstkesp", "%u", 0); /* XXX */
669 PS_ADD("kstkeip", "%u", 0); /* XXX */
670 PS_ADD("signal", "%u", 0); /* XXX */
671 PS_ADD("blocked", "%u", 0); /* XXX */
672 PS_ADD("sigignore", "%u", 0); /* XXX */
673 PS_ADD("sigcatch", "%u", 0); /* XXX */
674 PS_ADD("wchan", "%u", 0); /* XXX */
675 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
676 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
677 PS_ADD("exitsignal", "%d", 0); /* XXX */
678 PS_ADD("processor", "%u", kp.ki_lastcpu);
679 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
680 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
688 * Filler function for proc/pid/statm
691 linprocfs_doprocstatm(PFS_FILL_ARGS)
693 struct kinfo_proc kp;
697 fill_kinfo_proc(p, &kp);
701 * See comments in linprocfs_doprocstatus() regarding the
702 * computation of lsize.
704 /* size resident share trs drs lrs dt */
705 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
706 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
707 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
708 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
709 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
710 lsize = B2P(kp.ki_size) - kp.ki_dsize -
711 kp.ki_ssize - kp.ki_tsize - 1;
712 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
713 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
719 * Filler function for proc/pid/status
722 linprocfs_doprocstatus(PFS_FILL_ARGS)
724 struct kinfo_proc kp;
732 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
734 if (P_SHOULDSTOP(p)) {
735 state = "T (stopped)";
743 if (p->p_flag & P_WEXIT) {
744 state = "X (exiting)";
747 switch(td2->td_state) {
749 state = "S (sleeping)";
753 state = "R (running)";
756 state = "? (unknown)";
761 state = "Z (zombie)";
764 state = "? (unknown)";
770 fill_kinfo_proc(p, &kp);
771 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
772 sbuf_printf(sb, "State:\t%s\n", state);
777 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
778 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
779 p->p_pptr->p_pid : 0);
780 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
782 p->p_ucred->cr_svuid,
783 /* FreeBSD doesn't have fsuid */
785 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
787 p->p_ucred->cr_svgid,
788 /* FreeBSD doesn't have fsgid */
790 sbuf_cat(sb, "Groups:\t");
791 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
792 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
799 * While our approximation of VmLib may not be accurate (I
800 * don't know of a simple way to verify it, and I'm not sure
801 * it has much meaning anyway), I believe it's good enough.
803 * The same code that could (I think) accurately compute VmLib
804 * could also compute VmLck, but I don't really care enough to
805 * implement it. Submissions are welcome.
807 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
808 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
809 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
810 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
811 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
812 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
813 lsize = B2P(kp.ki_size) - kp.ki_dsize -
814 kp.ki_ssize - kp.ki_tsize - 1;
815 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
820 * We support up to 128 signals, while Linux supports 32,
821 * but we only define 32 (the same 32 as Linux, to boot), so
822 * just show the lower 32 bits of each mask. XXX hack.
824 * NB: on certain platforms (Sparc at least) Linux actually
825 * supports 64 signals, but this code is a long way from
826 * running on anything but i386, so ignore that for now.
829 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
831 * I can't seem to find out where the signal mask is in
832 * relation to struct proc, so SigBlk is left unimplemented.
834 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
836 mtx_lock(&ps->ps_mtx);
837 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
838 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
839 mtx_unlock(&ps->ps_mtx);
843 * Linux also prints the capability masks, but we don't have
844 * capabilities yet, and when we do get them they're likely to
845 * be meaningless to Linux programs, so we lie. XXX
847 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
848 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
849 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
856 * Filler function for proc/pid/cwd
859 linprocfs_doproccwd(PFS_FILL_ARGS)
861 char *fullpath = "unknown";
862 char *freepath = NULL;
864 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
865 sbuf_printf(sb, "%s", fullpath);
867 free(freepath, M_TEMP);
872 * Filler function for proc/pid/root
875 linprocfs_doprocroot(PFS_FILL_ARGS)
878 char *fullpath = "unknown";
879 char *freepath = NULL;
881 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
882 vn_fullpath(td, rvp, &fullpath, &freepath);
883 sbuf_printf(sb, "%s", fullpath);
885 free(freepath, M_TEMP);
890 * Filler function for proc/pid/cmdline
893 linprocfs_doproccmdline(PFS_FILL_ARGS)
895 struct ps_strings pstr;
900 * If we are using the ps/cmdline caching, use that. Otherwise
901 * revert back to the old way which only implements full cmdline
902 * for the currept process and just p->p_comm for all other
904 * Note that if the argv is no longer available, we deliberately
905 * don't fall back on p->p_comm or return an error: the authentic
906 * Linux behaviour is to return zero-length in this case.
910 if (p->p_args && p_cansee(td, p) == 0) {
911 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
913 } else if (p != td->td_proc) {
915 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
918 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
922 if (pstr.ps_nargvstr > ARG_MAX)
924 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
926 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
927 pstr.ps_nargvstr * sizeof(char *));
929 free(ps_argvstr, M_TEMP);
932 for (i = 0; i < pstr.ps_nargvstr; i++) {
933 sbuf_copyin(sb, ps_argvstr[i], 0);
934 sbuf_printf(sb, "%c", '\0');
936 free(ps_argvstr, M_TEMP);
943 * Filler function for proc/pid/environ
946 linprocfs_doprocenviron(PFS_FILL_ARGS)
949 sbuf_printf(sb, "doprocenviron\n%c", '\0');
954 * Filler function for proc/pid/maps
957 linprocfs_doprocmaps(PFS_FILL_ARGS)
961 vm_map_entry_t entry, tmp_entry;
962 vm_object_t obj, tobj, lobj;
963 vm_offset_t e_start, e_end;
964 vm_ooffset_t off = 0;
966 unsigned int last_timestamp;
967 char *name = "", *freename = NULL;
969 int ref_count, shadow_count, flags;
976 error = p_candebug(td, p);
981 if (uio->uio_rw != UIO_READ)
985 vm = vmspace_acquire_ref(p);
989 vm_map_lock_read(map);
990 for (entry = map->header.next; entry != &map->header;
991 entry = entry->next) {
994 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
996 e_prot = entry->protection;
997 e_start = entry->start;
999 obj = entry->object.vm_object;
1000 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1001 VM_OBJECT_LOCK(tobj);
1003 VM_OBJECT_UNLOCK(lobj);
1006 last_timestamp = map->timestamp;
1007 vm_map_unlock_read(map);
1010 off = IDX_TO_OFF(lobj->size);
1011 if (lobj->type == OBJT_VNODE) {
1019 VM_OBJECT_UNLOCK(lobj);
1021 ref_count = obj->ref_count;
1022 shadow_count = obj->shadow_count;
1023 VM_OBJECT_UNLOCK(obj);
1025 vn_fullpath(td, vp, &name, &freename);
1026 locked = VFS_LOCK_GIANT(vp->v_mount);
1027 vn_lock(vp, LK_SHARED | LK_RETRY);
1028 VOP_GETATTR(vp, &vat, td->td_ucred);
1029 ino = vat.va_fileid;
1031 VFS_UNLOCK_GIANT(locked);
1041 * start, end, access, offset, major, minor, inode, name.
1043 error = sbuf_printf(sb,
1044 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1045 (u_long)e_start, (u_long)e_end,
1046 (e_prot & VM_PROT_READ)?"r":"-",
1047 (e_prot & VM_PROT_WRITE)?"w":"-",
1048 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1058 free(freename, M_TEMP);
1059 vm_map_lock_read(map);
1064 if (last_timestamp != map->timestamp) {
1066 * Look again for the entry because the map was
1067 * modified while it was unlocked. Specifically,
1068 * the entry may have been clipped, merged, or deleted.
1070 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1074 vm_map_unlock_read(map);
1081 * Filler function for proc/net/dev
1084 linprocfs_donetdev(PFS_FILL_ARGS)
1086 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1089 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
1090 "Inter-", " Receive", " Transmit", " face",
1091 "bytes packets errs drop fifo frame compressed",
1092 "bytes packets errs drop fifo frame compressed");
1094 CURVNET_SET(TD_TO_VNET(curthread));
1096 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1097 linux_ifname(ifp, ifname, sizeof ifname);
1098 sbuf_printf(sb, "%6.6s:", ifname);
1099 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1100 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1101 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1102 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
1111 * Filler function for proc/sys/kernel/osrelease
1114 linprocfs_doosrelease(PFS_FILL_ARGS)
1116 char osrelease[LINUX_MAX_UTSNAME];
1118 linux_get_osrelease(td, osrelease);
1119 sbuf_printf(sb, "%s\n", osrelease);
1125 * Filler function for proc/sys/kernel/ostype
1128 linprocfs_doostype(PFS_FILL_ARGS)
1130 char osname[LINUX_MAX_UTSNAME];
1132 linux_get_osname(td, osname);
1133 sbuf_printf(sb, "%s\n", osname);
1139 * Filler function for proc/sys/kernel/version
1142 linprocfs_doosbuild(PFS_FILL_ARGS)
1145 linprocfs_osbuild(td, sb);
1151 * Filler function for proc/sys/kernel/msgmni
1154 linprocfs_domsgmni(PFS_FILL_ARGS)
1157 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1162 * Filler function for proc/sys/kernel/pid_max
1165 linprocfs_dopid_max(PFS_FILL_ARGS)
1168 sbuf_printf(sb, "%i\n", PID_MAX);
1173 * Filler function for proc/sys/kernel/sem
1176 linprocfs_dosem(PFS_FILL_ARGS)
1179 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1180 seminfo.semopm, seminfo.semmni);
1185 * Filler function for proc/scsi/device_info
1188 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1195 * Filler function for proc/scsi/scsi
1198 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1204 extern struct cdevsw *cdevsw[];
1207 * Filler function for proc/devices
1210 linprocfs_dodevices(PFS_FILL_ARGS)
1213 sbuf_printf(sb, "Character devices:\n");
1215 char_devices = linux_get_char_devices();
1216 sbuf_printf(sb, "%s", char_devices);
1217 linux_free_get_char_devices(char_devices);
1219 sbuf_printf(sb, "\nBlock devices:\n");
1225 * Filler function for proc/cmdline
1228 linprocfs_docmdline(PFS_FILL_ARGS)
1231 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1232 sbuf_printf(sb, " ro root=302\n");
1237 * Filler function for proc/filesystems
1240 linprocfs_dofilesystems(PFS_FILL_ARGS)
1242 struct vfsconf *vfsp;
1245 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1246 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1247 sbuf_printf(sb, "nodev");
1248 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1256 * Filler function for proc/modules
1259 linprocfs_domodules(PFS_FILL_ARGS)
1261 struct linker_file *lf;
1263 TAILQ_FOREACH(lf, &linker_files, link) {
1264 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1265 (unsigned long)lf->size, lf->refs);
1272 * Filler function for proc/pid/fd
1275 linprocfs_dofdescfs(PFS_FILL_ARGS)
1279 sbuf_printf(sb, "/dev/fd");
1281 sbuf_printf(sb, "unknown");
1289 linprocfs_init(PFS_INIT_ARGS)
1291 struct pfs_node *root;
1292 struct pfs_node *dir;
1297 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1298 NULL, NULL, NULL, PFS_RD);
1299 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1300 NULL, NULL, NULL, PFS_RD);
1301 pfs_create_file(root, "devices", &linprocfs_dodevices,
1302 NULL, NULL, NULL, PFS_RD);
1303 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1304 NULL, NULL, NULL, PFS_RD);
1305 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1306 NULL, NULL, NULL, PFS_RD);
1307 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1308 NULL, NULL, NULL, PFS_RD);
1310 pfs_create_file(root, "modules", &linprocfs_domodules,
1311 NULL, NULL, NULL, PFS_RD);
1313 pfs_create_file(root, "mounts", &linprocfs_domtab,
1314 NULL, NULL, NULL, PFS_RD);
1315 pfs_create_file(root, "mtab", &linprocfs_domtab,
1316 NULL, NULL, NULL, PFS_RD);
1317 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1318 NULL, NULL, NULL, PFS_RD);
1319 pfs_create_link(root, "self", &procfs_docurproc,
1320 NULL, NULL, NULL, 0);
1321 pfs_create_file(root, "stat", &linprocfs_dostat,
1322 NULL, NULL, NULL, PFS_RD);
1323 pfs_create_file(root, "uptime", &linprocfs_douptime,
1324 NULL, NULL, NULL, PFS_RD);
1325 pfs_create_file(root, "version", &linprocfs_doversion,
1326 NULL, NULL, NULL, PFS_RD);
1329 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1330 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1331 NULL, NULL, NULL, PFS_RD);
1333 /* /proc/<pid>/... */
1334 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1335 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1336 NULL, NULL, NULL, PFS_RD);
1337 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1338 NULL, NULL, NULL, 0);
1339 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1340 NULL, NULL, NULL, PFS_RD);
1341 pfs_create_link(dir, "exe", &procfs_doprocfile,
1342 NULL, &procfs_notsystem, NULL, 0);
1343 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1344 NULL, NULL, NULL, PFS_RD);
1345 pfs_create_file(dir, "mem", &procfs_doprocmem,
1346 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1347 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1348 NULL, NULL, NULL, 0);
1349 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1350 NULL, NULL, NULL, PFS_RD);
1351 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1352 NULL, NULL, NULL, PFS_RD);
1353 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1354 NULL, NULL, NULL, PFS_RD);
1355 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1356 NULL, NULL, NULL, 0);
1358 /* /proc/scsi/... */
1359 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1360 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1361 NULL, NULL, NULL, PFS_RD);
1362 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1363 NULL, NULL, NULL, PFS_RD);
1366 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1367 /* /proc/sys/kernel/... */
1368 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1369 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1370 NULL, NULL, NULL, PFS_RD);
1371 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1372 NULL, NULL, NULL, PFS_RD);
1373 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1374 NULL, NULL, NULL, PFS_RD);
1375 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1376 NULL, NULL, NULL, PFS_RD);
1377 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1378 NULL, NULL, NULL, PFS_RD);
1379 pfs_create_file(dir, "sem", &linprocfs_dosem,
1380 NULL, NULL, NULL, PFS_RD);
1389 linprocfs_uninit(PFS_INIT_ARGS)
1392 /* nothing to do, pseudofs will GC */
1396 PSEUDOFS(linprocfs, 1);
1397 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1398 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1399 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1400 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);