linprocfs.c revision 114983
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 114983 2003-05-13 20:36:02Z jhb $ 4259412Smsmith */ 4359412Smsmith 4459412Smsmith#include <sys/param.h> 4583926Sdes#include <sys/queue.h> 4676166Smarkm#include <sys/blist.h> 4774135Sjlemon#include <sys/conf.h> 4883926Sdes#include <sys/exec.h> 4976166Smarkm#include <sys/jail.h> 5065633Sdes#include <sys/kernel.h> 5183926Sdes#include <sys/linker.h> 5276166Smarkm#include <sys/lock.h> 5374135Sjlemon#include <sys/malloc.h> 5478025Sdes#include <sys/mount.h> 5576827Salfred#include <sys/mutex.h> 5685289Sdes#include <sys/namei.h> 5765633Sdes#include <sys/proc.h> 5865633Sdes#include <sys/resourcevar.h> 5969995Sdes#include <sys/sbuf.h> 6083926Sdes#include <sys/socket.h> 6176839Sjlemon#include <sys/sysctl.h> 6283926Sdes#include <sys/systm.h> 6365633Sdes#include <sys/tty.h> 6483926Sdes#include <sys/user.h> 6583926Sdes#include <sys/vmmeter.h> 6659412Smsmith#include <sys/vnode.h> 6759412Smsmith 6883926Sdes#include <net/if.h> 6983926Sdes 7059412Smsmith#include <vm/vm.h> 7159412Smsmith#include <vm/pmap.h> 7267588Sdes#include <vm/vm_map.h> 7359412Smsmith#include <vm/vm_param.h> 7460860Sdes#include <vm/vm_object.h> 7559412Smsmith#include <vm/swap_pager.h> 7669799Sdes 7767589Sdes#include <machine/clock.h> 7878113Sdes 7978113Sdes#ifdef __alpha__ 8078113Sdes#include <machine/alpha_cpu.h> 8178113Sdes#include <machine/cpuconf.h> 8278113Sdes#include <machine/rpb.h> 8378113Sdesextern int ncpus; 8478113Sdes#endif /* __alpha__ */ 8578113Sdes 8678113Sdes#ifdef __i386__ 8767589Sdes#include <machine/cputypes.h> 8859412Smsmith#include <machine/md_var.h> 8978113Sdes#endif /* __i386__ */ 9059412Smsmith 9187275Srwatson#include <machine/../linux/linux.h> 9285129Sdes#include <compat/linux/linux_ioctl.h> 9369995Sdes#include <compat/linux/linux_mib.h> 9485289Sdes#include <compat/linux/linux_util.h> 9578025Sdes#include <fs/pseudofs/pseudofs.h> 9684248Sdes#include <fs/procfs/procfs.h> 9759412Smsmith 9867588Sdes/* 9967588Sdes * Various conversion macros 10067588Sdes */ 10176405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10267588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10367588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10469799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10567588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10667588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10774135Sjlemon 10878113Sdes/* 10978113Sdes * Filler function for proc/meminfo 11078113Sdes */ 11178025Sdesstatic int 11278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 11359412Smsmith{ 11459412Smsmith unsigned long memtotal; /* total memory in bytes */ 11559412Smsmith unsigned long memused; /* used memory in bytes */ 11659412Smsmith unsigned long memfree; /* free memory in bytes */ 11759412Smsmith unsigned long memshared; /* shared memory ??? */ 11859412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 119113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 120113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 121113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 12260860Sdes vm_object_t object; 12359412Smsmith 12459412Smsmith memtotal = physmem * PAGE_SIZE; 12559412Smsmith /* 12659412Smsmith * The correct thing here would be: 12759412Smsmith * 12859412Smsmith memfree = cnt.v_free_count * PAGE_SIZE; 12959412Smsmith memused = memtotal - memfree; 13059412Smsmith * 13159412Smsmith * but it might mislead linux binaries into thinking there 13259412Smsmith * is very little memory left, so we cheat and tell them that 13359412Smsmith * all memory that isn't wired down is free. 13459412Smsmith */ 13559412Smsmith memused = cnt.v_wire_count * PAGE_SIZE; 13659412Smsmith memfree = memtotal - memused; 13764560Sbde if (swapblist == NULL) { 13864560Sbde swaptotal = 0; 13964560Sbde swapfree = 0; 14064560Sbde } else { 14176839Sjlemon swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */ 14276839Sjlemon swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 14364560Sbde } 14459412Smsmith swapused = swaptotal - swapfree; 14560860Sdes memshared = 0; 14671471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 14760860Sdes if (object->shadow_count > 1) 14860860Sdes memshared += object->resident_page_count; 14960860Sdes memshared *= PAGE_SIZE; 15059412Smsmith /* 15159412Smsmith * We'd love to be able to write: 15259412Smsmith * 15359412Smsmith buffers = bufspace; 15459412Smsmith * 15559412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 15659412Smsmith * like unstaticizing it just for linprocfs's sake. 15759412Smsmith */ 15859412Smsmith buffers = 0; 15959412Smsmith cached = cnt.v_cache_count * PAGE_SIZE; 16059412Smsmith 16178025Sdes sbuf_printf(sb, 16278031Sdes " total: used: free: shared: buffers: cached:\n" 16369799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 16476839Sjlemon "Swap: %llu %llu %llu\n" 16569799Sdes "MemTotal: %9lu kB\n" 16669799Sdes "MemFree: %9lu kB\n" 16769799Sdes "MemShared:%9lu kB\n" 16869799Sdes "Buffers: %9lu kB\n" 16969799Sdes "Cached: %9lu kB\n" 17076839Sjlemon "SwapTotal:%9llu kB\n" 17176839Sjlemon "SwapFree: %9llu kB\n", 17269799Sdes memtotal, memused, memfree, memshared, buffers, cached, 17369799Sdes swaptotal, swapused, swapfree, 17469799Sdes B2K(memtotal), B2K(memfree), 17569799Sdes B2K(memshared), B2K(buffers), B2K(cached), 17669799Sdes B2K(swaptotal), B2K(swapfree)); 17759412Smsmith 17878025Sdes return (0); 17959412Smsmith} 18059412Smsmith 18178113Sdes#ifdef __alpha__ 18278113Sdes/* 18378113Sdes * Filler function for proc/cpuinfo (Alpha version) 18478113Sdes */ 18578025Sdesstatic int 18678025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 18759412Smsmith{ 18878113Sdes u_int64_t type, major; 18978113Sdes struct pcs *pcsp; 19078113Sdes const char *model, *sysname; 19178113Sdes 19278113Sdes static const char *cpuname[] = { 19378113Sdes "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", 19478113Sdes "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" 19578113Sdes }; 19678113Sdes 19778113Sdes pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 19878113Sdes type = pcsp->pcs_proc_type; 19978113Sdes major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; 20078113Sdes if (major < sizeof(cpuname)/sizeof(char *)) { 20178113Sdes model = cpuname[major - 1]; 20278113Sdes } else { 20378113Sdes model = "unknown"; 20478113Sdes } 20578113Sdes 20678113Sdes sysname = alpha_dsr_sysname(); 20778113Sdes 20878113Sdes sbuf_printf(sb, 20978113Sdes "cpu\t\t\t: Alpha\n" 21078113Sdes "cpu model\t\t: %s\n" 21178113Sdes "cpu variation\t\t: %ld\n" 212113574Sjhb "cpu revision\t\t: %d\n" 21378113Sdes "cpu serial number\t: %s\n" 21478113Sdes "system type\t\t: %s\n" 21578113Sdes "system variation\t: %s\n" 216113574Sjhb "system revision\t\t: %d\n" 21778113Sdes "system serial number\t: %s\n" 21878113Sdes "cycle frequency [Hz]\t: %lu\n" 219113574Sjhb "timer frequency [Hz]\t: %u\n" 22078113Sdes "page size [bytes]\t: %ld\n" 22178113Sdes "phys. address bits\t: %ld\n" 22278113Sdes "max. addr. space #\t: %ld\n" 223113574Sjhb "BogoMIPS\t\t: %u.%02u\n" 224113574Sjhb "kernel unaligned acc\t: %d (pc=%x,va=%x)\n" 225113574Sjhb "user unaligned acc\t: %d (pc=%x,va=%x)\n" 22678113Sdes "platform string\t\t: %s\n" 22778113Sdes "cpus detected\t\t: %d\n" 22878113Sdes , 22978113Sdes model, 23078113Sdes pcsp->pcs_proc_var, 23178113Sdes *(int *)hwrpb->rpb_revision, 23278113Sdes " ", 23378113Sdes " ", 23478113Sdes "0", 23578113Sdes 0, 23678113Sdes " ", 23778113Sdes hwrpb->rpb_cc_freq, 23878113Sdes hz, 23978113Sdes hwrpb->rpb_page_size, 24078113Sdes hwrpb->rpb_phys_addr_size, 24178113Sdes hwrpb->rpb_max_asn, 24278113Sdes 0, 0, 24378113Sdes 0, 0, 0, 24478113Sdes 0, 0, 0, 24578113Sdes sysname, 24678113Sdes ncpus); 24778113Sdes return (0); 24878113Sdes} 24978113Sdes#endif /* __alpha__ */ 25078113Sdes 25178113Sdes#ifdef __i386__ 25278113Sdes/* 25378113Sdes * Filler function for proc/cpuinfo (i386 version) 25478113Sdes */ 25578113Sdesstatic int 25678113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 25778113Sdes{ 25869799Sdes int class, i, fqmhz, fqkhz; 25959412Smsmith 26069799Sdes /* 26178031Sdes * We default the flags to include all non-conflicting flags, 26278031Sdes * and the Intel versions of conflicting flags. 26369799Sdes */ 26478031Sdes static char *flags[] = { 26578031Sdes "fpu", "vme", "de", "pse", "tsc", 26678031Sdes "msr", "pae", "mce", "cx8", "apic", 26778031Sdes "sep", "sep", "mtrr", "pge", "mca", 26878031Sdes "cmov", "pat", "pse36", "pn", "b19", 26978031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 27078031Sdes "xmm", "b26", "b27", "b28", "b29", 27167589Sdes "3dnowext", "3dnow" 27267589Sdes }; 27367589Sdes 27459412Smsmith switch (cpu_class) { 27559412Smsmith case CPUCLASS_286: 27667589Sdes class = 2; 27759412Smsmith break; 27859412Smsmith case CPUCLASS_386: 27967589Sdes class = 3; 28059412Smsmith break; 28159412Smsmith case CPUCLASS_486: 28267589Sdes class = 4; 28359412Smsmith break; 28459412Smsmith case CPUCLASS_586: 28567589Sdes class = 5; 28659412Smsmith break; 28759412Smsmith case CPUCLASS_686: 28867589Sdes class = 6; 28959412Smsmith break; 29059412Smsmith default: 29178031Sdes class = 0; 29259412Smsmith break; 29359412Smsmith } 29459412Smsmith 29578025Sdes sbuf_printf(sb, 29678031Sdes "processor\t: %d\n" 29769799Sdes "vendor_id\t: %.20s\n" 29869799Sdes "cpu family\t: %d\n" 29969799Sdes "model\t\t: %d\n" 30069799Sdes "stepping\t: %d\n", 30169799Sdes 0, cpu_vendor, class, cpu, cpu_id & 0xf); 30259412Smsmith 30378031Sdes sbuf_cat(sb, 30478031Sdes "flags\t\t:"); 30567589Sdes 30678031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 30767589Sdes flags[16] = "fcmov"; 30878031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 30967589Sdes flags[24] = "cxmmx"; 31078031Sdes } 31178031Sdes 31278031Sdes for (i = 0; i < 32; i++) 31367589Sdes if (cpu_feature & (1 << i)) 31478025Sdes sbuf_printf(sb, " %s", flags[i]); 31578025Sdes sbuf_cat(sb, "\n"); 31678031Sdes if (class >= 5) { 31769799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 31869799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 31978025Sdes sbuf_printf(sb, 32069799Sdes "cpu MHz\t\t: %d.%02d\n" 32169799Sdes "bogomips\t: %d.%02d\n", 32269799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 32378031Sdes } 32469995Sdes 32578025Sdes return (0); 32659412Smsmith} 32778113Sdes#endif /* __i386__ */ 32865633Sdes 32978113Sdes/* 33085289Sdes * Filler function for proc/mtab 33185289Sdes * 33285289Sdes * This file doesn't exist in Linux' procfs, but is included here so 33385289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 33485289Sdes */ 33585289Sdesstatic int 33685289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 33785289Sdes{ 33885289Sdes struct nameidata nd; 33985289Sdes struct mount *mp; 34091334Sjulian const char *lep; 34191334Sjulian char *dlep, *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; 34891334Sjulian if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1) 34985289Sdes lep = linux_emul_path; 35091334Sjulian else 35191334Sjulian lep = dlep; 35285289Sdes lep_len = strlen(lep); 35385289Sdes 35485289Sdes mtx_lock(&mountlist_mtx); 35585289Sdes error = 0; 35685289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 35785289Sdes error = VFS_STATFS(mp, &mp->mnt_stat, td); 35885289Sdes if (error) 35985289Sdes break; 36085289Sdes 36185289Sdes /* determine device name */ 36285289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 36385289Sdes 36485289Sdes /* determine mount point */ 36585289Sdes mntto = mp->mnt_stat.f_mntonname; 36685289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 36785289Sdes mntto[lep_len] == '/') 36885289Sdes mntto += lep_len; 36985289Sdes 37085289Sdes /* determine fs type */ 37185289Sdes fstype = mp->mnt_stat.f_fstypename; 37285289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 37385289Sdes mntfrom = fstype = "proc"; 37485289Sdes else if (strcmp(fstype, "procfs") == 0) 37585289Sdes continue; 37685289Sdes 37785289Sdes sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 37885289Sdes mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 37985289Sdes#define ADD_OPTION(opt, name) \ 38085289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 38185289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 38285289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 38385289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 38485289Sdes ADD_OPTION(MNT_NODEV, "nodev"); 38585289Sdes ADD_OPTION(MNT_UNION, "union"); 38685289Sdes ADD_OPTION(MNT_ASYNC, "async"); 38785289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 38885289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 38985289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 39085289Sdes#undef ADD_OPTION 39185289Sdes /* a real Linux mtab will also show NFS options */ 39285289Sdes sbuf_printf(sb, " 0 0\n"); 39385289Sdes } 39485289Sdes mtx_unlock(&mountlist_mtx); 39585289Sdes if (flep != NULL) 39685289Sdes free(flep, M_TEMP); 39785289Sdes return (error); 39885289Sdes} 39985289Sdes 40085289Sdes/* 40178113Sdes * Filler function for proc/stat 40278113Sdes */ 40378025Sdesstatic int 40478025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 40565633Sdes{ 40678025Sdes sbuf_printf(sb, 40769799Sdes "cpu %ld %ld %ld %ld\n" 40869799Sdes "disk 0 0 0 0\n" 40969799Sdes "page %u %u\n" 41069799Sdes "swap %u %u\n" 41169799Sdes "intr %u\n" 41269799Sdes "ctxt %u\n" 41385657Sdillon "btime %lld\n", 41469799Sdes T2J(cp_time[CP_USER]), 41569799Sdes T2J(cp_time[CP_NICE]), 41669799Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 41769799Sdes T2J(cp_time[CP_IDLE]), 41869799Sdes cnt.v_vnodepgsin, 41969799Sdes cnt.v_vnodepgsout, 42069799Sdes cnt.v_swappgsin, 42169799Sdes cnt.v_swappgsout, 42269799Sdes cnt.v_intr, 42369799Sdes cnt.v_swtch, 424113574Sjhb (long long)boottime.tv_sec); 42578025Sdes return (0); 42665633Sdes} 42765633Sdes 42878113Sdes/* 42978113Sdes * Filler function for proc/uptime 43078113Sdes */ 43178025Sdesstatic int 43278025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 43365633Sdes{ 43465633Sdes struct timeval tv; 43565633Sdes 43665633Sdes getmicrouptime(&tv); 43785657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 438113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 43969799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 44078025Sdes return (0); 44165633Sdes} 44265633Sdes 44378113Sdes/* 44478113Sdes * Filler function for proc/version 44578113Sdes */ 44678025Sdesstatic int 44778025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 44865633Sdes{ 44987275Srwatson char osname[LINUX_MAX_UTSNAME]; 45087275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 45187275Srwatson 452112206Sjhb linux_get_osname(td, osname); 453112206Sjhb linux_get_osrelease(td, osrelease); 45487275Srwatson 45578025Sdes sbuf_printf(sb, 45669995Sdes "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 45787275Srwatson " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 45878025Sdes return (0); 45965633Sdes} 46065633Sdes 46178113Sdes/* 46278113Sdes * Filler function for proc/loadavg 46378113Sdes */ 46478025Sdesstatic int 46578025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 46676839Sjlemon{ 46778025Sdes sbuf_printf(sb, 46876839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 46976839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 47076839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 47176839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 47276839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 47376839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 47476839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 47576839Sjlemon 1, /* number of running tasks */ 47676839Sjlemon nprocs, /* number of tasks */ 47778116Sdes lastpid /* the last pid */ 47876839Sjlemon ); 47978025Sdes 48078025Sdes return (0); 48176839Sjlemon} 48276839Sjlemon 48378113Sdes/* 48478113Sdes * Filler function for proc/pid/stat 48578113Sdes */ 48678025Sdesstatic int 48778025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 48867588Sdes{ 48969995Sdes struct kinfo_proc kp; 49067588Sdes 49194307Sjhb PROC_LOCK(p); 49269995Sdes fill_kinfo_proc(p, &kp); 49378025Sdes sbuf_printf(sb, "%d", p->p_pid); 49478025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 49567588Sdes PS_ADD("comm", "(%s)", p->p_comm); 49667588Sdes PS_ADD("statr", "%c", '0'); /* XXX */ 49773923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 49867588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 49967588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 50091140Stanimura PROC_UNLOCK(p); 50167588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 50267588Sdes PS_ADD("tpgid", "%d", 0); /* XXX */ 50367588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 50467588Sdes PS_ADD("minflt", "%u", 0); /* XXX */ 50567588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50667588Sdes PS_ADD("majflt", "%u", 0); /* XXX */ 50767588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50867588Sdes PS_ADD("utime", "%d", 0); /* XXX */ 50967588Sdes PS_ADD("stime", "%d", 0); /* XXX */ 51067588Sdes PS_ADD("cutime", "%d", 0); /* XXX */ 51167588Sdes PS_ADD("cstime", "%d", 0); /* XXX */ 51267588Sdes PS_ADD("counter", "%d", 0); /* XXX */ 51367588Sdes PS_ADD("priority", "%d", 0); /* XXX */ 51467588Sdes PS_ADD("timeout", "%u", 0); /* XXX */ 51567588Sdes PS_ADD("itrealvalue", "%u", 0); /* XXX */ 51667588Sdes PS_ADD("starttime", "%d", 0); /* XXX */ 517113574Sjhb PS_ADD("vsize", "%ju", (uintmax_t)kp.ki_size); 518113574Sjhb PS_ADD("rss", "%ju", P2K((uintmax_t)kp.ki_rssize)); 51967588Sdes PS_ADD("rlim", "%u", 0); /* XXX */ 52069995Sdes PS_ADD("startcode", "%u", (unsigned)0); 52167588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 52267588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 52369799Sdes PS_ADD("esp", "%u", 0); /* XXX */ 52469799Sdes PS_ADD("eip", "%u", 0); /* XXX */ 52567588Sdes PS_ADD("signal", "%d", 0); /* XXX */ 52667588Sdes PS_ADD("blocked", "%d", 0); /* XXX */ 52767588Sdes PS_ADD("sigignore", "%d", 0); /* XXX */ 52867588Sdes PS_ADD("sigcatch", "%d", 0); /* XXX */ 52967588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 53069799Sdes PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 53169799Sdes PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 53269799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 53369799Sdes PS_ADD("processor", "%d", 0); /* XXX */ 53467588Sdes#undef PS_ADD 53578025Sdes sbuf_putc(sb, '\n'); 53667588Sdes 53778025Sdes return (0); 53867588Sdes} 53967588Sdes 54067588Sdes/* 54178113Sdes * Filler function for proc/pid/status 54278113Sdes */ 54378025Sdesstatic int 54478025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 54567588Sdes{ 54669995Sdes struct kinfo_proc kp; 54767588Sdes char *state; 54869799Sdes segsz_t lsize; 54999072Sjulian struct thread *td2; 550114983Sjhb struct sigacts *ps; 55174135Sjlemon int i; 55267588Sdes 553113611Sjhb PROC_LOCK(p); 55499072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 55599072Sjulian 55699072Sjulian if (P_SHOULDSTOP(p)) { 55799072Sjulian state = "T (stopped)"; 55899072Sjulian } else { 559113611Sjhb mtx_lock_spin(&sched_lock); 56099072Sjulian switch(p->p_state) { 56199072Sjulian case PRS_NEW: 56299072Sjulian state = "I (idle)"; 56399072Sjulian break; 56499072Sjulian case PRS_NORMAL: 56599072Sjulian if (p->p_flag & P_WEXIT) { 56699072Sjulian state = "X (exiting)"; 56799072Sjulian break; 56899072Sjulian } 56999072Sjulian switch(td2->td_state) { 570103216Sjulian case TDS_INHIBITED: 57199072Sjulian state = "S (sleeping)"; 57299072Sjulian break; 57399072Sjulian case TDS_RUNQ: 57499072Sjulian case TDS_RUNNING: 57599072Sjulian state = "R (running)"; 57699072Sjulian break; 57799072Sjulian default: 57899072Sjulian state = "? (unknown)"; 57999072Sjulian break; 58099072Sjulian } 58199072Sjulian break; 58299072Sjulian case PRS_ZOMBIE: 58399072Sjulian state = "Z (zombie)"; 58499072Sjulian break; 58599072Sjulian default: 58699072Sjulian state = "? (unknown)"; 58799072Sjulian break; 58899072Sjulian } 589113611Sjhb mtx_unlock_spin(&sched_lock); 59099072Sjulian } 59167588Sdes 59269995Sdes fill_kinfo_proc(p, &kp); 59378025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 59478031Sdes sbuf_printf(sb, "State:\t%s\n", state); 59567588Sdes 59667588Sdes /* 59767588Sdes * Credentials 59867588Sdes */ 59978025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 60078025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 60173923Sjhb p->p_pptr->p_pid : 0); 60278031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 60378031Sdes p->p_ucred->cr_uid, 60478031Sdes p->p_ucred->cr_svuid, 60578031Sdes /* FreeBSD doesn't have fsuid */ 60678031Sdes p->p_ucred->cr_uid); 60778031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 60878031Sdes p->p_ucred->cr_gid, 60978031Sdes p->p_ucred->cr_svgid, 61078031Sdes /* FreeBSD doesn't have fsgid */ 61178031Sdes p->p_ucred->cr_gid); 61278025Sdes sbuf_cat(sb, "Groups:\t"); 61367588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 61478031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 61571471Sjhb PROC_UNLOCK(p); 61678025Sdes sbuf_putc(sb, '\n'); 61767588Sdes 61867588Sdes /* 61967588Sdes * Memory 62069799Sdes * 62169799Sdes * While our approximation of VmLib may not be accurate (I 62269799Sdes * don't know of a simple way to verify it, and I'm not sure 62369799Sdes * it has much meaning anyway), I believe it's good enough. 62469799Sdes * 62569799Sdes * The same code that could (I think) accurately compute VmLib 62669799Sdes * could also compute VmLck, but I don't really care enough to 62769799Sdes * implement it. Submissions are welcome. 62867588Sdes */ 629113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 63078025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 631113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 632113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 633113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 634113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 63569995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 63669995Sdes kp.ki_ssize - kp.ki_tsize - 1; 637113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 63867588Sdes 63967588Sdes /* 64067588Sdes * Signal masks 64167588Sdes * 64267588Sdes * We support up to 128 signals, while Linux supports 32, 64367588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 64467588Sdes * just show the lower 32 bits of each mask. XXX hack. 64567588Sdes * 64667588Sdes * NB: on certain platforms (Sparc at least) Linux actually 64767588Sdes * supports 64 signals, but this code is a long way from 64867588Sdes * running on anything but i386, so ignore that for now. 64967588Sdes */ 65071471Sjhb PROC_LOCK(p); 651104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 65269799Sdes /* 65369799Sdes * I can't seem to find out where the signal mask is in 65469799Sdes * relation to struct proc, so SigBlk is left unimplemented. 65569799Sdes */ 65678025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 657114983Sjhb ps = p->p_sigacts; 658114983Sjhb mtx_lock(&ps->ps_mtx); 659114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 660114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 661114983Sjhb mtx_unlock(&ps->ps_mtx); 66271471Sjhb PROC_UNLOCK(p); 66367588Sdes 66467588Sdes /* 66567588Sdes * Linux also prints the capability masks, but we don't have 66667588Sdes * capabilities yet, and when we do get them they're likely to 66767588Sdes * be meaningless to Linux programs, so we lie. XXX 66867588Sdes */ 66978025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 67078025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 67178025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 67278025Sdes 67378025Sdes return (0); 67467588Sdes} 67574135Sjlemon 67678113Sdes/* 67778113Sdes * Filler function for proc/pid/cmdline 67878113Sdes */ 67978025Sdesstatic int 68078113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 68178113Sdes{ 68278113Sdes struct ps_strings pstr; 68378113Sdes int error, i; 68478113Sdes 68578113Sdes /* 68678113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 68778113Sdes * revert back to the old way which only implements full cmdline 68878113Sdes * for the currept process and just p->p_comm for all other 68978113Sdes * processes. 69078113Sdes * Note that if the argv is no longer available, we deliberately 69178113Sdes * don't fall back on p->p_comm or return an error: the authentic 69278113Sdes * Linux behaviour is to return zero-length in this case. 69378113Sdes */ 69478113Sdes 69594620Sjhb PROC_LOCK(p); 69696886Sjhb if (p->p_args && (ps_argsopen || !p_cansee(td, p))) { 69794620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 69894620Sjhb PROC_UNLOCK(p); 69994620Sjhb } else if (p != td->td_proc) { 70094620Sjhb PROC_UNLOCK(p); 70194620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 70294620Sjhb } else { 70394620Sjhb PROC_UNLOCK(p); 704103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 705103767Sjake sizeof(pstr)); 70694620Sjhb if (error) 70794620Sjhb return (error); 70894620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 70994620Sjhb sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 71094620Sjhb sbuf_printf(sb, "%c", '\0'); 71178113Sdes } 71278113Sdes } 71378113Sdes 71478113Sdes return (0); 71578113Sdes} 71678113Sdes 71778113Sdes/* 71878113Sdes * Filler function for proc/net/dev 71978113Sdes */ 72078025Sdesstatic int 72178025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 72274135Sjlemon{ 72385129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 72474135Sjlemon struct ifnet *ifp; 72574135Sjlemon 72685129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 72783926Sdes "Inter-", " Receive", " Transmit", " face", 72885129Sdes "bytes packets errs drop fifo frame compressed", 72983926Sdes "bytes packets errs drop fifo frame compressed"); 73074135Sjlemon 731108172Shsu IFNET_RLOCK(); 73274135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 73385129Sdes linux_ifname(ifp, ifname, sizeof ifname); 73485129Sdes sbuf_printf(sb, "%6.6s:", ifname); 73583926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 73683926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 73783926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 73883926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 73974135Sjlemon } 740108172Shsu IFNET_RUNLOCK(); 74178025Sdes 74278025Sdes return (0); 74374135Sjlemon} 74474135Sjlemon 74585538Sphk#if 0 74685538Sphkextern struct cdevsw *cdevsw[]; 74785538Sphk 74878113Sdes/* 74978113Sdes * Filler function for proc/devices 75078113Sdes */ 75178025Sdesstatic int 75278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 75374135Sjlemon{ 75474135Sjlemon int i; 75574135Sjlemon 75678025Sdes sbuf_printf(sb, "Character devices:\n"); 75774135Sjlemon 75878025Sdes for (i = 0; i < NUMCDEVSW; i++) 75974135Sjlemon if (cdevsw[i] != NULL) 76078025Sdes sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 76174135Sjlemon 76278025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 76378025Sdes 76478025Sdes return (0); 76574135Sjlemon} 76685538Sphk#endif 76774135Sjlemon 76878113Sdes/* 76978113Sdes * Filler function for proc/cmdline 77078113Sdes */ 77178025Sdesstatic int 77278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 77374135Sjlemon{ 77478025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 77578025Sdes sbuf_printf(sb, " ro root=302\n"); 77678025Sdes return (0); 77778025Sdes} 77874135Sjlemon 77983926Sdes#if 0 78078025Sdes/* 78183926Sdes * Filler function for proc/modules 78283926Sdes */ 78383926Sdesstatic int 78483926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 78583926Sdes{ 78683926Sdes struct linker_file *lf; 78783926Sdes 78883926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 78983926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 79083926Sdes (unsigned long)lf->size, lf->refs); 79183926Sdes } 79283926Sdes return (0); 79383926Sdes} 79483926Sdes#endif 79583926Sdes 79683926Sdes/* 79785129Sdes * Constructor 79878025Sdes */ 79985129Sdesstatic int 80085129Sdeslinprocfs_init(PFS_INIT_ARGS) 80185129Sdes{ 80285129Sdes struct pfs_node *root; 80385129Sdes struct pfs_node *dir; 80474135Sjlemon 80585129Sdes root = pi->pi_root; 80678025Sdes 80785129Sdes#define PFS_CREATE_FILE(name) \ 80885129Sdes pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 80985129Sdes PFS_CREATE_FILE(cmdline); 81085129Sdes PFS_CREATE_FILE(cpuinfo); 81185538Sphk#if 0 81285129Sdes PFS_CREATE_FILE(devices); 81385538Sphk#endif 81485129Sdes PFS_CREATE_FILE(loadavg); 81585129Sdes PFS_CREATE_FILE(meminfo); 81683926Sdes#if 0 81785129Sdes PFS_CREATE_FILE(modules); 81883926Sdes#endif 81985289Sdes PFS_CREATE_FILE(mtab); 82085129Sdes PFS_CREATE_FILE(stat); 82185129Sdes PFS_CREATE_FILE(uptime); 82285129Sdes PFS_CREATE_FILE(version); 82385129Sdes#undef PFS_CREATE_FILE 82487543Sdes pfs_create_link(root, "self", &procfs_docurproc, 82585129Sdes NULL, NULL, 0); 82678025Sdes 82785129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 82885129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 82985129Sdes NULL, NULL, PFS_RD); 83078025Sdes 83185129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 83285129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 83385129Sdes NULL, NULL, PFS_RD); 83487543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 83587543Sdes NULL, &procfs_notsystem, 0); 83685129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 83785129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 83885129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 83985129Sdes NULL, NULL, PFS_RD); 84085129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 84185129Sdes NULL, NULL, PFS_RD); 84285129Sdes 84385129Sdes return (0); 84485129Sdes} 84585129Sdes 84685129Sdes/* 84785129Sdes * Destructor 84885129Sdes */ 84985129Sdesstatic int 85085129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 85185129Sdes{ 85285129Sdes 85385129Sdes /* nothing to do, pseudofs will GC */ 85485129Sdes return (0); 85585129Sdes} 85685129Sdes 85785129SdesPSEUDOFS(linprocfs, 1); 85878025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 85978025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 860