linprocfs.c revision 166162
139213Sgibbs/*- 239213Sgibbs * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav 339213Sgibbs * Copyright (c) 1999 Pierre Beyssac 439213Sgibbs * Copyright (c) 1993 Jan-Simon Pendry 539213Sgibbs * Copyright (c) 1993 639213Sgibbs * The Regents of the University of California. All rights reserved. 739213Sgibbs * 839213Sgibbs * This code is derived from software contributed to Berkeley by 939213Sgibbs * Jan-Simon Pendry. 1039213Sgibbs * 1139213Sgibbs * Redistribution and use in source and binary forms, with or without 1239213Sgibbs * modification, are permitted provided that the following conditions 1339213Sgibbs * are met: 1439213Sgibbs * 1. Redistributions of source code must retain the above copyright 1539213Sgibbs * notice, this list of conditions and the following disclaimer. 1639213Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1739213Sgibbs * notice, this list of conditions and the following disclaimer in the 1839213Sgibbs * documentation and/or other materials provided with the distribution. 1939213Sgibbs * 3. All advertising materials mentioning features or use of this software 2039213Sgibbs * must display the following acknowledgement: 2139213Sgibbs * This product includes software developed by the University of 2239213Sgibbs * California, Berkeley and its contributors. 2339213Sgibbs * 4. Neither the name of the University nor the names of its contributors 2439213Sgibbs * may be used to endorse or promote products derived from this software 2539213Sgibbs * without specific prior written permission. 2639213Sgibbs * 2739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2839213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29116162Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30116162Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31116162Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3239213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3339213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3439213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3539213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3760041Sphk * SUCH DAMAGE. 3839213Sgibbs * 3939213Sgibbs * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 4039213Sgibbs */ 4150073Sken 4239213Sgibbs#include <sys/cdefs.h> 4339213Sgibbs__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 166162 2007-01-21 13:18:52Z netchild $"); 4439213Sgibbs 4539213Sgibbs#include <sys/param.h> 4639213Sgibbs#include <sys/queue.h> 4739213Sgibbs#include <sys/blist.h> 4839213Sgibbs#include <sys/conf.h> 4939213Sgibbs#include <sys/exec.h> 5039213Sgibbs#include <sys/filedesc.h> 5139213Sgibbs#include <sys/jail.h> 5239213Sgibbs#include <sys/kernel.h> 5350073Sken#include <sys/linker.h> 5450073Sken#include <sys/lock.h> 5539213Sgibbs#include <sys/malloc.h> 5639213Sgibbs#include <sys/mount.h> 5739213Sgibbs#include <sys/mutex.h> 5839213Sgibbs#include <sys/namei.h> 5939213Sgibbs#include <sys/proc.h> 6039213Sgibbs#include <sys/resourcevar.h> 6139213Sgibbs#include <sys/sbuf.h> 6239213Sgibbs#include <sys/smp.h> 6339213Sgibbs#include <sys/socket.h> 6439213Sgibbs#include <sys/sysctl.h> 6539213Sgibbs#include <sys/systm.h> 6639213Sgibbs#include <sys/time.h> 6739213Sgibbs#include <sys/tty.h> 6839213Sgibbs#include <sys/user.h> 6939213Sgibbs#include <sys/vmmeter.h> 7039213Sgibbs#include <sys/vnode.h> 7139213Sgibbs 7239213Sgibbs#include <net/if.h> 7339213Sgibbs 7439213Sgibbs#include <vm/vm.h> 7539213Sgibbs#include <vm/pmap.h> 7639213Sgibbs#include <vm/vm_map.h> 7739213Sgibbs#include <vm/vm_param.h> 7839213Sgibbs#include <vm/vm_object.h> 7959249Sphk#include <vm/swap_pager.h> 80112006Sphk 8160938Sjake#include <machine/clock.h> 8239213Sgibbs 8339213Sgibbs#if defined(__i386__) || defined(__amd64__) 8439213Sgibbs#include <machine/cputypes.h> 8550073Sken#include <machine/md_var.h> 8653257Sken#endif /* __i386__ || __amd64__ */ 8739213Sgibbs 8839213Sgibbs#include "opt_compat.h" 8939213Sgibbs#ifdef COMPAT_LINUX32 /* XXX */ 9039213Sgibbs#include <machine/../linux32/linux.h> 9139213Sgibbs#else 9239213Sgibbs#include <machine/../linux/linux.h> 9339213Sgibbs#endif 9439213Sgibbs#include <compat/linux/linux_ioctl.h> 9539213Sgibbs#include <compat/linux/linux_mib.h> 9640603Sken#include <compat/linux/linux_util.h> 9739213Sgibbs#include <fs/pseudofs/pseudofs.h> 9839213Sgibbs#include <fs/procfs/procfs.h> 9939213Sgibbs 10039213Sgibbs/* 10150073Sken * Various conversion macros 10239213Sgibbs */ 10339213Sgibbs#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10439213Sgibbs#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10539213Sgibbs#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10639213Sgibbs#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10739213Sgibbs#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10839213Sgibbs#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10939213Sgibbs 11039213Sgibbs/** 11139213Sgibbs * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 11239213Sgibbs * 11339213Sgibbs * The linux procfs state field displays one of the characters RSDZTW to 11439213Sgibbs * denote running, sleeping in an interruptible wait, waiting in an 11539213Sgibbs * uninteruptible disk sleep, a zombie process, process is being traced 11639213Sgibbs * or stopped, or process is paging respectively. 11772119Speter * 11839213Sgibbs * Our struct kinfo_proc contains the variable ki_stat which contains a 11939213Sgibbs * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 12047625Sphk * 121126080Sphk * This character array is used with ki_stati-1 as an index and tries to 122126080Sphk * map our states to suitable linux states. 123111815Sphk */ 124111815Sphkstatic char linux_state[] = "RRSTZDD"; 125111815Sphk 126111815Sphk/* 127111815Sphk * Filler function for proc/meminfo 128111815Sphk */ 129111815Sphkstatic int 13039213Sgibbslinprocfs_domeminfo(PFS_FILL_ARGS) 13139213Sgibbs{ 13250073Sken unsigned long memtotal; /* total memory in bytes */ 13350073Sken unsigned long memused; /* used memory in bytes */ 13450073Sken unsigned long memfree; /* free memory in bytes */ 13550073Sken unsigned long memshared; /* shared memory ??? */ 13639213Sgibbs unsigned long buffers, cached; /* buffer / cache memory ??? */ 13783366Sjulian unsigned long long swaptotal; /* total swap space in bytes */ 13839213Sgibbs unsigned long long swapused; /* used swap space in bytes */ 13939213Sgibbs unsigned long long swapfree; /* free swap space in bytes */ 14039213Sgibbs vm_object_t object; 14139213Sgibbs int i, j; 14239213Sgibbs 14340603Sken memtotal = physmem * PAGE_SIZE; 14439213Sgibbs /* 14539213Sgibbs * The correct thing here would be: 146101940Snjl * 14739213Sgibbs memfree = cnt.v_free_count * PAGE_SIZE; 14839213Sgibbs memused = memtotal - memfree; 14939213Sgibbs * 15039213Sgibbs * but it might mislead linux binaries into thinking there 15139213Sgibbs * is very little memory left, so we cheat and tell them that 15240603Sken * all memory that isn't wired down is free. 15340603Sken */ 15440603Sken memused = cnt.v_wire_count * PAGE_SIZE; 15540603Sken memfree = memtotal - memused; 15640603Sken swap_pager_status(&i, &j); 15740603Sken swaptotal = (unsigned long long)i * PAGE_SIZE; 15839213Sgibbs swapused = (unsigned long long)j * PAGE_SIZE; 15949982Sbillf swapfree = swaptotal - swapused; 16039213Sgibbs memshared = 0; 16141297Sken mtx_lock(&vm_object_list_mtx); 16241297Sken TAILQ_FOREACH(object, &vm_object_list, object_list) 16339213Sgibbs if (object->shadow_count > 1) 16441297Sken memshared += object->resident_page_count; 16539213Sgibbs mtx_unlock(&vm_object_list_mtx); 16641297Sken memshared *= PAGE_SIZE; 16741297Sken /* 16839213Sgibbs * We'd love to be able to write: 16939213Sgibbs * 17039213Sgibbs buffers = bufspace; 17139213Sgibbs * 17239213Sgibbs * but bufspace is internal to vfs_bio.c and we don't feel 17339213Sgibbs * like unstaticizing it just for linprocfs's sake. 17439213Sgibbs */ 17539213Sgibbs buffers = 0; 17639213Sgibbs cached = cnt.v_cache_count * PAGE_SIZE; 17739213Sgibbs 17839213Sgibbs sbuf_printf(sb, 17939213Sgibbs " total: used: free: shared: buffers: cached:\n" 18039213Sgibbs "Mem: %lu %lu %lu %lu %lu %lu\n" 18183366Sjulian "Swap: %llu %llu %llu\n" 18239213Sgibbs "MemTotal: %9lu kB\n" 18339213Sgibbs "MemFree: %9lu kB\n" 18439213Sgibbs "MemShared:%9lu kB\n" 18539213Sgibbs "Buffers: %9lu kB\n" 18639213Sgibbs "Cached: %9lu kB\n" 187101940Snjl "SwapTotal:%9llu kB\n" 18839213Sgibbs "SwapFree: %9llu kB\n", 18939213Sgibbs memtotal, memused, memfree, memshared, buffers, cached, 19039213Sgibbs swaptotal, swapused, swapfree, 19139213Sgibbs B2K(memtotal), B2K(memfree), 19239213Sgibbs B2K(memshared), B2K(buffers), B2K(cached), 19339213Sgibbs B2K(swaptotal), B2K(swapfree)); 19439213Sgibbs 19539213Sgibbs return (0); 19639213Sgibbs} 19739213Sgibbs 19839213Sgibbs#if defined(__i386__) || defined(__amd64__) 19939213Sgibbs/* 20039213Sgibbs * Filler function for proc/cpuinfo (i386 & amd64 version) 20139213Sgibbs */ 20239213Sgibbsstatic int 20339213Sgibbslinprocfs_docpuinfo(PFS_FILL_ARGS) 20439213Sgibbs{ 20539213Sgibbs int hw_model[2]; 20639213Sgibbs char model[128]; 20739213Sgibbs size_t size; 20859249Sphk int class, fqmhz, fqkhz; 20939213Sgibbs int i; 21039213Sgibbs 21139213Sgibbs /* 21239213Sgibbs * We default the flags to include all non-conflicting flags, 21339213Sgibbs * and the Intel versions of conflicting flags. 214101940Snjl */ 21576362Sphk static char *flags[] = { 21639213Sgibbs "fpu", "vme", "de", "pse", "tsc", 21776362Sphk "msr", "pae", "mce", "cx8", "apic", 21876362Sphk "sep", "sep", "mtrr", "pge", "mca", 21939213Sgibbs "cmov", "pat", "pse36", "pn", "b19", 22039213Sgibbs "b20", "b21", "mmxext", "mmx", "fxsr", 22139213Sgibbs "xmm", "b26", "b27", "b28", "b29", 22239213Sgibbs "3dnowext", "3dnow" 22339213Sgibbs }; 22439213Sgibbs 22539213Sgibbs switch (cpu_class) { 22639213Sgibbs#ifdef __i386__ 22739213Sgibbs case CPUCLASS_286: 22839213Sgibbs class = 2; 22939213Sgibbs break; 23039213Sgibbs case CPUCLASS_386: 23139213Sgibbs class = 3; 23239213Sgibbs break; 23339213Sgibbs case CPUCLASS_486: 23476362Sphk class = 4; 23576362Sphk break; 23639213Sgibbs case CPUCLASS_586: 23739213Sgibbs class = 5; 23839213Sgibbs break; 23939213Sgibbs case CPUCLASS_686: 24039213Sgibbs class = 6; 24159249Sphk break; 24239213Sgibbs default: 24339213Sgibbs class = 0; 24439213Sgibbs break; 24539213Sgibbs#else /* __amd64__ */ 24639213Sgibbs default: 24739213Sgibbs class = 15; 24839213Sgibbs break; 24939213Sgibbs#endif 25039213Sgibbs } 25139213Sgibbs 25239213Sgibbs hw_model[0] = CTL_HW; 25339213Sgibbs hw_model[1] = HW_MODEL; 25439213Sgibbs model[0] = '\0'; 25539213Sgibbs size = sizeof(model); 25639213Sgibbs if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 25739213Sgibbs strcpy(model, "unknown"); 25839213Sgibbs for (i = 0; i < mp_ncpus; ++i) { 25939213Sgibbs sbuf_printf(sb, 26039213Sgibbs "processor\t: %d\n" 26139213Sgibbs "vendor_id\t: %.20s\n" 26239213Sgibbs "cpu family\t: %d\n" 26339213Sgibbs "model\t\t: %d\n" 26439213Sgibbs "model name\t: %s\n" 26539213Sgibbs "stepping\t: %d\n", 26639213Sgibbs i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 26739213Sgibbs /* XXX per-cpu vendor / class / model / id? */ 26839213Sgibbs } 26939213Sgibbs 27039213Sgibbs sbuf_cat(sb, 27139213Sgibbs "flags\t\t:"); 27239213Sgibbs 27339213Sgibbs if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27439213Sgibbs flags[16] = "fcmov"; 27539213Sgibbs } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 27639213Sgibbs flags[24] = "cxmmx"; 27739213Sgibbs } 27839213Sgibbs 27939213Sgibbs for (i = 0; i < 32; i++) 28039213Sgibbs if (cpu_feature & (1 << i)) 28139213Sgibbs sbuf_printf(sb, " %s", flags[i]); 28239213Sgibbs sbuf_cat(sb, "\n"); 28339213Sgibbs if (class >= 5) { 28439213Sgibbs fqmhz = (tsc_freq + 4999) / 1000000; 28539213Sgibbs fqkhz = ((tsc_freq + 4999) / 10000) % 100; 28639213Sgibbs sbuf_printf(sb, 28739213Sgibbs "cpu MHz\t\t: %d.%02d\n" 28839213Sgibbs "bogomips\t: %d.%02d\n", 28939213Sgibbs fqmhz, fqkhz, fqmhz, fqkhz); 29039213Sgibbs } 29139213Sgibbs 29239213Sgibbs return (0); 29339213Sgibbs} 29439213Sgibbs#endif /* __i386__ || __amd64__ */ 29539213Sgibbs 29639213Sgibbs/* 29739213Sgibbs * Filler function for proc/mtab 29839213Sgibbs * 29939213Sgibbs * This file doesn't exist in Linux' procfs, but is included here so 30039213Sgibbs * users can symlink /compat/linux/etc/mtab to /proc/mtab 30139213Sgibbs */ 30239213Sgibbsstatic int 30339213Sgibbslinprocfs_domtab(PFS_FILL_ARGS) 30439213Sgibbs{ 30539213Sgibbs struct nameidata nd; 30639213Sgibbs struct mount *mp; 30739213Sgibbs const char *lep; 30839213Sgibbs char *dlep, *flep, *mntto, *mntfrom, *fstype; 30939213Sgibbs size_t lep_len; 31039213Sgibbs int error; 31139213Sgibbs 31239213Sgibbs /* resolve symlinks etc. in the emulation tree prefix */ 31339213Sgibbs NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 31459249Sphk flep = NULL; 31539213Sgibbs if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 31650073Sken lep = linux_emul_path; 31750073Sken else 31839213Sgibbs lep = dlep; 31939213Sgibbs lep_len = strlen(lep); 320112006Sphk 32139213Sgibbs mtx_lock(&mountlist_mtx); 32239213Sgibbs error = 0; 32356148Smjacob TAILQ_FOREACH(mp, &mountlist, mnt_list) { 32443819Sken /* determine device name */ 32539213Sgibbs mntfrom = mp->mnt_stat.f_mntfromname; 32653257Sken 32753257Sken /* determine mount point */ 32853257Sken mntto = mp->mnt_stat.f_mntonname; 329101940Snjl if (strncmp(mntto, lep, lep_len) == 0 && 330101940Snjl mntto[lep_len] == '/') 33139213Sgibbs mntto += lep_len; 33239213Sgibbs 33339213Sgibbs /* determine fs type */ 33439213Sgibbs fstype = mp->mnt_stat.f_fstypename; 33539213Sgibbs if (strcmp(fstype, pn->pn_info->pi_name) == 0) 33639213Sgibbs mntfrom = fstype = "proc"; 33739213Sgibbs else if (strcmp(fstype, "procfs") == 0) 33839213Sgibbs continue; 33939213Sgibbs 34039213Sgibbs if (strcmp(fstype, "linsysfs") == 0) { 34139213Sgibbs sbuf_printf(sb, "/sys %s sysfs %s", mntto, 34239213Sgibbs mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 34339213Sgibbs } else { 34439213Sgibbs sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 34539213Sgibbs mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 34639213Sgibbs } 34739213Sgibbs#define ADD_OPTION(opt, name) \ 34839213Sgibbs if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 34939213Sgibbs ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35039213Sgibbs ADD_OPTION(MNT_NOEXEC, "noexec"); 35139213Sgibbs ADD_OPTION(MNT_NOSUID, "nosuid"); 35239213Sgibbs ADD_OPTION(MNT_UNION, "union"); 35340603Sken ADD_OPTION(MNT_ASYNC, "async"); 35440603Sken ADD_OPTION(MNT_SUIDDIR, "suiddir"); 35540603Sken ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 35640603Sken ADD_OPTION(MNT_NOATIME, "noatime"); 35740603Sken#undef ADD_OPTION 35840603Sken /* a real Linux mtab will also show NFS options */ 35940603Sken sbuf_printf(sb, " 0 0\n"); 36040603Sken } 36140603Sken mtx_unlock(&mountlist_mtx); 36240603Sken if (flep != NULL) 36340603Sken free(flep, M_TEMP); 36440603Sken return (error); 36540603Sken} 36640603Sken 36740603Sken/* 36840603Sken * Filler function for proc/stat 36940603Sken */ 37040603Skenstatic int 37140603Skenlinprocfs_dostat(PFS_FILL_ARGS) 37240603Sken{ 37340603Sken int i; 37440603Sken 37540603Sken sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 37640603Sken T2J(cp_time[CP_USER]), 37740603Sken T2J(cp_time[CP_NICE]), 37840603Sken T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 37940603Sken T2J(cp_time[CP_IDLE])); 38040603Sken for (i = 0; i < mp_ncpus; ++i) 38140603Sken sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 38240603Sken T2J(cp_time[CP_USER]) / mp_ncpus, 38340603Sken T2J(cp_time[CP_NICE]) / mp_ncpus, 38440603Sken T2J(cp_time[CP_SYS]) / mp_ncpus, 38540603Sken T2J(cp_time[CP_IDLE]) / mp_ncpus); 386112946Sphk sbuf_printf(sb, 38740603Sken "disk 0 0 0 0\n" 38840603Sken "page %u %u\n" 38940603Sken "swap %u %u\n" 39040603Sken "intr %u\n" 39140603Sken "ctxt %u\n" 39240603Sken "btime %lld\n", 39340603Sken cnt.v_vnodepgsin, 39440603Sken cnt.v_vnodepgsout, 39539213Sgibbs cnt.v_swappgsin, 39639213Sgibbs cnt.v_swappgsout, 39740603Sken cnt.v_intr, 39840603Sken cnt.v_swtch, 39940603Sken (long long)boottime.tv_sec); 40040603Sken return (0); 401112006Sphk} 40240603Sken 40353257Sken/* 40453257Sken * Filler function for proc/uptime 40539213Sgibbs */ 40639213Sgibbsstatic int 40740603Skenlinprocfs_douptime(PFS_FILL_ARGS) 40839213Sgibbs{ 40939213Sgibbs struct timeval tv; 41039213Sgibbs 41139213Sgibbs getmicrouptime(&tv); 41239213Sgibbs sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 41339213Sgibbs (long long)tv.tv_sec, tv.tv_usec / 10000, 41439213Sgibbs T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 41539213Sgibbs return (0); 41639213Sgibbs} 41739213Sgibbs 41839213Sgibbs/* 41939213Sgibbs * Filler function for proc/version 42039213Sgibbs */ 42139213Sgibbsstatic int 42239213Sgibbslinprocfs_doversion(PFS_FILL_ARGS) 42379177Smjacob{ 42479177Smjacob char osname[LINUX_MAX_UTSNAME]; 42539213Sgibbs char osrelease[LINUX_MAX_UTSNAME]; 42656148Smjacob 42739213Sgibbs linux_get_osname(td, osname); 42839213Sgibbs linux_get_osrelease(td, osrelease); 42939213Sgibbs 43039213Sgibbs sbuf_printf(sb, 43139213Sgibbs "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 43239213Sgibbs " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 43339213Sgibbs return (0); 43440603Sken} 43540603Sken 43640603Sken/* 43740603Sken * Filler function for proc/loadavg 43839213Sgibbs */ 43939213Sgibbsstatic int 44039213Sgibbslinprocfs_doloadavg(PFS_FILL_ARGS) 44139213Sgibbs{ 44239213Sgibbs sbuf_printf(sb, 44339213Sgibbs "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 44439213Sgibbs (int)(averunnable.ldavg[0] / averunnable.fscale), 44539213Sgibbs (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 44639213Sgibbs (int)(averunnable.ldavg[1] / averunnable.fscale), 44739213Sgibbs (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 44839213Sgibbs (int)(averunnable.ldavg[2] / averunnable.fscale), 44939213Sgibbs (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 45039213Sgibbs 1, /* number of running tasks */ 45139213Sgibbs nprocs, /* number of tasks */ 45239213Sgibbs lastpid /* the last pid */ 45339213Sgibbs ); 45439213Sgibbs 45539213Sgibbs return (0); 45639213Sgibbs} 45739213Sgibbs 45839213Sgibbs/* 45971999Sphk * Filler function for proc/pid/stat 46039213Sgibbs */ 46139213Sgibbsstatic int 46239213Sgibbslinprocfs_doprocstat(PFS_FILL_ARGS) 463115562Sphk{ 46439213Sgibbs struct kinfo_proc kp; 46547413Sgibbs char state; 46639213Sgibbs static int ratelimit = 0; 46739213Sgibbs 46839213Sgibbs PROC_LOCK(p); 46939213Sgibbs fill_kinfo_proc(p, &kp); 47039213Sgibbs sbuf_printf(sb, "%d", p->p_pid); 47139213Sgibbs#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 47239213Sgibbs PS_ADD("comm", "(%s)", p->p_comm); 47339213Sgibbs if (kp.ki_stat > sizeof(linux_state)) { 47459249Sphk state = 'R'; 47539213Sgibbs 47639213Sgibbs if (ratelimit == 0) { 47739213Sgibbs printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 47839213Sgibbs kp.ki_stat, sizeof(linux_state)); 47939213Sgibbs ++ratelimit; 48039213Sgibbs } 48139213Sgibbs } else 48239213Sgibbs state = linux_state[kp.ki_stat - 1]; 48359249Sphk PS_ADD("state", "%c", state); 48439213Sgibbs PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 48539213Sgibbs PS_ADD("pgrp", "%d", p->p_pgid); 48639213Sgibbs PS_ADD("session", "%d", p->p_session->s_sid); 48739213Sgibbs PROC_UNLOCK(p); 48839213Sgibbs PS_ADD("tty", "%d", 0); /* XXX */ 48939213Sgibbs PS_ADD("tpgid", "%d", kp.ki_tpgid); 49039213Sgibbs PS_ADD("flags", "%u", 0); /* XXX */ 49139213Sgibbs PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 49239213Sgibbs PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 49339213Sgibbs PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 49439213Sgibbs PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 49539213Sgibbs PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 49639213Sgibbs PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 49739213Sgibbs PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 49839213Sgibbs PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 49959249Sphk PS_ADD("priority", "%d", kp.ki_pri.pri_user); 50039213Sgibbs PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 501112260Sphk PS_ADD("0", "%d", 0); /* removed field */ 50239213Sgibbs PS_ADD("itrealvalue", "%d", 0); /* XXX */ 50339213Sgibbs /* XXX: starttime is not right, it is the _same_ for _every_ process. 50439213Sgibbs It should be the number of jiffies between system boot and process 50539213Sgibbs start. */ 50639213Sgibbs PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 50759249Sphk PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 50839213Sgibbs PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 50959249Sphk PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 51059249Sphk PS_ADD("startcode", "%u", (unsigned)0); 51139213Sgibbs PS_ADD("endcode", "%u", 0); /* XXX */ 51250073Sken PS_ADD("startstack", "%u", 0); /* XXX */ 51339213Sgibbs PS_ADD("kstkesp", "%u", 0); /* XXX */ 51476192Sken PS_ADD("kstkeip", "%u", 0); /* XXX */ 51539213Sgibbs PS_ADD("signal", "%u", 0); /* XXX */ 51639213Sgibbs PS_ADD("blocked", "%u", 0); /* XXX */ 51739213Sgibbs PS_ADD("sigignore", "%u", 0); /* XXX */ 51839213Sgibbs PS_ADD("sigcatch", "%u", 0); /* XXX */ 51939213Sgibbs PS_ADD("wchan", "%u", 0); /* XXX */ 52039213Sgibbs PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 52139213Sgibbs PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 52239213Sgibbs PS_ADD("exitsignal", "%d", 0); /* XXX */ 52339213Sgibbs PS_ADD("processor", "%u", kp.ki_lastcpu); 52439213Sgibbs PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 52539213Sgibbs PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 52659249Sphk#undef PS_ADD 52739213Sgibbs sbuf_putc(sb, '\n'); 52839213Sgibbs 52939213Sgibbs return (0); 53039213Sgibbs} 53139213Sgibbs 53239213Sgibbs/* 53339213Sgibbs * Filler function for proc/pid/statm 53439213Sgibbs */ 53539213Sgibbsstatic int 53639213Sgibbslinprocfs_doprocstatm(PFS_FILL_ARGS) 53739213Sgibbs{ 53839213Sgibbs struct kinfo_proc kp; 53939213Sgibbs segsz_t lsize; 54039213Sgibbs 54139213Sgibbs PROC_LOCK(p); 54239213Sgibbs fill_kinfo_proc(p, &kp); 54339213Sgibbs PROC_UNLOCK(p); 54439213Sgibbs 54539213Sgibbs /* 54639213Sgibbs * See comments in linprocfs_doprocstatus() regarding the 54739213Sgibbs * computation of lsize. 54839213Sgibbs */ 54939213Sgibbs /* size resident share trs drs lrs dt */ 55059249Sphk sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 55139213Sgibbs sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 55239213Sgibbs sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 55359249Sphk sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 55439213Sgibbs sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 55539213Sgibbs lsize = B2P(kp.ki_size) - kp.ki_dsize - 55639213Sgibbs kp.ki_ssize - kp.ki_tsize - 1; 55739213Sgibbs sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 55839213Sgibbs sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 55939213Sgibbs 56039213Sgibbs return (0); 56139213Sgibbs} 56239213Sgibbs 56339213Sgibbs/* 56474840Sken * Filler function for proc/pid/status 56574840Sken */ 56639213Sgibbsstatic int 56739213Sgibbslinprocfs_doprocstatus(PFS_FILL_ARGS) 56839213Sgibbs{ 56939213Sgibbs struct kinfo_proc kp; 57039213Sgibbs char *state; 57139213Sgibbs segsz_t lsize; 57239213Sgibbs struct thread *td2; 57339213Sgibbs struct sigacts *ps; 57439213Sgibbs int i; 57539213Sgibbs 57639213Sgibbs PROC_LOCK(p); 57739213Sgibbs td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 57839213Sgibbs 57939213Sgibbs if (P_SHOULDSTOP(p)) { 58039213Sgibbs state = "T (stopped)"; 58139213Sgibbs } else { 58239213Sgibbs mtx_lock_spin(&sched_lock); 58339213Sgibbs switch(p->p_state) { 58439213Sgibbs case PRS_NEW: 58539213Sgibbs state = "I (idle)"; 58639213Sgibbs break; 58739213Sgibbs case PRS_NORMAL: 58839213Sgibbs if (p->p_flag & P_WEXIT) { 58939213Sgibbs state = "X (exiting)"; 590112946Sphk break; 59139213Sgibbs } 59259249Sphk switch(td2->td_state) { 59359249Sphk case TDS_INHIBITED: 59459249Sphk state = "S (sleeping)"; 59539213Sgibbs break; 59659249Sphk case TDS_RUNQ: 59759249Sphk case TDS_RUNNING: 59859249Sphk state = "R (running)"; 59939213Sgibbs break; 60059249Sphk default: 60139213Sgibbs state = "? (unknown)"; 60239213Sgibbs break; 60339213Sgibbs } 60439213Sgibbs break; 60539213Sgibbs case PRS_ZOMBIE: 60639213Sgibbs state = "Z (zombie)"; 60739213Sgibbs break; 60839213Sgibbs default: 60939213Sgibbs state = "? (unknown)"; 61059249Sphk break; 61159249Sphk } 61259249Sphk mtx_unlock_spin(&sched_lock); 61339213Sgibbs } 61439213Sgibbs 61539213Sgibbs fill_kinfo_proc(p, &kp); 61639213Sgibbs sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 61739213Sgibbs sbuf_printf(sb, "State:\t%s\n", state); 61839213Sgibbs 61939213Sgibbs /* 62039213Sgibbs * Credentials 62139213Sgibbs */ 62239213Sgibbs sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 623112006Sphk sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 62439213Sgibbs p->p_pptr->p_pid : 0); 62539213Sgibbs sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 62639213Sgibbs p->p_ucred->cr_uid, 62739213Sgibbs p->p_ucred->cr_svuid, 62839213Sgibbs /* FreeBSD doesn't have fsuid */ 62939213Sgibbs p->p_ucred->cr_uid); 63039213Sgibbs sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 63139213Sgibbs p->p_ucred->cr_gid, 63239213Sgibbs p->p_ucred->cr_svgid, 63339213Sgibbs /* FreeBSD doesn't have fsgid */ 63439213Sgibbs p->p_ucred->cr_gid); 63539213Sgibbs sbuf_cat(sb, "Groups:\t"); 63639213Sgibbs for (i = 0; i < p->p_ucred->cr_ngroups; i++) 63739213Sgibbs sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 63839213Sgibbs PROC_UNLOCK(p); 63939213Sgibbs sbuf_putc(sb, '\n'); 64039213Sgibbs 64139213Sgibbs /* 64239213Sgibbs * Memory 64339213Sgibbs * 64439213Sgibbs * While our approximation of VmLib may not be accurate (I 64539213Sgibbs * don't know of a simple way to verify it, and I'm not sure 64639213Sgibbs * it has much meaning anyway), I believe it's good enough. 64750073Sken * 64883366Sjulian * The same code that could (I think) accurately compute VmLib 64950073Sken * could also compute VmLck, but I don't really care enough to 65050073Sken * implement it. Submissions are welcome. 65150073Sken */ 65250073Sken sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 65350073Sken sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 654101940Snjl sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 65550073Sken sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 65650073Sken sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 65750073Sken sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 65850073Sken lsize = B2P(kp.ki_size) - kp.ki_dsize - 65950073Sken kp.ki_ssize - kp.ki_tsize - 1; 66050073Sken sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 66150073Sken 66250073Sken /* 66350073Sken * Signal masks 66450073Sken * 66550073Sken * We support up to 128 signals, while Linux supports 32, 66650073Sken * but we only define 32 (the same 32 as Linux, to boot), so 66750073Sken * just show the lower 32 bits of each mask. XXX hack. 66850073Sken * 66950073Sken * NB: on certain platforms (Sparc at least) Linux actually 67050073Sken * supports 64 signals, but this code is a long way from 67150073Sken * running on anything but i386, so ignore that for now. 67250073Sken */ 67350073Sken PROC_LOCK(p); 67450073Sken sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 67550073Sken /* 67650073Sken * I can't seem to find out where the signal mask is in 67750073Sken * relation to struct proc, so SigBlk is left unimplemented. 67850073Sken */ 67950073Sken sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 68050073Sken ps = p->p_sigacts; 68150073Sken mtx_lock(&ps->ps_mtx); 68250073Sken sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 68350073Sken sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 68450073Sken mtx_unlock(&ps->ps_mtx); 68550073Sken PROC_UNLOCK(p); 68650073Sken 68750073Sken /* 68850073Sken * Linux also prints the capability masks, but we don't have 68950073Sken * capabilities yet, and when we do get them they're likely to 69050073Sken * be meaningless to Linux programs, so we lie. XXX 69150073Sken */ 69250073Sken sbuf_printf(sb, "CapInh:\t%016x\n", 0); 69350073Sken sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 69450073Sken sbuf_printf(sb, "CapEff:\t%016x\n", 0); 69550073Sken 69639213Sgibbs return (0); 69739213Sgibbs} 69839213Sgibbs 69939213Sgibbs 70039213Sgibbs/* 70139213Sgibbs * Filler function for proc/pid/cwd 70239213Sgibbs */ 70339213Sgibbsstatic int 70439213Sgibbslinprocfs_doproccwd(PFS_FILL_ARGS) 70539213Sgibbs{ 70639213Sgibbs char *fullpath = "unknown"; 70739213Sgibbs char *freepath = NULL; 70839213Sgibbs 70939213Sgibbs vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 71039213Sgibbs sbuf_printf(sb, "%s", fullpath); 71139213Sgibbs if (freepath) 71239213Sgibbs free(freepath, M_TEMP); 71339213Sgibbs return (0); 71439213Sgibbs} 71539213Sgibbs 71639213Sgibbs/* 71739213Sgibbs * Filler function for proc/pid/root 71839213Sgibbs */ 71939213Sgibbsstatic int 72039213Sgibbslinprocfs_doprocroot(PFS_FILL_ARGS) 72139213Sgibbs{ 722 struct vnode *rvp; 723 char *fullpath = "unknown"; 724 char *freepath = NULL; 725 726 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 727 vn_fullpath(td, rvp, &fullpath, &freepath); 728 sbuf_printf(sb, "%s", fullpath); 729 if (freepath) 730 free(freepath, M_TEMP); 731 return (0); 732} 733 734/* 735 * Filler function for proc/pid/cmdline 736 */ 737static int 738linprocfs_doproccmdline(PFS_FILL_ARGS) 739{ 740 struct ps_strings pstr; 741 char **ps_argvstr; 742 int error, i; 743 744 /* 745 * If we are using the ps/cmdline caching, use that. Otherwise 746 * revert back to the old way which only implements full cmdline 747 * for the currept process and just p->p_comm for all other 748 * processes. 749 * Note that if the argv is no longer available, we deliberately 750 * don't fall back on p->p_comm or return an error: the authentic 751 * Linux behaviour is to return zero-length in this case. 752 */ 753 754 PROC_LOCK(p); 755 if (p->p_args && p_cansee(td, p) == 0) { 756 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 757 PROC_UNLOCK(p); 758 } else if (p != td->td_proc) { 759 PROC_UNLOCK(p); 760 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 761 } else { 762 PROC_UNLOCK(p); 763 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 764 sizeof(pstr)); 765 if (error) 766 return (error); 767 if (pstr.ps_nargvstr > ARG_MAX) 768 return (E2BIG); 769 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 770 M_TEMP, M_WAITOK); 771 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 772 pstr.ps_nargvstr * sizeof(char *)); 773 if (error) { 774 free(ps_argvstr, M_TEMP); 775 return (error); 776 } 777 for (i = 0; i < pstr.ps_nargvstr; i++) { 778 sbuf_copyin(sb, ps_argvstr[i], 0); 779 sbuf_printf(sb, "%c", '\0'); 780 } 781 free(ps_argvstr, M_TEMP); 782 } 783 784 return (0); 785} 786 787/* 788 * Filler function for proc/pid/environ 789 */ 790static int 791linprocfs_doprocenviron(PFS_FILL_ARGS) 792{ 793 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 794 795 return (0); 796} 797 798/* 799 * Filler function for proc/pid/maps 800 */ 801static int 802linprocfs_doprocmaps(PFS_FILL_ARGS) 803{ 804 char mebuffer[512]; 805 vm_map_t map = &p->p_vmspace->vm_map; 806 vm_map_entry_t entry; 807 vm_object_t obj, tobj, lobj; 808 vm_ooffset_t off = 0; 809 char *name = "", *freename = NULL; 810 size_t len; 811 ino_t ino; 812 int ref_count, shadow_count, flags; 813 int error; 814 struct vnode *vp; 815 struct vattr vat; 816 int locked; 817 818 PROC_LOCK(p); 819 error = p_candebug(td, p); 820 PROC_UNLOCK(p); 821 if (error) 822 return (error); 823 824 if (uio->uio_rw != UIO_READ) 825 return (EOPNOTSUPP); 826 827 if (uio->uio_offset != 0) 828 return (0); 829 830 error = 0; 831 if (map != &curthread->td_proc->p_vmspace->vm_map) 832 vm_map_lock_read(map); 833 for (entry = map->header.next; 834 ((uio->uio_resid > 0) && (entry != &map->header)); 835 entry = entry->next) { 836 name = ""; 837 freename = NULL; 838 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 839 continue; 840 obj = entry->object.vm_object; 841 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 842 lobj = tobj; 843 ino = 0; 844 if (lobj) { 845 VM_OBJECT_LOCK(lobj); 846 off = IDX_TO_OFF(lobj->size); 847 if (lobj->type == OBJT_VNODE) { 848 vp = lobj->handle; 849 if (vp) 850 vref(vp); 851 } 852 else 853 vp = NULL; 854 flags = obj->flags; 855 ref_count = obj->ref_count; 856 shadow_count = obj->shadow_count; 857 VM_OBJECT_UNLOCK(lobj); 858 if (vp) { 859 vn_fullpath(td, vp, &name, &freename); 860 locked = VFS_LOCK_GIANT(vp->v_mount); 861 vn_lock(vp, LK_SHARED | LK_RETRY, td); 862 VOP_GETATTR(vp, &vat, td->td_ucred, td); 863 ino = vat.va_fileid; 864 vput(vp); 865 VFS_UNLOCK_GIANT(locked); 866 } 867 } else { 868 flags = 0; 869 ref_count = 0; 870 shadow_count = 0; 871 } 872 873 /* 874 * format: 875 * start, end, access, offset, major, minor, inode, name. 876 */ 877 snprintf(mebuffer, sizeof mebuffer, 878 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 879 (u_long)entry->start, (u_long)entry->end, 880 (entry->protection & VM_PROT_READ)?"r":"-", 881 (entry->protection & VM_PROT_WRITE)?"w":"-", 882 (entry->protection & VM_PROT_EXECUTE)?"x":"-", 883 "p", 884 (u_long)off, 885 0, 886 0, 887 (u_long)ino, 888 *name ? " " : "", 889 name 890 ); 891 if (freename) 892 free(freename, M_TEMP); 893 len = strlen(mebuffer); 894 if (len > uio->uio_resid) 895 len = uio->uio_resid; /* 896 * XXX We should probably return 897 * EFBIG here, as in procfs. 898 */ 899 error = uiomove(mebuffer, len, uio); 900 if (error) 901 break; 902 } 903 if (map != &curthread->td_proc->p_vmspace->vm_map) 904 vm_map_unlock_read(map); 905 906 return (error); 907} 908 909/* 910 * Filler function for proc/net/dev 911 */ 912static int 913linprocfs_donetdev(PFS_FILL_ARGS) 914{ 915 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 916 struct ifnet *ifp; 917 918 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 919 "Inter-", " Receive", " Transmit", " face", 920 "bytes packets errs drop fifo frame compressed", 921 "bytes packets errs drop fifo frame compressed"); 922 923 IFNET_RLOCK(); 924 TAILQ_FOREACH(ifp, &ifnet, if_link) { 925 linux_ifname(ifp, ifname, sizeof ifname); 926 sbuf_printf(sb, "%6.6s:", ifname); 927 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 928 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 929 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 930 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 931 } 932 IFNET_RUNLOCK(); 933 934 return (0); 935} 936 937/* 938 * Filler function for proc/sys/kernel/msgmni 939 */ 940static int 941linprocfs_domsgmni(PFS_FILL_ARGS) 942{ 943 int msgmni; 944 size_t size; 945 946 size = sizeof(msgmni); 947 if (kernel_sysctlbyname(td, "kern.ipc.msgmni", &msgmni, &size, 948 0, 0, 0, 0) != 0) 949 msgmni = 0; 950 sbuf_printf(sb, "%i\n", msgmni); 951 952 return (0); 953} 954 955/* 956 * Filler function for proc/sys/kernel/pid_max 957 */ 958static int 959linprocfs_dopid_max(PFS_FILL_ARGS) 960{ 961 962 sbuf_printf(sb, "%i\n", PID_MAX); 963 964 return (0); 965} 966 967/* 968 * Filler function for proc/sys/kernel/sem 969 */ 970static int 971linprocfs_dosem(PFS_FILL_ARGS) 972{ 973 int semmsl, semmns, semopm, semmni; 974 size_t size; 975 976 /* Field 1: SEMMSL */ 977 size = sizeof(semmsl); 978 if (kernel_sysctlbyname(td, "kern.ipc.semmsl", &semmsl, &size, 979 0, 0, 0, 0) != 0) 980 semmsl = 0; 981 982 /* Field 2: SEMMNS */ 983 size = sizeof(semmns); 984 if (kernel_sysctlbyname(td, "kern.ipc.semmns", &semmns, &size, 985 0, 0, 0, 0) != 0) 986 semmns = 0; 987 988 /* Field 3: SEMOPM */ 989 size = sizeof(semopm); 990 if (kernel_sysctlbyname(td, "kern.ipc.semopm", &semopm, &size, 991 0, 0, 0, 0) != 0) 992 semopm = 0; 993 994 /* Field 4: SEMMNI */ 995 size = sizeof(semmni); 996 if (kernel_sysctlbyname(td, "kern.ipc.semmni", &semmni, &size, 997 0, 0, 0, 0) != 0) 998 semmni = 0; 999 1000 sbuf_printf(sb, "%i %i %i %i\n", semmsl, semmns, semopm, semmni); 1001 1002 return (0); 1003} 1004 1005/* 1006 * Filler function for proc/scsi/device_info 1007 */ 1008static int 1009linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1010{ 1011 return (0); 1012} 1013 1014/* 1015 * Filler function for proc/scsi/scsi 1016 */ 1017static int 1018linprocfs_doscsiscsi(PFS_FILL_ARGS) 1019{ 1020 return (0); 1021} 1022 1023extern struct cdevsw *cdevsw[]; 1024 1025/* 1026 * Filler function for proc/devices 1027 */ 1028static int 1029linprocfs_dodevices(PFS_FILL_ARGS) 1030{ 1031 char *char_devices; 1032 sbuf_printf(sb, "Character devices:\n"); 1033 1034 char_devices = linux_get_char_devices(); 1035 sbuf_printf(sb, "%s", char_devices); 1036 linux_free_get_char_devices(char_devices); 1037 1038 sbuf_printf(sb, "\nBlock devices:\n"); 1039 1040 return (0); 1041} 1042 1043/* 1044 * Filler function for proc/cmdline 1045 */ 1046static int 1047linprocfs_docmdline(PFS_FILL_ARGS) 1048{ 1049 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1050 sbuf_printf(sb, " ro root=302\n"); 1051 return (0); 1052} 1053 1054#if 0 1055/* 1056 * Filler function for proc/modules 1057 */ 1058static int 1059linprocfs_domodules(PFS_FILL_ARGS) 1060{ 1061 struct linker_file *lf; 1062 1063 TAILQ_FOREACH(lf, &linker_files, link) { 1064 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1065 (unsigned long)lf->size, lf->refs); 1066 } 1067 return (0); 1068} 1069#endif 1070 1071/* 1072 * Constructor 1073 */ 1074static int 1075linprocfs_init(PFS_INIT_ARGS) 1076{ 1077 struct pfs_node *root; 1078 struct pfs_node *dir; 1079 1080 root = pi->pi_root; 1081 1082 /* /proc/... */ 1083 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1084 NULL, NULL, PFS_RD); 1085 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1086 NULL, NULL, PFS_RD); 1087 pfs_create_file(root, "devices", &linprocfs_dodevices, 1088 NULL, NULL, PFS_RD); 1089 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1090 NULL, NULL, PFS_RD); 1091 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1092 NULL, NULL, PFS_RD); 1093#if 0 1094 pfs_create_file(root, "modules", &linprocfs_domodules, 1095 NULL, NULL, PFS_RD); 1096#endif 1097 pfs_create_file(root, "mounts", &linprocfs_domtab, 1098 NULL, NULL, PFS_RD); 1099 pfs_create_file(root, "mtab", &linprocfs_domtab, 1100 NULL, NULL, PFS_RD); 1101 pfs_create_link(root, "self", &procfs_docurproc, 1102 NULL, NULL, 0); 1103 pfs_create_file(root, "stat", &linprocfs_dostat, 1104 NULL, NULL, PFS_RD); 1105 pfs_create_file(root, "uptime", &linprocfs_douptime, 1106 NULL, NULL, PFS_RD); 1107 pfs_create_file(root, "version", &linprocfs_doversion, 1108 NULL, NULL, PFS_RD); 1109 1110 /* /proc/net/... */ 1111 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 1112 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1113 NULL, NULL, PFS_RD); 1114 1115 /* /proc/<pid>/... */ 1116 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 1117 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1118 NULL, NULL, PFS_RD); 1119 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1120 NULL, NULL, 0); 1121 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1122 NULL, NULL, PFS_RD); 1123 pfs_create_link(dir, "exe", &procfs_doprocfile, 1124 NULL, &procfs_notsystem, 0); 1125 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1126 NULL, NULL, PFS_RD); 1127 pfs_create_file(dir, "mem", &procfs_doprocmem, 1128 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1129 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1130 NULL, NULL, 0); 1131 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1132 NULL, NULL, PFS_RD); 1133 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1134 NULL, NULL, PFS_RD); 1135 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1136 NULL, NULL, PFS_RD); 1137 1138 /* /proc/scsi/... */ 1139 dir = pfs_create_dir(root, "scsi", NULL, NULL, 0); 1140 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1141 NULL, NULL, PFS_RD); 1142 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1143 NULL, NULL, PFS_RD); 1144 1145 /* /proc/sys/... */ 1146 dir = pfs_create_dir(root, "sys", NULL, NULL, 0); 1147 /* /proc/sys/kernel/... */ 1148 dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0); 1149 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1150 NULL, NULL, PFS_RD); 1151 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1152 NULL, NULL, PFS_RD); 1153 pfs_create_file(dir, "sem", &linprocfs_dosem, 1154 NULL, NULL, PFS_RD); 1155 1156 return (0); 1157} 1158 1159/* 1160 * Destructor 1161 */ 1162static int 1163linprocfs_uninit(PFS_INIT_ARGS) 1164{ 1165 1166 /* nothing to do, pseudofs will GC */ 1167 return (0); 1168} 1169 1170PSEUDOFS(linprocfs, 1); 1171MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1172MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1173