linprocfs.c revision 116173
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 42116173Sobrien#include <sys/cdefs.h> 43116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 116173 2003-06-10 21:29:12Z obrien $"); 44116173Sobrien 4559412Smsmith#include <sys/param.h> 4683926Sdes#include <sys/queue.h> 4776166Smarkm#include <sys/blist.h> 4874135Sjlemon#include <sys/conf.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> 7659412Smsmith#include <vm/swap_pager.h> 7769799Sdes 7867589Sdes#include <machine/clock.h> 7978113Sdes 8078113Sdes#ifdef __alpha__ 8178113Sdes#include <machine/alpha_cpu.h> 8278113Sdes#include <machine/cpuconf.h> 8378113Sdes#include <machine/rpb.h> 8478113Sdesextern int ncpus; 8578113Sdes#endif /* __alpha__ */ 8678113Sdes 8778113Sdes#ifdef __i386__ 8867589Sdes#include <machine/cputypes.h> 8959412Smsmith#include <machine/md_var.h> 9078113Sdes#endif /* __i386__ */ 9159412Smsmith 9287275Srwatson#include <machine/../linux/linux.h> 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 ??? */ 120113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 121113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 122113574Sjhb unsigned long long 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" 213113574Sjhb "cpu revision\t\t: %d\n" 21478113Sdes "cpu serial number\t: %s\n" 21578113Sdes "system type\t\t: %s\n" 21678113Sdes "system variation\t: %s\n" 217113574Sjhb "system revision\t\t: %d\n" 21878113Sdes "system serial number\t: %s\n" 21978113Sdes "cycle frequency [Hz]\t: %lu\n" 220113574Sjhb "timer frequency [Hz]\t: %u\n" 22178113Sdes "page size [bytes]\t: %ld\n" 22278113Sdes "phys. address bits\t: %ld\n" 22378113Sdes "max. addr. space #\t: %ld\n" 224113574Sjhb "BogoMIPS\t\t: %u.%02u\n" 225113574Sjhb "kernel unaligned acc\t: %d (pc=%x,va=%x)\n" 226113574Sjhb "user unaligned acc\t: %d (pc=%x,va=%x)\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; 34191334Sjulian const char *lep; 34291334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 34385289Sdes size_t lep_len; 34485289Sdes int error; 34585289Sdes 34685289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 34785289Sdes NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 34885289Sdes flep = NULL; 34991334Sjulian if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1) 35085289Sdes lep = linux_emul_path; 35191334Sjulian else 35291334Sjulian lep = dlep; 35385289Sdes lep_len = strlen(lep); 35485289Sdes 35585289Sdes mtx_lock(&mountlist_mtx); 35685289Sdes error = 0; 35785289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 35885289Sdes error = VFS_STATFS(mp, &mp->mnt_stat, td); 35985289Sdes if (error) 36085289Sdes break; 36185289Sdes 36285289Sdes /* determine device name */ 36385289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 36485289Sdes 36585289Sdes /* determine mount point */ 36685289Sdes mntto = mp->mnt_stat.f_mntonname; 36785289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 36885289Sdes mntto[lep_len] == '/') 36985289Sdes mntto += lep_len; 37085289Sdes 37185289Sdes /* determine fs type */ 37285289Sdes fstype = mp->mnt_stat.f_fstypename; 37385289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 37485289Sdes mntfrom = fstype = "proc"; 37585289Sdes else if (strcmp(fstype, "procfs") == 0) 37685289Sdes continue; 37785289Sdes 37885289Sdes sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 37985289Sdes mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 38085289Sdes#define ADD_OPTION(opt, name) \ 38185289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 38285289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 38385289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 38485289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 38585289Sdes ADD_OPTION(MNT_NODEV, "nodev"); 38685289Sdes ADD_OPTION(MNT_UNION, "union"); 38785289Sdes ADD_OPTION(MNT_ASYNC, "async"); 38885289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 38985289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 39085289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 39185289Sdes#undef ADD_OPTION 39285289Sdes /* a real Linux mtab will also show NFS options */ 39385289Sdes sbuf_printf(sb, " 0 0\n"); 39485289Sdes } 39585289Sdes mtx_unlock(&mountlist_mtx); 39685289Sdes if (flep != NULL) 39785289Sdes free(flep, M_TEMP); 39885289Sdes return (error); 39985289Sdes} 40085289Sdes 40185289Sdes/* 40278113Sdes * Filler function for proc/stat 40378113Sdes */ 40478025Sdesstatic int 40578025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 40665633Sdes{ 40778025Sdes sbuf_printf(sb, 40869799Sdes "cpu %ld %ld %ld %ld\n" 40969799Sdes "disk 0 0 0 0\n" 41069799Sdes "page %u %u\n" 41169799Sdes "swap %u %u\n" 41269799Sdes "intr %u\n" 41369799Sdes "ctxt %u\n" 41485657Sdillon "btime %lld\n", 41569799Sdes T2J(cp_time[CP_USER]), 41669799Sdes T2J(cp_time[CP_NICE]), 41769799Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 41869799Sdes T2J(cp_time[CP_IDLE]), 41969799Sdes cnt.v_vnodepgsin, 42069799Sdes cnt.v_vnodepgsout, 42169799Sdes cnt.v_swappgsin, 42269799Sdes cnt.v_swappgsout, 42369799Sdes cnt.v_intr, 42469799Sdes cnt.v_swtch, 425113574Sjhb (long long)boottime.tv_sec); 42678025Sdes return (0); 42765633Sdes} 42865633Sdes 42978113Sdes/* 43078113Sdes * Filler function for proc/uptime 43178113Sdes */ 43278025Sdesstatic int 43378025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 43465633Sdes{ 43565633Sdes struct timeval tv; 43665633Sdes 43765633Sdes getmicrouptime(&tv); 43885657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 439113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 44069799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 44178025Sdes return (0); 44265633Sdes} 44365633Sdes 44478113Sdes/* 44578113Sdes * Filler function for proc/version 44678113Sdes */ 44778025Sdesstatic int 44878025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 44965633Sdes{ 45087275Srwatson char osname[LINUX_MAX_UTSNAME]; 45187275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 45287275Srwatson 453112206Sjhb linux_get_osname(td, osname); 454112206Sjhb linux_get_osrelease(td, osrelease); 45587275Srwatson 45678025Sdes sbuf_printf(sb, 45769995Sdes "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 45887275Srwatson " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 45978025Sdes return (0); 46065633Sdes} 46165633Sdes 46278113Sdes/* 46378113Sdes * Filler function for proc/loadavg 46478113Sdes */ 46578025Sdesstatic int 46678025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 46776839Sjlemon{ 46878025Sdes sbuf_printf(sb, 46976839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 47076839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 47176839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 47276839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 47376839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 47476839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 47576839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 47676839Sjlemon 1, /* number of running tasks */ 47776839Sjlemon nprocs, /* number of tasks */ 47878116Sdes lastpid /* the last pid */ 47976839Sjlemon ); 48078025Sdes 48178025Sdes return (0); 48276839Sjlemon} 48376839Sjlemon 48478113Sdes/* 48578113Sdes * Filler function for proc/pid/stat 48678113Sdes */ 48778025Sdesstatic int 48878025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 48967588Sdes{ 49069995Sdes struct kinfo_proc kp; 49167588Sdes 49294307Sjhb PROC_LOCK(p); 49369995Sdes fill_kinfo_proc(p, &kp); 49478025Sdes sbuf_printf(sb, "%d", p->p_pid); 49578025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 49667588Sdes PS_ADD("comm", "(%s)", p->p_comm); 49767588Sdes PS_ADD("statr", "%c", '0'); /* XXX */ 49873923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 49967588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 50067588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 50191140Stanimura PROC_UNLOCK(p); 50267588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 50367588Sdes PS_ADD("tpgid", "%d", 0); /* XXX */ 50467588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 50567588Sdes PS_ADD("minflt", "%u", 0); /* XXX */ 50667588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50767588Sdes PS_ADD("majflt", "%u", 0); /* XXX */ 50867588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50967588Sdes PS_ADD("utime", "%d", 0); /* XXX */ 51067588Sdes PS_ADD("stime", "%d", 0); /* XXX */ 51167588Sdes PS_ADD("cutime", "%d", 0); /* XXX */ 51267588Sdes PS_ADD("cstime", "%d", 0); /* XXX */ 51367588Sdes PS_ADD("counter", "%d", 0); /* XXX */ 51467588Sdes PS_ADD("priority", "%d", 0); /* XXX */ 51567588Sdes PS_ADD("timeout", "%u", 0); /* XXX */ 51667588Sdes PS_ADD("itrealvalue", "%u", 0); /* XXX */ 51767588Sdes PS_ADD("starttime", "%d", 0); /* XXX */ 518113574Sjhb PS_ADD("vsize", "%ju", (uintmax_t)kp.ki_size); 519113574Sjhb PS_ADD("rss", "%ju", P2K((uintmax_t)kp.ki_rssize)); 52067588Sdes PS_ADD("rlim", "%u", 0); /* XXX */ 52169995Sdes PS_ADD("startcode", "%u", (unsigned)0); 52267588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 52367588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 52469799Sdes PS_ADD("esp", "%u", 0); /* XXX */ 52569799Sdes PS_ADD("eip", "%u", 0); /* XXX */ 52667588Sdes PS_ADD("signal", "%d", 0); /* XXX */ 52767588Sdes PS_ADD("blocked", "%d", 0); /* XXX */ 52867588Sdes PS_ADD("sigignore", "%d", 0); /* XXX */ 52967588Sdes PS_ADD("sigcatch", "%d", 0); /* XXX */ 53067588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 53169799Sdes PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 53269799Sdes PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 53369799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 53469799Sdes PS_ADD("processor", "%d", 0); /* XXX */ 53567588Sdes#undef PS_ADD 53678025Sdes sbuf_putc(sb, '\n'); 53767588Sdes 53878025Sdes return (0); 53967588Sdes} 54067588Sdes 54167588Sdes/* 54278113Sdes * Filler function for proc/pid/status 54378113Sdes */ 54478025Sdesstatic int 54578025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 54667588Sdes{ 54769995Sdes struct kinfo_proc kp; 54867588Sdes char *state; 54969799Sdes segsz_t lsize; 55099072Sjulian struct thread *td2; 551114983Sjhb struct sigacts *ps; 55274135Sjlemon int i; 55367588Sdes 554113611Sjhb PROC_LOCK(p); 55599072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 55699072Sjulian 55799072Sjulian if (P_SHOULDSTOP(p)) { 55899072Sjulian state = "T (stopped)"; 55999072Sjulian } else { 560113611Sjhb mtx_lock_spin(&sched_lock); 56199072Sjulian switch(p->p_state) { 56299072Sjulian case PRS_NEW: 56399072Sjulian state = "I (idle)"; 56499072Sjulian break; 56599072Sjulian case PRS_NORMAL: 56699072Sjulian if (p->p_flag & P_WEXIT) { 56799072Sjulian state = "X (exiting)"; 56899072Sjulian break; 56999072Sjulian } 57099072Sjulian switch(td2->td_state) { 571103216Sjulian case TDS_INHIBITED: 57299072Sjulian state = "S (sleeping)"; 57399072Sjulian break; 57499072Sjulian case TDS_RUNQ: 57599072Sjulian case TDS_RUNNING: 57699072Sjulian state = "R (running)"; 57799072Sjulian break; 57899072Sjulian default: 57999072Sjulian state = "? (unknown)"; 58099072Sjulian break; 58199072Sjulian } 58299072Sjulian break; 58399072Sjulian case PRS_ZOMBIE: 58499072Sjulian state = "Z (zombie)"; 58599072Sjulian break; 58699072Sjulian default: 58799072Sjulian state = "? (unknown)"; 58899072Sjulian break; 58999072Sjulian } 590113611Sjhb mtx_unlock_spin(&sched_lock); 59199072Sjulian } 59267588Sdes 59369995Sdes fill_kinfo_proc(p, &kp); 59478025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 59578031Sdes sbuf_printf(sb, "State:\t%s\n", state); 59667588Sdes 59767588Sdes /* 59867588Sdes * Credentials 59967588Sdes */ 60078025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 60178025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 60273923Sjhb p->p_pptr->p_pid : 0); 60378031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 60478031Sdes p->p_ucred->cr_uid, 60578031Sdes p->p_ucred->cr_svuid, 60678031Sdes /* FreeBSD doesn't have fsuid */ 60778031Sdes p->p_ucred->cr_uid); 60878031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 60978031Sdes p->p_ucred->cr_gid, 61078031Sdes p->p_ucred->cr_svgid, 61178031Sdes /* FreeBSD doesn't have fsgid */ 61278031Sdes p->p_ucred->cr_gid); 61378025Sdes sbuf_cat(sb, "Groups:\t"); 61467588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 61578031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 61671471Sjhb PROC_UNLOCK(p); 61778025Sdes sbuf_putc(sb, '\n'); 61867588Sdes 61967588Sdes /* 62067588Sdes * Memory 62169799Sdes * 62269799Sdes * While our approximation of VmLib may not be accurate (I 62369799Sdes * don't know of a simple way to verify it, and I'm not sure 62469799Sdes * it has much meaning anyway), I believe it's good enough. 62569799Sdes * 62669799Sdes * The same code that could (I think) accurately compute VmLib 62769799Sdes * could also compute VmLck, but I don't really care enough to 62869799Sdes * implement it. Submissions are welcome. 62967588Sdes */ 630113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 63178025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 632113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 633113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 634113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 635113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 63669995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 63769995Sdes kp.ki_ssize - kp.ki_tsize - 1; 638113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 63967588Sdes 64067588Sdes /* 64167588Sdes * Signal masks 64267588Sdes * 64367588Sdes * We support up to 128 signals, while Linux supports 32, 64467588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 64567588Sdes * just show the lower 32 bits of each mask. XXX hack. 64667588Sdes * 64767588Sdes * NB: on certain platforms (Sparc at least) Linux actually 64867588Sdes * supports 64 signals, but this code is a long way from 64967588Sdes * running on anything but i386, so ignore that for now. 65067588Sdes */ 65171471Sjhb PROC_LOCK(p); 652104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 65369799Sdes /* 65469799Sdes * I can't seem to find out where the signal mask is in 65569799Sdes * relation to struct proc, so SigBlk is left unimplemented. 65669799Sdes */ 65778025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 658114983Sjhb ps = p->p_sigacts; 659114983Sjhb mtx_lock(&ps->ps_mtx); 660114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 661114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 662114983Sjhb mtx_unlock(&ps->ps_mtx); 66371471Sjhb PROC_UNLOCK(p); 66467588Sdes 66567588Sdes /* 66667588Sdes * Linux also prints the capability masks, but we don't have 66767588Sdes * capabilities yet, and when we do get them they're likely to 66867588Sdes * be meaningless to Linux programs, so we lie. XXX 66967588Sdes */ 67078025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 67178025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 67278025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 67378025Sdes 67478025Sdes return (0); 67567588Sdes} 67674135Sjlemon 67778113Sdes/* 67878113Sdes * Filler function for proc/pid/cmdline 67978113Sdes */ 68078025Sdesstatic int 68178113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 68278113Sdes{ 68378113Sdes struct ps_strings pstr; 68478113Sdes int error, i; 68578113Sdes 68678113Sdes /* 68778113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 68878113Sdes * revert back to the old way which only implements full cmdline 68978113Sdes * for the currept process and just p->p_comm for all other 69078113Sdes * processes. 69178113Sdes * Note that if the argv is no longer available, we deliberately 69278113Sdes * don't fall back on p->p_comm or return an error: the authentic 69378113Sdes * Linux behaviour is to return zero-length in this case. 69478113Sdes */ 69578113Sdes 69694620Sjhb PROC_LOCK(p); 69796886Sjhb if (p->p_args && (ps_argsopen || !p_cansee(td, p))) { 69894620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 69994620Sjhb PROC_UNLOCK(p); 70094620Sjhb } else if (p != td->td_proc) { 70194620Sjhb PROC_UNLOCK(p); 70294620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 70394620Sjhb } else { 70494620Sjhb PROC_UNLOCK(p); 705103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 706103767Sjake sizeof(pstr)); 70794620Sjhb if (error) 70894620Sjhb return (error); 70994620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 71094620Sjhb sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 71194620Sjhb sbuf_printf(sb, "%c", '\0'); 71278113Sdes } 71378113Sdes } 71478113Sdes 71578113Sdes return (0); 71678113Sdes} 71778113Sdes 71878113Sdes/* 719116173Sobrien * Filler function for proc/pid/environ 720116173Sobrien */ 721116173Sobrienstatic int 722116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 723116173Sobrien{ 724116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 725116173Sobrien 726116173Sobrien return (0); 727116173Sobrien} 728116173Sobrien 729116173Sobrien/* 730116173Sobrien * Filler function for proc/pid/maps 731116173Sobrien */ 732116173Sobrienstatic int 733116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 734116173Sobrien{ 735116173Sobrien sbuf_printf(sb, "doprocmaps\n%c", '\0'); 736116173Sobrien 737116173Sobrien return (0); 738116173Sobrien} 739116173Sobrien 740116173Sobrien/* 74178113Sdes * Filler function for proc/net/dev 74278113Sdes */ 74378025Sdesstatic int 74478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 74574135Sjlemon{ 74685129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 74774135Sjlemon struct ifnet *ifp; 74874135Sjlemon 74985129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 75083926Sdes "Inter-", " Receive", " Transmit", " face", 75185129Sdes "bytes packets errs drop fifo frame compressed", 75283926Sdes "bytes packets errs drop fifo frame compressed"); 75374135Sjlemon 754108172Shsu IFNET_RLOCK(); 75574135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 75685129Sdes linux_ifname(ifp, ifname, sizeof ifname); 75785129Sdes sbuf_printf(sb, "%6.6s:", ifname); 75883926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 75983926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 76083926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 76183926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 76274135Sjlemon } 763108172Shsu IFNET_RUNLOCK(); 76478025Sdes 76578025Sdes return (0); 76674135Sjlemon} 76774135Sjlemon 76885538Sphk#if 0 76985538Sphkextern struct cdevsw *cdevsw[]; 77085538Sphk 77178113Sdes/* 77278113Sdes * Filler function for proc/devices 77378113Sdes */ 77478025Sdesstatic int 77578025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 77674135Sjlemon{ 77774135Sjlemon int i; 77874135Sjlemon 77978025Sdes sbuf_printf(sb, "Character devices:\n"); 78074135Sjlemon 78178025Sdes for (i = 0; i < NUMCDEVSW; i++) 78274135Sjlemon if (cdevsw[i] != NULL) 78378025Sdes sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 78474135Sjlemon 78578025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 78678025Sdes 78778025Sdes return (0); 78874135Sjlemon} 78985538Sphk#endif 79074135Sjlemon 79178113Sdes/* 79278113Sdes * Filler function for proc/cmdline 79378113Sdes */ 79478025Sdesstatic int 79578025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 79674135Sjlemon{ 79778025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 79878025Sdes sbuf_printf(sb, " ro root=302\n"); 79978025Sdes return (0); 80078025Sdes} 80174135Sjlemon 80283926Sdes#if 0 80378025Sdes/* 80483926Sdes * Filler function for proc/modules 80583926Sdes */ 80683926Sdesstatic int 80783926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 80883926Sdes{ 80983926Sdes struct linker_file *lf; 81083926Sdes 81183926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 81283926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 81383926Sdes (unsigned long)lf->size, lf->refs); 81483926Sdes } 81583926Sdes return (0); 81683926Sdes} 81783926Sdes#endif 81883926Sdes 81983926Sdes/* 82085129Sdes * Constructor 82178025Sdes */ 82285129Sdesstatic int 82385129Sdeslinprocfs_init(PFS_INIT_ARGS) 82485129Sdes{ 82585129Sdes struct pfs_node *root; 82685129Sdes struct pfs_node *dir; 82774135Sjlemon 82885129Sdes root = pi->pi_root; 82978025Sdes 83085129Sdes#define PFS_CREATE_FILE(name) \ 83185129Sdes pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 83285129Sdes PFS_CREATE_FILE(cmdline); 83385129Sdes PFS_CREATE_FILE(cpuinfo); 83485538Sphk#if 0 83585129Sdes PFS_CREATE_FILE(devices); 83685538Sphk#endif 83785129Sdes PFS_CREATE_FILE(loadavg); 83885129Sdes PFS_CREATE_FILE(meminfo); 83983926Sdes#if 0 84085129Sdes PFS_CREATE_FILE(modules); 84183926Sdes#endif 84285289Sdes PFS_CREATE_FILE(mtab); 84385129Sdes PFS_CREATE_FILE(stat); 84485129Sdes PFS_CREATE_FILE(uptime); 84585129Sdes PFS_CREATE_FILE(version); 84685129Sdes#undef PFS_CREATE_FILE 84787543Sdes pfs_create_link(root, "self", &procfs_docurproc, 84885129Sdes NULL, NULL, 0); 84978025Sdes 85085129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 85185129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 85285129Sdes NULL, NULL, PFS_RD); 85378025Sdes 85485129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 85585129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 85685129Sdes NULL, NULL, PFS_RD); 857116173Sobrien 858116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 859116173Sobrien NULL, NULL, PFS_RD); 860116173Sobrien 86187543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 86287543Sdes NULL, &procfs_notsystem, 0); 863116173Sobrien 864116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 865116173Sobrien NULL, NULL, PFS_RD); 866116173Sobrien 86785129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 86885129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 86985129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 87085129Sdes NULL, NULL, PFS_RD); 87185129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 87285129Sdes NULL, NULL, PFS_RD); 87385129Sdes 87485129Sdes return (0); 87585129Sdes} 87685129Sdes 87785129Sdes/* 87885129Sdes * Destructor 87985129Sdes */ 88085129Sdesstatic int 88185129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 88285129Sdes{ 88385129Sdes 88485129Sdes /* nothing to do, pseudofs will GC */ 88585129Sdes return (0); 88685129Sdes} 88785129Sdes 88885129SdesPSEUDOFS(linprocfs, 1); 88978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 89078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 891