2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
42 #include "opt_compat.h"
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
47 #include <sys/param.h>
48 #include <sys/queue.h>
49 #include <sys/blist.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
55 #include <sys/kernel.h>
56 #include <sys/linker.h>
58 #include <sys/malloc.h>
59 #include <sys/mount.h>
61 #include <sys/mutex.h>
62 #include <sys/namei.h>
64 #include <sys/ptrace.h>
65 #include <sys/resourcevar.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
71 #include <sys/systm.h>
75 #include <sys/vmmeter.h>
76 #include <sys/vnode.h>
83 #include <vm/vm_extern.h>
85 #include <vm/vm_map.h>
86 #include <vm/vm_param.h>
87 #include <vm/vm_object.h>
88 #include <vm/swap_pager.h>
90 #include <machine/clock.h>
92 #include <geom/geom.h>
93 #include <geom/geom_int.h>
95 #if defined(__i386__) || defined(__amd64__)
96 #include <machine/cputypes.h>
97 #include <machine/md_var.h>
98 #endif /* __i386__ || __amd64__ */
100 #ifdef COMPAT_FREEBSD32
101 #include <compat/freebsd32/freebsd32_util.h>
104 #ifdef COMPAT_LINUX32 /* XXX */
105 #include <machine/../linux32/linux.h>
107 #include <machine/../linux/linux.h>
109 #include <compat/linux/linux_ioctl.h>
110 #include <compat/linux/linux_mib.h>
111 #include <compat/linux/linux_util.h>
112 #include <fs/pseudofs/pseudofs.h>
113 #include <fs/procfs/procfs.h>
116 * Various conversion macros
118 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */
119 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */
120 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
121 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
122 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
123 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
124 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
125 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
128 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
130 * The linux procfs state field displays one of the characters RSDZTW to
131 * denote running, sleeping in an interruptible wait, waiting in an
132 * uninterruptible disk sleep, a zombie process, process is being traced
133 * or stopped, or process is paging respectively.
135 * Our struct kinfo_proc contains the variable ki_stat which contains a
136 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
138 * This character array is used with ki_stati-1 as an index and tries to
139 * map our states to suitable linux states.
141 static char linux_state[] = "RRSTZDD";
144 * Filler function for proc/meminfo
147 linprocfs_domeminfo(PFS_FILL_ARGS)
149 unsigned long memtotal; /* total memory in bytes */
150 unsigned long memused; /* used memory in bytes */
151 unsigned long memfree; /* free memory in bytes */
152 unsigned long memshared; /* shared memory ??? */
153 unsigned long buffers, cached; /* buffer / cache memory ??? */
154 unsigned long long swaptotal; /* total swap space in bytes */
155 unsigned long long swapused; /* used swap space in bytes */
156 unsigned long long swapfree; /* free swap space in bytes */
160 memtotal = physmem * PAGE_SIZE;
162 * The correct thing here would be:
164 memfree = cnt.v_free_count * PAGE_SIZE;
165 memused = memtotal - memfree;
167 * but it might mislead linux binaries into thinking there
168 * is very little memory left, so we cheat and tell them that
169 * all memory that isn't wired down is free.
171 memused = cnt.v_wire_count * PAGE_SIZE;
172 memfree = memtotal - memused;
173 swap_pager_status(&i, &j);
174 swaptotal = (unsigned long long)i * PAGE_SIZE;
175 swapused = (unsigned long long)j * PAGE_SIZE;
176 swapfree = swaptotal - swapused;
178 mtx_lock(&vm_object_list_mtx);
179 TAILQ_FOREACH(object, &vm_object_list, object_list)
180 if (object->shadow_count > 1)
181 memshared += object->resident_page_count;
182 mtx_unlock(&vm_object_list_mtx);
183 memshared *= PAGE_SIZE;
185 * We'd love to be able to write:
189 * but bufspace is internal to vfs_bio.c and we don't feel
190 * like unstaticizing it just for linprocfs's sake.
193 cached = cnt.v_cache_count * PAGE_SIZE;
196 " total: used: free: shared: buffers: cached:\n"
197 "Mem: %lu %lu %lu %lu %lu %lu\n"
198 "Swap: %llu %llu %llu\n"
199 "MemTotal: %9lu kB\n"
201 "MemShared:%9lu kB\n"
204 "SwapTotal:%9llu kB\n"
205 "SwapFree: %9llu kB\n",
206 memtotal, memused, memfree, memshared, buffers, cached,
207 swaptotal, swapused, swapfree,
208 B2K(memtotal), B2K(memfree),
209 B2K(memshared), B2K(buffers), B2K(cached),
210 B2K(swaptotal), B2K(swapfree));
215 #if defined(__i386__) || defined(__amd64__)
217 * Filler function for proc/cpuinfo (i386 & amd64 version)
220 linprocfs_docpuinfo(PFS_FILL_ARGS)
225 int class, fqmhz, fqkhz;
229 * We default the flags to include all non-conflicting flags,
230 * and the Intel versions of conflicting flags.
232 static char *flags[] = {
233 "fpu", "vme", "de", "pse", "tsc",
234 "msr", "pae", "mce", "cx8", "apic",
235 "sep", "sep", "mtrr", "pge", "mca",
236 "cmov", "pat", "pse36", "pn", "b19",
237 "b20", "b21", "mmxext", "mmx", "fxsr",
238 "xmm", "sse2", "b27", "b28", "b29",
262 #else /* __amd64__ */
269 hw_model[0] = CTL_HW;
270 hw_model[1] = HW_MODEL;
272 size = sizeof(model);
273 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
274 strcpy(model, "unknown");
275 for (i = 0; i < mp_ncpus; ++i) {
278 "vendor_id\t: %.20s\n"
282 "stepping\t: %u\n\n",
283 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
284 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
285 /* XXX per-cpu vendor / class / model / id? */
288 sbuf_cat(sb, "flags\t\t:");
291 switch (cpu_vendor_id) {
296 case CPU_VENDOR_CYRIX:
302 for (i = 0; i < 32; i++)
303 if (cpu_feature & (1 << i))
304 sbuf_printf(sb, " %s", flags[i]);
307 fqmhz = (tsc_freq + 4999) / 1000000;
308 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
310 "cpu MHz\t\t: %d.%02d\n"
311 "bogomips\t: %d.%02d\n",
312 fqmhz, fqkhz, fqmhz, fqkhz);
317 #endif /* __i386__ || __amd64__ */
320 * Filler function for proc/mtab
322 * This file doesn't exist in Linux' procfs, but is included here so
323 * users can symlink /compat/linux/etc/mtab to /proc/mtab
326 linprocfs_domtab(PFS_FILL_ARGS)
331 char *dlep, *flep, *mntto, *mntfrom, *fstype;
335 /* resolve symlinks etc. in the emulation tree prefix */
336 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
339 lep = linux_emul_path;
341 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
344 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
346 lep_len = strlen(lep);
348 mtx_lock(&mountlist_mtx);
350 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
351 /* determine device name */
352 mntfrom = mp->mnt_stat.f_mntfromname;
354 /* determine mount point */
355 mntto = mp->mnt_stat.f_mntonname;
356 if (strncmp(mntto, lep, lep_len) == 0 &&
357 mntto[lep_len] == '/')
360 /* determine fs type */
361 fstype = mp->mnt_stat.f_fstypename;
362 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
363 mntfrom = fstype = "proc";
364 else if (strcmp(fstype, "procfs") == 0)
367 if (strcmp(fstype, "linsysfs") == 0) {
368 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
369 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
371 /* For Linux msdosfs is called vfat */
372 if (strcmp(fstype, "msdosfs") == 0)
374 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
375 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
377 #define ADD_OPTION(opt, name) \
378 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
379 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
380 ADD_OPTION(MNT_NOEXEC, "noexec");
381 ADD_OPTION(MNT_NOSUID, "nosuid");
382 ADD_OPTION(MNT_UNION, "union");
383 ADD_OPTION(MNT_ASYNC, "async");
384 ADD_OPTION(MNT_SUIDDIR, "suiddir");
385 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
386 ADD_OPTION(MNT_NOATIME, "noatime");
388 /* a real Linux mtab will also show NFS options */
389 sbuf_printf(sb, " 0 0\n");
391 mtx_unlock(&mountlist_mtx);
398 * Filler function for proc/partitions
402 linprocfs_dopartitions(PFS_FILL_ARGS)
406 struct g_provider *pp;
414 /* resolve symlinks etc. in the emulation tree prefix */
415 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
418 lep = linux_emul_path;
420 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
423 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
425 lep_len = strlen(lep);
429 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect "
430 "ruse wio wmerge wsect wuse running use aveq\n");
432 LIST_FOREACH(cp, &g_classes, class) {
433 if (strcmp(cp->name, "DISK") == 0 ||
434 strcmp(cp->name, "PART") == 0)
435 LIST_FOREACH(gp, &cp->geom, geom) {
436 LIST_FOREACH(pp, &gp->provider, provider) {
437 if (linux_driver_get_major_minor(
438 pp->name, &major, &minor) != 0) {
442 sbuf_printf(sb, "%d %d %lld %s "
444 "%d %d %d %d %d %d\n",
446 (long long)pp->mediasize, pp->name,
461 * Filler function for proc/stat
464 linprocfs_dostat(PFS_FILL_ARGS)
467 long cp_time[CPUSTATES];
471 read_cpu_time(cp_time);
472 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
473 T2J(cp_time[CP_USER]),
474 T2J(cp_time[CP_NICE]),
475 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
476 T2J(cp_time[CP_IDLE]));
479 cp = pcpu->pc_cp_time;
480 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
483 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
499 (long long)boottime.tv_sec);
504 linprocfs_doswaps(PFS_FILL_ARGS)
507 uintmax_t total, used;
509 char devname[SPECNAMELEN + 1];
511 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
514 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
516 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
517 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
520 * The space and not tab after the device name is on
521 * purpose. Linux does so.
523 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
524 devname, total, used);
531 * Filler function for proc/uptime
534 linprocfs_douptime(PFS_FILL_ARGS)
536 long cp_time[CPUSTATES];
540 read_cpu_time(cp_time);
541 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
542 (long long)tv.tv_sec, tv.tv_usec / 10000,
543 T2S(cp_time[CP_IDLE] / mp_ncpus),
544 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
552 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
558 strncpy(osbuild, version, 256);
560 cp1 = strstr(osbuild, "\n");
561 cp2 = strstr(osbuild, ":");
564 cp1 = strstr(osbuild, "#");
568 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
571 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
578 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
584 cp = strstr(version, "\n ");
586 strncpy(builder, cp + 5, 256);
588 cp = strstr(builder, ":");
593 sbuf_cat(sb, builder);
596 sbuf_cat(sb, "des@freebsd.org");
600 * Filler function for proc/version
603 linprocfs_doversion(PFS_FILL_ARGS)
605 char osname[LINUX_MAX_UTSNAME];
606 char osrelease[LINUX_MAX_UTSNAME];
608 linux_get_osname(td, osname);
609 linux_get_osrelease(td, osrelease);
610 sbuf_printf(sb, "%s version %s (", osname, osrelease);
611 linprocfs_osbuilder(td, sb);
612 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
613 linprocfs_osbuild(td, sb);
620 * Filler function for proc/loadavg
623 linprocfs_doloadavg(PFS_FILL_ARGS)
627 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
628 (int)(averunnable.ldavg[0] / averunnable.fscale),
629 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
630 (int)(averunnable.ldavg[1] / averunnable.fscale),
631 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
632 (int)(averunnable.ldavg[2] / averunnable.fscale),
633 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
634 1, /* number of running tasks */
635 nprocs, /* number of tasks */
636 lastpid /* the last pid */
642 * Filler function for proc/pid/stat
645 linprocfs_doprocstat(PFS_FILL_ARGS)
647 struct kinfo_proc kp;
649 static int ratelimit = 0;
650 vm_offset_t startcode, startdata;
653 fill_kinfo_proc(p, &kp);
655 startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
656 startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
661 sbuf_printf(sb, "%d", p->p_pid);
662 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
663 PS_ADD("comm", "(%s)", p->p_comm);
664 if (kp.ki_stat > sizeof(linux_state)) {
667 if (ratelimit == 0) {
668 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
669 kp.ki_stat, sizeof(linux_state));
673 state = linux_state[kp.ki_stat - 1];
674 PS_ADD("state", "%c", state);
675 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
676 PS_ADD("pgrp", "%d", p->p_pgid);
677 PS_ADD("session", "%d", p->p_session->s_sid);
679 PS_ADD("tty", "%d", kp.ki_tdev);
680 PS_ADD("tpgid", "%d", kp.ki_tpgid);
681 PS_ADD("flags", "%u", 0); /* XXX */
682 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
683 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
684 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
685 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
686 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
687 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
688 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
689 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
690 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
691 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
692 PS_ADD("0", "%d", 0); /* removed field */
693 PS_ADD("itrealvalue", "%d", 0); /* XXX */
694 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
695 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
696 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
697 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
698 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
699 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
700 PS_ADD("startstack", "%u", 0); /* XXX */
701 PS_ADD("kstkesp", "%u", 0); /* XXX */
702 PS_ADD("kstkeip", "%u", 0); /* XXX */
703 PS_ADD("signal", "%u", 0); /* XXX */
704 PS_ADD("blocked", "%u", 0); /* XXX */
705 PS_ADD("sigignore", "%u", 0); /* XXX */
706 PS_ADD("sigcatch", "%u", 0); /* XXX */
707 PS_ADD("wchan", "%u", 0); /* XXX */
708 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
709 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
710 PS_ADD("exitsignal", "%d", 0); /* XXX */
711 PS_ADD("processor", "%u", kp.ki_lastcpu);
712 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
713 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
721 * Filler function for proc/pid/statm
724 linprocfs_doprocstatm(PFS_FILL_ARGS)
726 struct kinfo_proc kp;
730 fill_kinfo_proc(p, &kp);
734 * See comments in linprocfs_doprocstatus() regarding the
735 * computation of lsize.
737 /* size resident share trs drs lrs dt */
738 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
739 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
740 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
741 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
742 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
743 lsize = B2P(kp.ki_size) - kp.ki_dsize -
744 kp.ki_ssize - kp.ki_tsize - 1;
745 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
746 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
752 * Filler function for proc/pid/status
755 linprocfs_doprocstatus(PFS_FILL_ARGS)
757 struct kinfo_proc kp;
765 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
767 if (P_SHOULDSTOP(p)) {
768 state = "T (stopped)";
775 if (p->p_flag & P_WEXIT) {
776 state = "X (exiting)";
779 switch(td2->td_state) {
781 state = "S (sleeping)";
785 state = "R (running)";
788 state = "? (unknown)";
793 state = "Z (zombie)";
796 state = "? (unknown)";
801 fill_kinfo_proc(p, &kp);
802 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
803 sbuf_printf(sb, "State:\t%s\n", state);
808 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
809 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
810 p->p_pptr->p_pid : 0);
811 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
813 p->p_ucred->cr_svuid,
814 /* FreeBSD doesn't have fsuid */
816 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
818 p->p_ucred->cr_svgid,
819 /* FreeBSD doesn't have fsgid */
821 sbuf_cat(sb, "Groups:\t");
822 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
823 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
830 * While our approximation of VmLib may not be accurate (I
831 * don't know of a simple way to verify it, and I'm not sure
832 * it has much meaning anyway), I believe it's good enough.
834 * The same code that could (I think) accurately compute VmLib
835 * could also compute VmLck, but I don't really care enough to
836 * implement it. Submissions are welcome.
838 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
839 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
840 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
841 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
842 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
843 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
844 lsize = B2P(kp.ki_size) - kp.ki_dsize -
845 kp.ki_ssize - kp.ki_tsize - 1;
846 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
851 * We support up to 128 signals, while Linux supports 32,
852 * but we only define 32 (the same 32 as Linux, to boot), so
853 * just show the lower 32 bits of each mask. XXX hack.
855 * NB: on certain platforms (Sparc at least) Linux actually
856 * supports 64 signals, but this code is a long way from
857 * running on anything but i386, so ignore that for now.
860 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
862 * I can't seem to find out where the signal mask is in
863 * relation to struct proc, so SigBlk is left unimplemented.
865 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
867 mtx_lock(&ps->ps_mtx);
868 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
869 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
870 mtx_unlock(&ps->ps_mtx);
874 * Linux also prints the capability masks, but we don't have
875 * capabilities yet, and when we do get them they're likely to
876 * be meaningless to Linux programs, so we lie. XXX
878 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
879 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
880 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
887 * Filler function for proc/pid/cwd
890 linprocfs_doproccwd(PFS_FILL_ARGS)
892 char *fullpath = "unknown";
893 char *freepath = NULL;
895 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
896 sbuf_printf(sb, "%s", fullpath);
898 free(freepath, M_TEMP);
903 * Filler function for proc/pid/root
906 linprocfs_doprocroot(PFS_FILL_ARGS)
909 char *fullpath = "unknown";
910 char *freepath = NULL;
912 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
913 vn_fullpath(td, rvp, &fullpath, &freepath);
914 sbuf_printf(sb, "%s", fullpath);
916 free(freepath, M_TEMP);
920 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */
921 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */
924 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
925 void (*resolver)(const struct ps_strings, u_long *, int *))
929 struct ps_strings pss;
930 int ret, i, n_elements, elm_len;
932 char **env_vector, *envp;
933 char env_string[UIO_CHUNK_SZ];
934 #ifdef COMPAT_FREEBSD32
935 struct freebsd32_ps_strings pss32;
936 uint32_t *env_vector32;
939 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \
941 iov.iov_base = (caddr_t)(base); \
942 iov.iov_len = (len); \
943 uio.uio_iov = &(iov); \
944 uio.uio_iovcnt = (cnt); \
945 uio.uio_offset = (off_t)(offset); \
946 uio.uio_resid = (sz); \
947 uio.uio_segflg = (flg); \
952 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
954 #ifdef COMPAT_FREEBSD32
956 if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
957 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
959 elm_len = sizeof(int32_t);
960 envp = (char *)env_vector32;
962 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
963 (off_t)(p->p_sysent->sv_psstrings),
964 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
965 ret = proc_rwmem(p, &tmp_uio);
968 pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
969 pss.ps_nargvstr = pss32.ps_nargvstr;
970 pss.ps_envstr = PTRIN(pss32.ps_envstr);
971 pss.ps_nenvstr = pss32.ps_nenvstr;
974 elm_len = sizeof(char *);
975 envp = (char *)env_vector;
977 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
978 (off_t)(p->p_sysent->sv_psstrings),
979 sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
980 ret = proc_rwmem(p, &tmp_uio);
983 #ifdef COMPAT_FREEBSD32
987 /* Get the array address and the number of elements */
988 resolver(pss, &addr, &n_elements);
990 /* Consistent with lib/libkvm/kvm_proc.c */
991 if (n_elements > MAX_ARGV_STR) {
996 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
997 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
998 ret = proc_rwmem(p, &tmp_uio);
1001 #ifdef COMPAT_FREEBSD32
1002 if (env_vector32 != NULL) {
1003 for (i = 0; i < n_elements; i++)
1004 env_vector[i] = PTRIN(env_vector32[i]);
1008 /* Now we can iterate through the list of strings */
1009 for (i = 0; i < n_elements; i++) {
1010 pbegin = (vm_offset_t)env_vector[i];
1012 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
1013 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
1014 ret = proc_rwmem(p, &tmp_uio);
1018 if (!strvalid(env_string, UIO_CHUNK_SZ)) {
1020 * We didn't find the end of the string.
1021 * Add the string to the buffer and move
1022 * the pointer. But do not allow strings
1023 * of unlimited length.
1025 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1026 if (sbuf_len(sb) >= ARG_MAX) {
1030 pbegin += UIO_CHUNK_SZ;
1032 sbuf_cat(sb, env_string);
1036 sbuf_bcat(sb, "", 1);
1041 free(env_vector, M_TEMP);
1042 #ifdef COMPAT_FREEBSD32
1043 free(env_vector32, M_TEMP);
1049 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1052 *addr = (u_long) ps.ps_argvstr;
1053 *n = ps.ps_nargvstr;
1057 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1060 *addr = (u_long) ps.ps_envstr;
1065 * Filler function for proc/pid/cmdline
1068 linprocfs_doproccmdline(PFS_FILL_ARGS)
1073 if ((ret = p_cansee(td, p)) != 0) {
1079 * Mimic linux behavior and pass only processes with usermode
1080 * address space as valid. Return zero silently otherwize.
1082 if (p->p_vmspace == &vmspace0) {
1086 if (p->p_args != NULL) {
1087 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1093 ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1098 * Filler function for proc/pid/environ
1101 linprocfs_doprocenviron(PFS_FILL_ARGS)
1106 if ((ret = p_candebug(td, p)) != 0) {
1112 * Mimic linux behavior and pass only processes with usermode
1113 * address space as valid. Return zero silently otherwize.
1115 if (p->p_vmspace == &vmspace0) {
1121 ret = linprocfs_doargv(td, p, sb, ps_string_env);
1126 * Filler function for proc/pid/maps
1129 linprocfs_doprocmaps(PFS_FILL_ARGS)
1133 vm_map_entry_t entry, tmp_entry;
1134 vm_object_t obj, tobj, lobj;
1135 vm_offset_t e_start, e_end;
1136 vm_ooffset_t off = 0;
1138 unsigned int last_timestamp;
1139 char *name = "", *freename = NULL;
1141 int ref_count, shadow_count, flags;
1148 error = p_candebug(td, p);
1153 if (uio->uio_rw != UIO_READ)
1154 return (EOPNOTSUPP);
1157 vm = vmspace_acquire_ref(p);
1161 vm_map_lock_read(map);
1162 for (entry = map->header.next; entry != &map->header;
1163 entry = entry->next) {
1166 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1168 e_prot = entry->protection;
1169 e_start = entry->start;
1171 obj = entry->object.vm_object;
1172 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1173 VM_OBJECT_LOCK(tobj);
1175 VM_OBJECT_UNLOCK(lobj);
1178 last_timestamp = map->timestamp;
1179 vm_map_unlock_read(map);
1182 off = IDX_TO_OFF(lobj->size);
1183 if (lobj->type == OBJT_VNODE) {
1191 VM_OBJECT_UNLOCK(lobj);
1193 ref_count = obj->ref_count;
1194 shadow_count = obj->shadow_count;
1195 VM_OBJECT_UNLOCK(obj);
1197 vn_fullpath(td, vp, &name, &freename);
1198 locked = VFS_LOCK_GIANT(vp->v_mount);
1199 vn_lock(vp, LK_SHARED | LK_RETRY);
1200 VOP_GETATTR(vp, &vat, td->td_ucred);
1201 ino = vat.va_fileid;
1203 VFS_UNLOCK_GIANT(locked);
1213 * start, end, access, offset, major, minor, inode, name.
1215 error = sbuf_printf(sb,
1216 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1217 (u_long)e_start, (u_long)e_end,
1218 (e_prot & VM_PROT_READ)?"r":"-",
1219 (e_prot & VM_PROT_WRITE)?"w":"-",
1220 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1230 free(freename, M_TEMP);
1231 vm_map_lock_read(map);
1236 if (last_timestamp != map->timestamp) {
1238 * Look again for the entry because the map was
1239 * modified while it was unlocked. Specifically,
1240 * the entry may have been clipped, merged, or deleted.
1242 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1246 vm_map_unlock_read(map);
1253 * Filler function for proc/net/dev
1256 linprocfs_donetdev(PFS_FILL_ARGS)
1258 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1261 sbuf_printf(sb, "%6s|%58s|%s\n"
1263 "Inter-", " Receive", " Transmit",
1265 "bytes packets errs drop fifo frame compressed multicast",
1266 "bytes packets errs drop fifo colls carrier compressed");
1268 CURVNET_SET(TD_TO_VNET(curthread));
1270 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1271 linux_ifname(ifp, ifname, sizeof ifname);
1272 sbuf_printf(sb, "%6.6s: ", ifname);
1273 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1274 ifp->if_ibytes, /* rx_bytes */
1275 ifp->if_ipackets, /* rx_packets */
1276 ifp->if_ierrors, /* rx_errors */
1277 ifp->if_iqdrops, /* rx_dropped +
1278 * rx_missed_errors */
1279 0UL, /* rx_fifo_errors */
1280 0UL, /* rx_length_errors +
1283 * rx_frame_errors */
1284 0UL, /* rx_compressed */
1285 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */
1286 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1287 ifp->if_obytes, /* tx_bytes */
1288 ifp->if_opackets, /* tx_packets */
1289 ifp->if_oerrors, /* tx_errors */
1290 0UL, /* tx_dropped */
1291 0UL, /* tx_fifo_errors */
1292 ifp->if_collisions, /* collisions */
1293 0UL, /* tx_carrier_errors +
1294 * tx_aborted_errors +
1295 * tx_window_errors +
1296 * tx_heartbeat_errors */
1297 0UL); /* tx_compressed */
1306 * Filler function for proc/sys/kernel/osrelease
1309 linprocfs_doosrelease(PFS_FILL_ARGS)
1311 char osrelease[LINUX_MAX_UTSNAME];
1313 linux_get_osrelease(td, osrelease);
1314 sbuf_printf(sb, "%s\n", osrelease);
1320 * Filler function for proc/sys/kernel/ostype
1323 linprocfs_doostype(PFS_FILL_ARGS)
1325 char osname[LINUX_MAX_UTSNAME];
1327 linux_get_osname(td, osname);
1328 sbuf_printf(sb, "%s\n", osname);
1334 * Filler function for proc/sys/kernel/version
1337 linprocfs_doosbuild(PFS_FILL_ARGS)
1340 linprocfs_osbuild(td, sb);
1346 * Filler function for proc/sys/kernel/msgmni
1349 linprocfs_domsgmni(PFS_FILL_ARGS)
1352 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1357 * Filler function for proc/sys/kernel/pid_max
1360 linprocfs_dopid_max(PFS_FILL_ARGS)
1363 sbuf_printf(sb, "%i\n", PID_MAX);
1368 * Filler function for proc/sys/kernel/sem
1371 linprocfs_dosem(PFS_FILL_ARGS)
1374 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1375 seminfo.semopm, seminfo.semmni);
1380 * Filler function for proc/scsi/device_info
1383 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1390 * Filler function for proc/scsi/scsi
1393 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1399 extern struct cdevsw *cdevsw[];
1402 * Filler function for proc/devices
1405 linprocfs_dodevices(PFS_FILL_ARGS)
1408 sbuf_printf(sb, "Character devices:\n");
1410 char_devices = linux_get_char_devices();
1411 sbuf_printf(sb, "%s", char_devices);
1412 linux_free_get_char_devices(char_devices);
1414 sbuf_printf(sb, "\nBlock devices:\n");
1420 * Filler function for proc/cmdline
1423 linprocfs_docmdline(PFS_FILL_ARGS)
1426 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1427 sbuf_printf(sb, " ro root=302\n");
1432 * Filler function for proc/filesystems
1435 linprocfs_dofilesystems(PFS_FILL_ARGS)
1437 struct vfsconf *vfsp;
1440 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1441 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1442 sbuf_printf(sb, "nodev");
1443 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1451 * Filler function for proc/modules
1454 linprocfs_domodules(PFS_FILL_ARGS)
1456 struct linker_file *lf;
1458 TAILQ_FOREACH(lf, &linker_files, link) {
1459 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1460 (unsigned long)lf->size, lf->refs);
1470 linprocfs_init(PFS_INIT_ARGS)
1472 struct pfs_node *root;
1473 struct pfs_node *dir;
1478 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1479 NULL, NULL, NULL, PFS_RD);
1480 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1481 NULL, NULL, NULL, PFS_RD);
1482 pfs_create_file(root, "devices", &linprocfs_dodevices,
1483 NULL, NULL, NULL, PFS_RD);
1484 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1485 NULL, NULL, NULL, PFS_RD);
1486 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1487 NULL, NULL, NULL, PFS_RD);
1488 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1489 NULL, NULL, NULL, PFS_RD);
1491 pfs_create_file(root, "modules", &linprocfs_domodules,
1492 NULL, NULL, NULL, PFS_RD);
1494 pfs_create_file(root, "mounts", &linprocfs_domtab,
1495 NULL, NULL, NULL, PFS_RD);
1496 pfs_create_file(root, "mtab", &linprocfs_domtab,
1497 NULL, NULL, NULL, PFS_RD);
1498 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1499 NULL, NULL, NULL, PFS_RD);
1500 pfs_create_link(root, "self", &procfs_docurproc,
1501 NULL, NULL, NULL, 0);
1502 pfs_create_file(root, "stat", &linprocfs_dostat,
1503 NULL, NULL, NULL, PFS_RD);
1504 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1505 NULL, NULL, NULL, PFS_RD);
1506 pfs_create_file(root, "uptime", &linprocfs_douptime,
1507 NULL, NULL, NULL, PFS_RD);
1508 pfs_create_file(root, "version", &linprocfs_doversion,
1509 NULL, NULL, NULL, PFS_RD);
1512 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1513 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1514 NULL, NULL, NULL, PFS_RD);
1516 /* /proc/<pid>/... */
1517 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1518 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1519 NULL, NULL, NULL, PFS_RD);
1520 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1521 NULL, NULL, NULL, 0);
1522 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1523 NULL, NULL, NULL, PFS_RD);
1524 pfs_create_link(dir, "exe", &procfs_doprocfile,
1525 NULL, &procfs_notsystem, NULL, 0);
1526 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1527 NULL, NULL, NULL, PFS_RD);
1528 pfs_create_file(dir, "mem", &procfs_doprocmem,
1529 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1530 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1531 NULL, NULL, NULL, 0);
1532 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1533 NULL, NULL, NULL, PFS_RD);
1534 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1535 NULL, NULL, NULL, PFS_RD);
1536 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1537 NULL, NULL, NULL, PFS_RD);
1539 /* /proc/scsi/... */
1540 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1541 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1542 NULL, NULL, NULL, PFS_RD);
1543 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1544 NULL, NULL, NULL, PFS_RD);
1547 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1548 /* /proc/sys/kernel/... */
1549 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1550 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1551 NULL, NULL, NULL, PFS_RD);
1552 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1553 NULL, NULL, NULL, PFS_RD);
1554 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1555 NULL, NULL, NULL, PFS_RD);
1556 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1557 NULL, NULL, NULL, PFS_RD);
1558 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1559 NULL, NULL, NULL, PFS_RD);
1560 pfs_create_file(dir, "sem", &linprocfs_dosem,
1561 NULL, NULL, NULL, PFS_RD);
1570 linprocfs_uninit(PFS_INIT_ARGS)
1573 /* nothing to do, pseudofs will GC */
1577 PSEUDOFS(linprocfs, 1);
1578 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1579 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1580 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1581 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);