linprocfs.c revision 85657
159412Smsmith/* 265577Sdes * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav 365577Sdes * Copyright (c) 1999 Pierre Beyssac 459412Smsmith * Copyright (c) 1993 Jan-Simon Pendry 559412Smsmith * Copyright (c) 1993 659412Smsmith * The Regents of the University of California. All rights reserved. 759412Smsmith * 859412Smsmith * This code is derived from software contributed to Berkeley by 959412Smsmith * Jan-Simon Pendry. 1059412Smsmith * 1159412Smsmith * Redistribution and use in source and binary forms, with or without 1259412Smsmith * modification, are permitted provided that the following conditions 1359412Smsmith * are met: 1459412Smsmith * 1. Redistributions of source code must retain the above copyright 1559412Smsmith * notice, this list of conditions and the following disclaimer. 1659412Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1759412Smsmith * notice, this list of conditions and the following disclaimer in the 1859412Smsmith * documentation and/or other materials provided with the distribution. 1959412Smsmith * 3. All advertising materials mentioning features or use of this software 2059412Smsmith * must display the following acknowledgement: 2159412Smsmith * This product includes software developed by the University of 2259412Smsmith * California, Berkeley and its contributors. 2359412Smsmith * 4. Neither the name of the University nor the names of its contributors 2459412Smsmith * may be used to endorse or promote products derived from this software 2559412Smsmith * without specific prior written permission. 2659412Smsmith * 2759412Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2859412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2959412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3059412Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3159412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3259412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3359412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3459412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3559412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3659412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3759412Smsmith * SUCH DAMAGE. 3859412Smsmith * 3959412Smsmith * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 4059412Smsmith * 4159412Smsmith * $FreeBSD: head/sys/compat/linprocfs/linprocfs.c 85657 2001-10-29 02:17:41Z dillon $ 4259412Smsmith */ 4359412Smsmith 4459412Smsmith#include <sys/param.h> 4583926Sdes#include <sys/queue.h> 4676166Smarkm#include <sys/blist.h> 4774135Sjlemon#include <sys/conf.h> 4865633Sdes#include <sys/dkstat.h> 4983926Sdes#include <sys/exec.h> 5076166Smarkm#include <sys/jail.h> 5165633Sdes#include <sys/kernel.h> 5283926Sdes#include <sys/linker.h> 5376166Smarkm#include <sys/lock.h> 5474135Sjlemon#include <sys/malloc.h> 5578025Sdes#include <sys/mount.h> 5676827Salfred#include <sys/mutex.h> 5785289Sdes#include <sys/namei.h> 5865633Sdes#include <sys/proc.h> 5965633Sdes#include <sys/resourcevar.h> 6069995Sdes#include <sys/sbuf.h> 6183926Sdes#include <sys/socket.h> 6276839Sjlemon#include <sys/sysctl.h> 6383926Sdes#include <sys/systm.h> 6465633Sdes#include <sys/tty.h> 6583926Sdes#include <sys/user.h> 6683926Sdes#include <sys/vmmeter.h> 6759412Smsmith#include <sys/vnode.h> 6859412Smsmith 6983926Sdes#include <net/if.h> 7083926Sdes 7159412Smsmith#include <vm/vm.h> 7259412Smsmith#include <vm/pmap.h> 7367588Sdes#include <vm/vm_map.h> 7459412Smsmith#include <vm/vm_param.h> 7560860Sdes#include <vm/vm_object.h> 7669995Sdes#include <vm/vm_zone.h> 7759412Smsmith#include <vm/swap_pager.h> 7869799Sdes 7967589Sdes#include <machine/clock.h> 8078113Sdes 8178113Sdes#ifdef __alpha__ 8278113Sdes#include <machine/alpha_cpu.h> 8378113Sdes#include <machine/cpuconf.h> 8478113Sdes#include <machine/rpb.h> 8578113Sdesextern int ncpus; 8678113Sdes#endif /* __alpha__ */ 8778113Sdes 8878113Sdes#ifdef __i386__ 8967589Sdes#include <machine/cputypes.h> 9059412Smsmith#include <machine/md_var.h> 9178113Sdes#endif /* __i386__ */ 9259412Smsmith 9385129Sdes#include <compat/linux/linux_ioctl.h> 9469995Sdes#include <compat/linux/linux_mib.h> 9585289Sdes#include <compat/linux/linux_util.h> 9678025Sdes#include <fs/pseudofs/pseudofs.h> 9784248Sdes#include <fs/procfs/procfs.h> 9859412Smsmith 9967588Sdes/* 10067588Sdes * Various conversion macros 10167588Sdes */ 10276405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10367588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10467588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10569799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10667588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10767588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10874135Sjlemon 10978113Sdes/* 11078113Sdes * Filler function for proc/meminfo 11178113Sdes */ 11278025Sdesstatic int 11378025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 11459412Smsmith{ 11559412Smsmith unsigned long memtotal; /* total memory in bytes */ 11659412Smsmith unsigned long memused; /* used memory in bytes */ 11759412Smsmith unsigned long memfree; /* free memory in bytes */ 11859412Smsmith unsigned long memshared; /* shared memory ??? */ 11959412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 12076839Sjlemon u_quad_t swaptotal; /* total swap space in bytes */ 12176839Sjlemon u_quad_t swapused; /* used swap space in bytes */ 12276839Sjlemon u_quad_t swapfree; /* free swap space in bytes */ 12360860Sdes vm_object_t object; 12459412Smsmith 12559412Smsmith memtotal = physmem * PAGE_SIZE; 12659412Smsmith /* 12759412Smsmith * The correct thing here would be: 12859412Smsmith * 12959412Smsmith memfree = cnt.v_free_count * PAGE_SIZE; 13059412Smsmith memused = memtotal - memfree; 13159412Smsmith * 13259412Smsmith * but it might mislead linux binaries into thinking there 13359412Smsmith * is very little memory left, so we cheat and tell them that 13459412Smsmith * all memory that isn't wired down is free. 13559412Smsmith */ 13659412Smsmith memused = cnt.v_wire_count * PAGE_SIZE; 13759412Smsmith memfree = memtotal - memused; 13864560Sbde if (swapblist == NULL) { 13964560Sbde swaptotal = 0; 14064560Sbde swapfree = 0; 14164560Sbde } else { 14276839Sjlemon swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */ 14376839Sjlemon swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 14464560Sbde } 14559412Smsmith swapused = swaptotal - swapfree; 14660860Sdes memshared = 0; 14771471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 14860860Sdes if (object->shadow_count > 1) 14960860Sdes memshared += object->resident_page_count; 15060860Sdes memshared *= PAGE_SIZE; 15159412Smsmith /* 15259412Smsmith * We'd love to be able to write: 15359412Smsmith * 15459412Smsmith buffers = bufspace; 15559412Smsmith * 15659412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 15759412Smsmith * like unstaticizing it just for linprocfs's sake. 15859412Smsmith */ 15959412Smsmith buffers = 0; 16059412Smsmith cached = cnt.v_cache_count * PAGE_SIZE; 16159412Smsmith 16278025Sdes sbuf_printf(sb, 16378031Sdes " total: used: free: shared: buffers: cached:\n" 16469799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 16576839Sjlemon "Swap: %llu %llu %llu\n" 16669799Sdes "MemTotal: %9lu kB\n" 16769799Sdes "MemFree: %9lu kB\n" 16869799Sdes "MemShared:%9lu kB\n" 16969799Sdes "Buffers: %9lu kB\n" 17069799Sdes "Cached: %9lu kB\n" 17176839Sjlemon "SwapTotal:%9llu kB\n" 17276839Sjlemon "SwapFree: %9llu kB\n", 17369799Sdes memtotal, memused, memfree, memshared, buffers, cached, 17469799Sdes swaptotal, swapused, swapfree, 17569799Sdes B2K(memtotal), B2K(memfree), 17669799Sdes B2K(memshared), B2K(buffers), B2K(cached), 17769799Sdes B2K(swaptotal), B2K(swapfree)); 17859412Smsmith 17978025Sdes return (0); 18059412Smsmith} 18159412Smsmith 18278113Sdes#ifdef __alpha__ 18378113Sdes/* 18478113Sdes * Filler function for proc/cpuinfo (Alpha version) 18578113Sdes */ 18678025Sdesstatic int 18778025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 18859412Smsmith{ 18978113Sdes u_int64_t type, major; 19078113Sdes struct pcs *pcsp; 19178113Sdes const char *model, *sysname; 19278113Sdes 19378113Sdes static const char *cpuname[] = { 19478113Sdes "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", 19578113Sdes "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" 19678113Sdes }; 19778113Sdes 19878113Sdes pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 19978113Sdes type = pcsp->pcs_proc_type; 20078113Sdes major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; 20178113Sdes if (major < sizeof(cpuname)/sizeof(char *)) { 20278113Sdes model = cpuname[major - 1]; 20378113Sdes } else { 20478113Sdes model = "unknown"; 20578113Sdes } 20678113Sdes 20778113Sdes sysname = alpha_dsr_sysname(); 20878113Sdes 20978113Sdes sbuf_printf(sb, 21078113Sdes "cpu\t\t\t: Alpha\n" 21178113Sdes "cpu model\t\t: %s\n" 21278113Sdes "cpu variation\t\t: %ld\n" 21378113Sdes "cpu revision\t\t: %ld\n" 21478113Sdes "cpu serial number\t: %s\n" 21578113Sdes "system type\t\t: %s\n" 21678113Sdes "system variation\t: %s\n" 21778113Sdes "system revision\t\t: %ld\n" 21878113Sdes "system serial number\t: %s\n" 21978113Sdes "cycle frequency [Hz]\t: %lu\n" 22078113Sdes "timer frequency [Hz]\t: %lu\n" 22178113Sdes "page size [bytes]\t: %ld\n" 22278113Sdes "phys. address bits\t: %ld\n" 22378113Sdes "max. addr. space #\t: %ld\n" 22478113Sdes "BogoMIPS\t\t: %lu.%02lu\n" 22578113Sdes "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 22678113Sdes "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 22778113Sdes "platform string\t\t: %s\n" 22878113Sdes "cpus detected\t\t: %d\n" 22978113Sdes , 23078113Sdes model, 23178113Sdes pcsp->pcs_proc_var, 23278113Sdes *(int *)hwrpb->rpb_revision, 23378113Sdes " ", 23478113Sdes " ", 23578113Sdes "0", 23678113Sdes 0, 23778113Sdes " ", 23878113Sdes hwrpb->rpb_cc_freq, 23978113Sdes hz, 24078113Sdes hwrpb->rpb_page_size, 24178113Sdes hwrpb->rpb_phys_addr_size, 24278113Sdes hwrpb->rpb_max_asn, 24378113Sdes 0, 0, 24478113Sdes 0, 0, 0, 24578113Sdes 0, 0, 0, 24678113Sdes sysname, 24778113Sdes ncpus); 24878113Sdes return (0); 24978113Sdes} 25078113Sdes#endif /* __alpha__ */ 25178113Sdes 25278113Sdes#ifdef __i386__ 25378113Sdes/* 25478113Sdes * Filler function for proc/cpuinfo (i386 version) 25578113Sdes */ 25678113Sdesstatic int 25778113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 25878113Sdes{ 25969799Sdes int class, i, fqmhz, fqkhz; 26059412Smsmith 26169799Sdes /* 26278031Sdes * We default the flags to include all non-conflicting flags, 26378031Sdes * and the Intel versions of conflicting flags. 26469799Sdes */ 26578031Sdes static char *flags[] = { 26678031Sdes "fpu", "vme", "de", "pse", "tsc", 26778031Sdes "msr", "pae", "mce", "cx8", "apic", 26878031Sdes "sep", "sep", "mtrr", "pge", "mca", 26978031Sdes "cmov", "pat", "pse36", "pn", "b19", 27078031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 27178031Sdes "xmm", "b26", "b27", "b28", "b29", 27267589Sdes "3dnowext", "3dnow" 27367589Sdes }; 27467589Sdes 27559412Smsmith switch (cpu_class) { 27659412Smsmith case CPUCLASS_286: 27767589Sdes class = 2; 27859412Smsmith break; 27959412Smsmith case CPUCLASS_386: 28067589Sdes class = 3; 28159412Smsmith break; 28259412Smsmith case CPUCLASS_486: 28367589Sdes class = 4; 28459412Smsmith break; 28559412Smsmith case CPUCLASS_586: 28667589Sdes class = 5; 28759412Smsmith break; 28859412Smsmith case CPUCLASS_686: 28967589Sdes class = 6; 29059412Smsmith break; 29159412Smsmith default: 29278031Sdes class = 0; 29359412Smsmith break; 29459412Smsmith } 29559412Smsmith 29678025Sdes sbuf_printf(sb, 29778031Sdes "processor\t: %d\n" 29869799Sdes "vendor_id\t: %.20s\n" 29969799Sdes "cpu family\t: %d\n" 30069799Sdes "model\t\t: %d\n" 30169799Sdes "stepping\t: %d\n", 30269799Sdes 0, cpu_vendor, class, cpu, cpu_id & 0xf); 30359412Smsmith 30478031Sdes sbuf_cat(sb, 30578031Sdes "flags\t\t:"); 30667589Sdes 30778031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 30867589Sdes flags[16] = "fcmov"; 30978031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 31067589Sdes flags[24] = "cxmmx"; 31178031Sdes } 31278031Sdes 31378031Sdes for (i = 0; i < 32; i++) 31467589Sdes if (cpu_feature & (1 << i)) 31578025Sdes sbuf_printf(sb, " %s", flags[i]); 31678025Sdes sbuf_cat(sb, "\n"); 31778031Sdes if (class >= 5) { 31869799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 31969799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 32078025Sdes sbuf_printf(sb, 32169799Sdes "cpu MHz\t\t: %d.%02d\n" 32269799Sdes "bogomips\t: %d.%02d\n", 32369799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 32478031Sdes } 32569995Sdes 32678025Sdes return (0); 32759412Smsmith} 32878113Sdes#endif /* __i386__ */ 32965633Sdes 33078113Sdes/* 33185289Sdes * Filler function for proc/mtab 33285289Sdes * 33385289Sdes * This file doesn't exist in Linux' procfs, but is included here so 33485289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 33585289Sdes */ 33685289Sdesstatic int 33785289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 33885289Sdes{ 33985289Sdes struct nameidata nd; 34085289Sdes struct mount *mp; 34185289Sdes char *lep, *flep, *mntto, *mntfrom, *fstype; 34285289Sdes size_t lep_len; 34385289Sdes int error; 34485289Sdes 34585289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 34685289Sdes NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 34785289Sdes flep = NULL; 34885289Sdes if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1) 34985289Sdes lep = linux_emul_path; 35085289Sdes lep_len = strlen(lep); 35185289Sdes 35285289Sdes mtx_lock(&mountlist_mtx); 35385289Sdes error = 0; 35485289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 35585289Sdes error = VFS_STATFS(mp, &mp->mnt_stat, td); 35685289Sdes if (error) 35785289Sdes break; 35885289Sdes 35985289Sdes /* determine device name */ 36085289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 36185289Sdes 36285289Sdes /* determine mount point */ 36385289Sdes mntto = mp->mnt_stat.f_mntonname; 36485289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 36585289Sdes mntto[lep_len] == '/') 36685289Sdes mntto += lep_len; 36785289Sdes 36885289Sdes /* determine fs type */ 36985289Sdes fstype = mp->mnt_stat.f_fstypename; 37085289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 37185289Sdes mntfrom = fstype = "proc"; 37285289Sdes else if (strcmp(fstype, "procfs") == 0) 37385289Sdes continue; 37485289Sdes 37585289Sdes sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 37685289Sdes mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 37785289Sdes#define ADD_OPTION(opt, name) \ 37885289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 37985289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 38085289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 38185289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 38285289Sdes ADD_OPTION(MNT_NODEV, "nodev"); 38385289Sdes ADD_OPTION(MNT_UNION, "union"); 38485289Sdes ADD_OPTION(MNT_ASYNC, "async"); 38585289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 38685289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 38785289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 38885289Sdes#undef ADD_OPTION 38985289Sdes /* a real Linux mtab will also show NFS options */ 39085289Sdes sbuf_printf(sb, " 0 0\n"); 39185289Sdes } 39285289Sdes mtx_unlock(&mountlist_mtx); 39385289Sdes if (flep != NULL) 39485289Sdes free(flep, M_TEMP); 39585289Sdes return (error); 39685289Sdes} 39785289Sdes 39885289Sdes/* 39978113Sdes * Filler function for proc/stat 40078113Sdes */ 40178025Sdesstatic int 40278025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 40365633Sdes{ 40478025Sdes sbuf_printf(sb, 40569799Sdes "cpu %ld %ld %ld %ld\n" 40669799Sdes "disk 0 0 0 0\n" 40769799Sdes "page %u %u\n" 40869799Sdes "swap %u %u\n" 40969799Sdes "intr %u\n" 41069799Sdes "ctxt %u\n" 41185657Sdillon "btime %lld\n", 41269799Sdes T2J(cp_time[CP_USER]), 41369799Sdes T2J(cp_time[CP_NICE]), 41469799Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 41569799Sdes T2J(cp_time[CP_IDLE]), 41669799Sdes cnt.v_vnodepgsin, 41769799Sdes cnt.v_vnodepgsout, 41869799Sdes cnt.v_swappgsin, 41969799Sdes cnt.v_swappgsout, 42069799Sdes cnt.v_intr, 42169799Sdes cnt.v_swtch, 42285657Sdillon (quad_t)boottime.tv_sec); 42378025Sdes return (0); 42465633Sdes} 42565633Sdes 42678113Sdes/* 42778113Sdes * Filler function for proc/uptime 42878113Sdes */ 42978025Sdesstatic int 43078025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 43165633Sdes{ 43265633Sdes struct timeval tv; 43365633Sdes 43465633Sdes getmicrouptime(&tv); 43585657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 43685657Sdillon (quad_t)tv.tv_sec, tv.tv_usec / 10000, 43769799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43878025Sdes return (0); 43965633Sdes} 44065633Sdes 44178113Sdes/* 44278113Sdes * Filler function for proc/version 44378113Sdes */ 44478025Sdesstatic int 44578025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 44665633Sdes{ 44778025Sdes sbuf_printf(sb, 44869995Sdes "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 44969995Sdes " #4 Sun Dec 18 04:30:00 CET 1977\n", 45083366Sjulian linux_get_osname(td->td_proc), 45183366Sjulian linux_get_osrelease(td->td_proc)); 45278025Sdes return (0); 45365633Sdes} 45465633Sdes 45578113Sdes/* 45678113Sdes * Filler function for proc/loadavg 45778113Sdes */ 45878025Sdesstatic int 45978025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 46076839Sjlemon{ 46178025Sdes sbuf_printf(sb, 46276839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 46376839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 46476839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 46576839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 46676839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 46776839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 46876839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 46976839Sjlemon 1, /* number of running tasks */ 47076839Sjlemon nprocs, /* number of tasks */ 47178116Sdes lastpid /* the last pid */ 47276839Sjlemon ); 47378025Sdes 47478025Sdes return (0); 47576839Sjlemon} 47676839Sjlemon 47778113Sdes/* 47878113Sdes * Filler function for proc/pid/stat 47978113Sdes */ 48078025Sdesstatic int 48178025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 48267588Sdes{ 48369995Sdes struct kinfo_proc kp; 48467588Sdes 48569995Sdes fill_kinfo_proc(p, &kp); 48678025Sdes sbuf_printf(sb, "%d", p->p_pid); 48778025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 48867588Sdes PS_ADD("comm", "(%s)", p->p_comm); 48967588Sdes PS_ADD("statr", "%c", '0'); /* XXX */ 49073923Sjhb PROC_LOCK(p); 49173923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 49273923Sjhb PROC_UNLOCK(p); 49367588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 49467588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 49567588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 49667588Sdes PS_ADD("tpgid", "%d", 0); /* XXX */ 49767588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 49867588Sdes PS_ADD("minflt", "%u", 0); /* XXX */ 49967588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50067588Sdes PS_ADD("majflt", "%u", 0); /* XXX */ 50167588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50267588Sdes PS_ADD("utime", "%d", 0); /* XXX */ 50367588Sdes PS_ADD("stime", "%d", 0); /* XXX */ 50467588Sdes PS_ADD("cutime", "%d", 0); /* XXX */ 50567588Sdes PS_ADD("cstime", "%d", 0); /* XXX */ 50667588Sdes PS_ADD("counter", "%d", 0); /* XXX */ 50767588Sdes PS_ADD("priority", "%d", 0); /* XXX */ 50867588Sdes PS_ADD("timeout", "%u", 0); /* XXX */ 50967588Sdes PS_ADD("itrealvalue", "%u", 0); /* XXX */ 51067588Sdes PS_ADD("starttime", "%d", 0); /* XXX */ 51169995Sdes PS_ADD("vsize", "%u", kp.ki_size); 51269995Sdes PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 51367588Sdes PS_ADD("rlim", "%u", 0); /* XXX */ 51469995Sdes PS_ADD("startcode", "%u", (unsigned)0); 51567588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 51667588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 51769799Sdes PS_ADD("esp", "%u", 0); /* XXX */ 51869799Sdes PS_ADD("eip", "%u", 0); /* XXX */ 51967588Sdes PS_ADD("signal", "%d", 0); /* XXX */ 52067588Sdes PS_ADD("blocked", "%d", 0); /* XXX */ 52167588Sdes PS_ADD("sigignore", "%d", 0); /* XXX */ 52267588Sdes PS_ADD("sigcatch", "%d", 0); /* XXX */ 52367588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 52469799Sdes PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 52569799Sdes PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 52669799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 52769799Sdes PS_ADD("processor", "%d", 0); /* XXX */ 52867588Sdes#undef PS_ADD 52978025Sdes sbuf_putc(sb, '\n'); 53067588Sdes 53178025Sdes return (0); 53267588Sdes} 53367588Sdes 53467588Sdes/* 53567588Sdes * Map process state to descriptive letter. Note that this does not 53667588Sdes * quite correspond to what Linux outputs, but it's close enough. 53767588Sdes */ 53867588Sdesstatic char *state_str[] = { 53967588Sdes "? (unknown)", 54067588Sdes "I (idle)", 54167588Sdes "R (running)", 54267588Sdes "S (sleeping)", 54367588Sdes "T (stopped)", 54467588Sdes "Z (zombie)", 54567588Sdes "W (waiting)", 54667588Sdes "M (mutex)" 54767588Sdes}; 54867588Sdes 54978113Sdes/* 55078113Sdes * Filler function for proc/pid/status 55178113Sdes */ 55278025Sdesstatic int 55378025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 55467588Sdes{ 55569995Sdes struct kinfo_proc kp; 55667588Sdes char *state; 55769799Sdes segsz_t lsize; 55874135Sjlemon int i; 55967588Sdes 56072200Sbmilekic mtx_lock_spin(&sched_lock); 56167588Sdes if (p->p_stat > sizeof state_str / sizeof *state_str) 56267588Sdes state = state_str[0]; 56367588Sdes else 56467588Sdes state = state_str[(int)p->p_stat]; 56572200Sbmilekic mtx_unlock_spin(&sched_lock); 56667588Sdes 56769995Sdes fill_kinfo_proc(p, &kp); 56878025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 56978031Sdes sbuf_printf(sb, "State:\t%s\n", state); 57067588Sdes 57167588Sdes /* 57267588Sdes * Credentials 57367588Sdes */ 57478025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 57571471Sjhb PROC_LOCK(p); 57678025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 57773923Sjhb p->p_pptr->p_pid : 0); 57878031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 57978031Sdes p->p_ucred->cr_uid, 58078031Sdes p->p_ucred->cr_svuid, 58178031Sdes /* FreeBSD doesn't have fsuid */ 58278031Sdes p->p_ucred->cr_uid); 58378031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 58478031Sdes p->p_ucred->cr_gid, 58578031Sdes p->p_ucred->cr_svgid, 58678031Sdes /* FreeBSD doesn't have fsgid */ 58778031Sdes p->p_ucred->cr_gid); 58878025Sdes sbuf_cat(sb, "Groups:\t"); 58967588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 59078031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 59171471Sjhb PROC_UNLOCK(p); 59278025Sdes sbuf_putc(sb, '\n'); 59367588Sdes 59467588Sdes /* 59567588Sdes * Memory 59669799Sdes * 59769799Sdes * While our approximation of VmLib may not be accurate (I 59869799Sdes * don't know of a simple way to verify it, and I'm not sure 59969799Sdes * it has much meaning anyway), I believe it's good enough. 60069799Sdes * 60169799Sdes * The same code that could (I think) accurately compute VmLib 60269799Sdes * could also compute VmLck, but I don't really care enough to 60369799Sdes * implement it. Submissions are welcome. 60467588Sdes */ 60578025Sdes sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 60678025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 60778025Sdes sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 60878025Sdes sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 60978025Sdes sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 61078025Sdes sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 61169995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 61269995Sdes kp.ki_ssize - kp.ki_tsize - 1; 61378025Sdes sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 61467588Sdes 61567588Sdes /* 61667588Sdes * Signal masks 61767588Sdes * 61867588Sdes * We support up to 128 signals, while Linux supports 32, 61967588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 62067588Sdes * just show the lower 32 bits of each mask. XXX hack. 62167588Sdes * 62267588Sdes * NB: on certain platforms (Sparc at least) Linux actually 62367588Sdes * supports 64 signals, but this code is a long way from 62467588Sdes * running on anything but i386, so ignore that for now. 62567588Sdes */ 62671471Sjhb PROC_LOCK(p); 62778025Sdes sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 62869799Sdes /* 62969799Sdes * I can't seem to find out where the signal mask is in 63069799Sdes * relation to struct proc, so SigBlk is left unimplemented. 63169799Sdes */ 63278025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 63378025Sdes sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 63478025Sdes sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 63571471Sjhb PROC_UNLOCK(p); 63667588Sdes 63767588Sdes /* 63867588Sdes * Linux also prints the capability masks, but we don't have 63967588Sdes * capabilities yet, and when we do get them they're likely to 64067588Sdes * be meaningless to Linux programs, so we lie. XXX 64167588Sdes */ 64278025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 64378025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 64478025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 64578025Sdes 64678025Sdes return (0); 64767588Sdes} 64874135Sjlemon 64978113Sdes/* 65078113Sdes * Filler function for proc/self 65178113Sdes */ 65278025Sdesstatic int 65378025Sdeslinprocfs_doselflink(PFS_FILL_ARGS) 65474135Sjlemon{ 65583366Sjulian sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid); 65678025Sdes return (0); 65774135Sjlemon} 65874135Sjlemon 65978113Sdes/* 66078113Sdes * Filler function for proc/pid/cmdline 66178113Sdes */ 66278025Sdesstatic int 66378113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 66478113Sdes{ 66578113Sdes struct ps_strings pstr; 66678113Sdes int error, i; 66778113Sdes 66878113Sdes /* 66978113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 67078113Sdes * revert back to the old way which only implements full cmdline 67178113Sdes * for the currept process and just p->p_comm for all other 67278113Sdes * processes. 67378113Sdes * Note that if the argv is no longer available, we deliberately 67478113Sdes * don't fall back on p->p_comm or return an error: the authentic 67578113Sdes * Linux behaviour is to return zero-length in this case. 67678113Sdes */ 67778113Sdes 67883366Sjulian if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) { 67978113Sdes sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 68083366Sjulian } else if (p != td->td_proc) { 68178113Sdes sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 68278113Sdes } else { 68378113Sdes error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); 68478113Sdes if (error) 68578113Sdes return (error); 68678113Sdes for (i = 0; i < pstr.ps_nargvstr; i++) { 68778113Sdes sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 68878113Sdes sbuf_printf(sb, "%c", '\0'); 68978113Sdes } 69078113Sdes } 69178113Sdes 69278113Sdes return (0); 69378113Sdes} 69478113Sdes 69578113Sdes/* 69678113Sdes * Filler function for proc/pid/exe 69778113Sdes */ 69878113Sdesstatic int 69985129Sdeslinprocfs_doprocexe(PFS_FILL_ARGS) 70074135Sjlemon{ 70174135Sjlemon char *fullpath = "unknown"; 70274135Sjlemon char *freepath = NULL; 70374135Sjlemon 70485289Sdes vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath); 70578025Sdes sbuf_printf(sb, "%s", fullpath); 70674135Sjlemon if (freepath) 70774135Sjlemon free(freepath, M_TEMP); 70878025Sdes return (0); 70974135Sjlemon} 71074135Sjlemon 71178113Sdes/* 71278113Sdes * Filler function for proc/net/dev 71378113Sdes */ 71478025Sdesstatic int 71578025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 71674135Sjlemon{ 71785129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 71874135Sjlemon struct ifnet *ifp; 71974135Sjlemon 72085129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 72183926Sdes "Inter-", " Receive", " Transmit", " face", 72285129Sdes "bytes packets errs drop fifo frame compressed", 72383926Sdes "bytes packets errs drop fifo frame compressed"); 72474135Sjlemon 72574135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 72685129Sdes linux_ifname(ifp, ifname, sizeof ifname); 72785129Sdes sbuf_printf(sb, "%6.6s:", ifname); 72883926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 72983926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 73083926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 73183926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 73274135Sjlemon } 73378025Sdes 73478025Sdes return (0); 73574135Sjlemon} 73674135Sjlemon 73785538Sphk#if 0 73885538Sphkextern struct cdevsw *cdevsw[]; 73985538Sphk 74078113Sdes/* 74178113Sdes * Filler function for proc/devices 74278113Sdes */ 74378025Sdesstatic int 74478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 74574135Sjlemon{ 74674135Sjlemon int i; 74774135Sjlemon 74878025Sdes sbuf_printf(sb, "Character devices:\n"); 74974135Sjlemon 75078025Sdes for (i = 0; i < NUMCDEVSW; i++) 75174135Sjlemon if (cdevsw[i] != NULL) 75278025Sdes sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 75374135Sjlemon 75478025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 75578025Sdes 75678025Sdes return (0); 75774135Sjlemon} 75885538Sphk#endif 75974135Sjlemon 76078113Sdes/* 76178113Sdes * Filler function for proc/cmdline 76278113Sdes */ 76378025Sdesstatic int 76478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 76574135Sjlemon{ 76678025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 76778025Sdes sbuf_printf(sb, " ro root=302\n"); 76878025Sdes return (0); 76978025Sdes} 77074135Sjlemon 77183926Sdes#if 0 77278025Sdes/* 77383926Sdes * Filler function for proc/modules 77483926Sdes */ 77583926Sdesstatic int 77683926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 77783926Sdes{ 77883926Sdes struct linker_file *lf; 77983926Sdes 78083926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 78183926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 78283926Sdes (unsigned long)lf->size, lf->refs); 78383926Sdes } 78483926Sdes return (0); 78583926Sdes} 78683926Sdes#endif 78783926Sdes 78883926Sdes/* 78985129Sdes * Constructor 79078025Sdes */ 79185129Sdesstatic int 79285129Sdeslinprocfs_init(PFS_INIT_ARGS) 79385129Sdes{ 79485129Sdes struct pfs_node *root; 79585129Sdes struct pfs_node *dir; 79674135Sjlemon 79785129Sdes root = pi->pi_root; 79878025Sdes 79985129Sdes#define PFS_CREATE_FILE(name) \ 80085129Sdes pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 80185129Sdes PFS_CREATE_FILE(cmdline); 80285129Sdes PFS_CREATE_FILE(cpuinfo); 80385538Sphk#if 0 80485129Sdes PFS_CREATE_FILE(devices); 80585538Sphk#endif 80685129Sdes PFS_CREATE_FILE(loadavg); 80785129Sdes PFS_CREATE_FILE(meminfo); 80883926Sdes#if 0 80985129Sdes PFS_CREATE_FILE(modules); 81083926Sdes#endif 81185289Sdes PFS_CREATE_FILE(mtab); 81285129Sdes PFS_CREATE_FILE(stat); 81385129Sdes PFS_CREATE_FILE(uptime); 81485129Sdes PFS_CREATE_FILE(version); 81585129Sdes#undef PFS_CREATE_FILE 81685129Sdes pfs_create_link(root, "self", &linprocfs_doselflink, 81785129Sdes NULL, NULL, 0); 81878025Sdes 81985129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 82085129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 82185129Sdes NULL, NULL, PFS_RD); 82278025Sdes 82385129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 82485129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 82585129Sdes NULL, NULL, PFS_RD); 82685129Sdes pfs_create_link(dir, "exe", &linprocfs_doprocexe, 82785129Sdes NULL, NULL, 0); 82885130Sdes#if 0 82985129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 83085129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 83185130Sdes#endif 83285129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 83385129Sdes NULL, NULL, PFS_RD); 83485129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 83585129Sdes NULL, NULL, PFS_RD); 83685129Sdes 83785129Sdes return (0); 83885129Sdes} 83985129Sdes 84085129Sdes/* 84185129Sdes * Destructor 84285129Sdes */ 84385129Sdesstatic int 84485129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 84585129Sdes{ 84685129Sdes 84785129Sdes /* nothing to do, pseudofs will GC */ 84885129Sdes return (0); 84985129Sdes} 85085129Sdes 85185129SdesPSEUDOFS(linprocfs, 1); 85278025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 85378025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 854