linprocfs.c revision 87543
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 87543 2001-12-09 00:38:59Z des $ 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 9387275Srwatson#include <machine/../linux/linux.h> 9485129Sdes#include <compat/linux/linux_ioctl.h> 9569995Sdes#include <compat/linux/linux_mib.h> 9685289Sdes#include <compat/linux/linux_util.h> 9778025Sdes#include <fs/pseudofs/pseudofs.h> 9884248Sdes#include <fs/procfs/procfs.h> 9959412Smsmith 10067588Sdes/* 10167588Sdes * Various conversion macros 10267588Sdes */ 10376405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10567588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10669799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10767588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10867588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10974135Sjlemon 11078113Sdes/* 11178113Sdes * Filler function for proc/meminfo 11278113Sdes */ 11378025Sdesstatic int 11478025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 11559412Smsmith{ 11659412Smsmith unsigned long memtotal; /* total memory in bytes */ 11759412Smsmith unsigned long memused; /* used memory in bytes */ 11859412Smsmith unsigned long memfree; /* free memory in bytes */ 11959412Smsmith unsigned long memshared; /* shared memory ??? */ 12059412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 12176839Sjlemon u_quad_t swaptotal; /* total swap space in bytes */ 12276839Sjlemon u_quad_t swapused; /* used swap space in bytes */ 12376839Sjlemon u_quad_t swapfree; /* free swap space in bytes */ 12460860Sdes vm_object_t object; 12559412Smsmith 12659412Smsmith memtotal = physmem * PAGE_SIZE; 12759412Smsmith /* 12859412Smsmith * The correct thing here would be: 12959412Smsmith * 13059412Smsmith memfree = cnt.v_free_count * PAGE_SIZE; 13159412Smsmith memused = memtotal - memfree; 13259412Smsmith * 13359412Smsmith * but it might mislead linux binaries into thinking there 13459412Smsmith * is very little memory left, so we cheat and tell them that 13559412Smsmith * all memory that isn't wired down is free. 13659412Smsmith */ 13759412Smsmith memused = cnt.v_wire_count * PAGE_SIZE; 13859412Smsmith memfree = memtotal - memused; 13964560Sbde if (swapblist == NULL) { 14064560Sbde swaptotal = 0; 14164560Sbde swapfree = 0; 14264560Sbde } else { 14376839Sjlemon swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */ 14476839Sjlemon swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 14564560Sbde } 14659412Smsmith swapused = swaptotal - swapfree; 14760860Sdes memshared = 0; 14871471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 14960860Sdes if (object->shadow_count > 1) 15060860Sdes memshared += object->resident_page_count; 15160860Sdes memshared *= PAGE_SIZE; 15259412Smsmith /* 15359412Smsmith * We'd love to be able to write: 15459412Smsmith * 15559412Smsmith buffers = bufspace; 15659412Smsmith * 15759412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 15859412Smsmith * like unstaticizing it just for linprocfs's sake. 15959412Smsmith */ 16059412Smsmith buffers = 0; 16159412Smsmith cached = cnt.v_cache_count * PAGE_SIZE; 16259412Smsmith 16378025Sdes sbuf_printf(sb, 16478031Sdes " total: used: free: shared: buffers: cached:\n" 16569799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 16676839Sjlemon "Swap: %llu %llu %llu\n" 16769799Sdes "MemTotal: %9lu kB\n" 16869799Sdes "MemFree: %9lu kB\n" 16969799Sdes "MemShared:%9lu kB\n" 17069799Sdes "Buffers: %9lu kB\n" 17169799Sdes "Cached: %9lu kB\n" 17276839Sjlemon "SwapTotal:%9llu kB\n" 17376839Sjlemon "SwapFree: %9llu kB\n", 17469799Sdes memtotal, memused, memfree, memshared, buffers, cached, 17569799Sdes swaptotal, swapused, swapfree, 17669799Sdes B2K(memtotal), B2K(memfree), 17769799Sdes B2K(memshared), B2K(buffers), B2K(cached), 17869799Sdes B2K(swaptotal), B2K(swapfree)); 17959412Smsmith 18078025Sdes return (0); 18159412Smsmith} 18259412Smsmith 18378113Sdes#ifdef __alpha__ 18478113Sdes/* 18578113Sdes * Filler function for proc/cpuinfo (Alpha version) 18678113Sdes */ 18778025Sdesstatic int 18878025Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 18959412Smsmith{ 19078113Sdes u_int64_t type, major; 19178113Sdes struct pcs *pcsp; 19278113Sdes const char *model, *sysname; 19378113Sdes 19478113Sdes static const char *cpuname[] = { 19578113Sdes "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", 19678113Sdes "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" 19778113Sdes }; 19878113Sdes 19978113Sdes pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 20078113Sdes type = pcsp->pcs_proc_type; 20178113Sdes major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; 20278113Sdes if (major < sizeof(cpuname)/sizeof(char *)) { 20378113Sdes model = cpuname[major - 1]; 20478113Sdes } else { 20578113Sdes model = "unknown"; 20678113Sdes } 20778113Sdes 20878113Sdes sysname = alpha_dsr_sysname(); 20978113Sdes 21078113Sdes sbuf_printf(sb, 21178113Sdes "cpu\t\t\t: Alpha\n" 21278113Sdes "cpu model\t\t: %s\n" 21378113Sdes "cpu variation\t\t: %ld\n" 21478113Sdes "cpu revision\t\t: %ld\n" 21578113Sdes "cpu serial number\t: %s\n" 21678113Sdes "system type\t\t: %s\n" 21778113Sdes "system variation\t: %s\n" 21878113Sdes "system revision\t\t: %ld\n" 21978113Sdes "system serial number\t: %s\n" 22078113Sdes "cycle frequency [Hz]\t: %lu\n" 22178113Sdes "timer frequency [Hz]\t: %lu\n" 22278113Sdes "page size [bytes]\t: %ld\n" 22378113Sdes "phys. address bits\t: %ld\n" 22478113Sdes "max. addr. space #\t: %ld\n" 22578113Sdes "BogoMIPS\t\t: %lu.%02lu\n" 22678113Sdes "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 22778113Sdes "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 22878113Sdes "platform string\t\t: %s\n" 22978113Sdes "cpus detected\t\t: %d\n" 23078113Sdes , 23178113Sdes model, 23278113Sdes pcsp->pcs_proc_var, 23378113Sdes *(int *)hwrpb->rpb_revision, 23478113Sdes " ", 23578113Sdes " ", 23678113Sdes "0", 23778113Sdes 0, 23878113Sdes " ", 23978113Sdes hwrpb->rpb_cc_freq, 24078113Sdes hz, 24178113Sdes hwrpb->rpb_page_size, 24278113Sdes hwrpb->rpb_phys_addr_size, 24378113Sdes hwrpb->rpb_max_asn, 24478113Sdes 0, 0, 24578113Sdes 0, 0, 0, 24678113Sdes 0, 0, 0, 24778113Sdes sysname, 24878113Sdes ncpus); 24978113Sdes return (0); 25078113Sdes} 25178113Sdes#endif /* __alpha__ */ 25278113Sdes 25378113Sdes#ifdef __i386__ 25478113Sdes/* 25578113Sdes * Filler function for proc/cpuinfo (i386 version) 25678113Sdes */ 25778113Sdesstatic int 25878113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 25978113Sdes{ 26069799Sdes int class, i, fqmhz, fqkhz; 26159412Smsmith 26269799Sdes /* 26378031Sdes * We default the flags to include all non-conflicting flags, 26478031Sdes * and the Intel versions of conflicting flags. 26569799Sdes */ 26678031Sdes static char *flags[] = { 26778031Sdes "fpu", "vme", "de", "pse", "tsc", 26878031Sdes "msr", "pae", "mce", "cx8", "apic", 26978031Sdes "sep", "sep", "mtrr", "pge", "mca", 27078031Sdes "cmov", "pat", "pse36", "pn", "b19", 27178031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 27278031Sdes "xmm", "b26", "b27", "b28", "b29", 27367589Sdes "3dnowext", "3dnow" 27467589Sdes }; 27567589Sdes 27659412Smsmith switch (cpu_class) { 27759412Smsmith case CPUCLASS_286: 27867589Sdes class = 2; 27959412Smsmith break; 28059412Smsmith case CPUCLASS_386: 28167589Sdes class = 3; 28259412Smsmith break; 28359412Smsmith case CPUCLASS_486: 28467589Sdes class = 4; 28559412Smsmith break; 28659412Smsmith case CPUCLASS_586: 28767589Sdes class = 5; 28859412Smsmith break; 28959412Smsmith case CPUCLASS_686: 29067589Sdes class = 6; 29159412Smsmith break; 29259412Smsmith default: 29378031Sdes class = 0; 29459412Smsmith break; 29559412Smsmith } 29659412Smsmith 29778025Sdes sbuf_printf(sb, 29878031Sdes "processor\t: %d\n" 29969799Sdes "vendor_id\t: %.20s\n" 30069799Sdes "cpu family\t: %d\n" 30169799Sdes "model\t\t: %d\n" 30269799Sdes "stepping\t: %d\n", 30369799Sdes 0, cpu_vendor, class, cpu, cpu_id & 0xf); 30459412Smsmith 30578031Sdes sbuf_cat(sb, 30678031Sdes "flags\t\t:"); 30767589Sdes 30878031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 30967589Sdes flags[16] = "fcmov"; 31078031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 31167589Sdes flags[24] = "cxmmx"; 31278031Sdes } 31378031Sdes 31478031Sdes for (i = 0; i < 32; i++) 31567589Sdes if (cpu_feature & (1 << i)) 31678025Sdes sbuf_printf(sb, " %s", flags[i]); 31778025Sdes sbuf_cat(sb, "\n"); 31878031Sdes if (class >= 5) { 31969799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 32069799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 32178025Sdes sbuf_printf(sb, 32269799Sdes "cpu MHz\t\t: %d.%02d\n" 32369799Sdes "bogomips\t: %d.%02d\n", 32469799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 32578031Sdes } 32669995Sdes 32778025Sdes return (0); 32859412Smsmith} 32978113Sdes#endif /* __i386__ */ 33065633Sdes 33178113Sdes/* 33285289Sdes * Filler function for proc/mtab 33385289Sdes * 33485289Sdes * This file doesn't exist in Linux' procfs, but is included here so 33585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 33685289Sdes */ 33785289Sdesstatic int 33885289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 33985289Sdes{ 34085289Sdes struct nameidata nd; 34185289Sdes struct mount *mp; 34285289Sdes char *lep, *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; 34985289Sdes if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &lep, &flep) == -1) 35085289Sdes lep = linux_emul_path; 35185289Sdes lep_len = strlen(lep); 35285289Sdes 35385289Sdes mtx_lock(&mountlist_mtx); 35485289Sdes error = 0; 35585289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 35685289Sdes error = VFS_STATFS(mp, &mp->mnt_stat, td); 35785289Sdes if (error) 35885289Sdes break; 35985289Sdes 36085289Sdes /* determine device name */ 36185289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 36285289Sdes 36385289Sdes /* determine mount point */ 36485289Sdes mntto = mp->mnt_stat.f_mntonname; 36585289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 36685289Sdes mntto[lep_len] == '/') 36785289Sdes mntto += lep_len; 36885289Sdes 36985289Sdes /* determine fs type */ 37085289Sdes fstype = mp->mnt_stat.f_fstypename; 37185289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 37285289Sdes mntfrom = fstype = "proc"; 37385289Sdes else if (strcmp(fstype, "procfs") == 0) 37485289Sdes continue; 37585289Sdes 37685289Sdes sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 37785289Sdes mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 37885289Sdes#define ADD_OPTION(opt, name) \ 37985289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 38085289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 38185289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 38285289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 38385289Sdes ADD_OPTION(MNT_NODEV, "nodev"); 38485289Sdes ADD_OPTION(MNT_UNION, "union"); 38585289Sdes ADD_OPTION(MNT_ASYNC, "async"); 38685289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 38785289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 38885289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 38985289Sdes#undef ADD_OPTION 39085289Sdes /* a real Linux mtab will also show NFS options */ 39185289Sdes sbuf_printf(sb, " 0 0\n"); 39285289Sdes } 39385289Sdes mtx_unlock(&mountlist_mtx); 39485289Sdes if (flep != NULL) 39585289Sdes free(flep, M_TEMP); 39685289Sdes return (error); 39785289Sdes} 39885289Sdes 39985289Sdes/* 40078113Sdes * Filler function for proc/stat 40178113Sdes */ 40278025Sdesstatic int 40378025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 40465633Sdes{ 40578025Sdes sbuf_printf(sb, 40669799Sdes "cpu %ld %ld %ld %ld\n" 40769799Sdes "disk 0 0 0 0\n" 40869799Sdes "page %u %u\n" 40969799Sdes "swap %u %u\n" 41069799Sdes "intr %u\n" 41169799Sdes "ctxt %u\n" 41285657Sdillon "btime %lld\n", 41369799Sdes T2J(cp_time[CP_USER]), 41469799Sdes T2J(cp_time[CP_NICE]), 41569799Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 41669799Sdes T2J(cp_time[CP_IDLE]), 41769799Sdes cnt.v_vnodepgsin, 41869799Sdes cnt.v_vnodepgsout, 41969799Sdes cnt.v_swappgsin, 42069799Sdes cnt.v_swappgsout, 42169799Sdes cnt.v_intr, 42269799Sdes cnt.v_swtch, 42385657Sdillon (quad_t)boottime.tv_sec); 42478025Sdes return (0); 42565633Sdes} 42665633Sdes 42778113Sdes/* 42878113Sdes * Filler function for proc/uptime 42978113Sdes */ 43078025Sdesstatic int 43178025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 43265633Sdes{ 43365633Sdes struct timeval tv; 43465633Sdes 43565633Sdes getmicrouptime(&tv); 43685657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 43785657Sdillon (quad_t)tv.tv_sec, tv.tv_usec / 10000, 43869799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43978025Sdes return (0); 44065633Sdes} 44165633Sdes 44278113Sdes/* 44378113Sdes * Filler function for proc/version 44478113Sdes */ 44578025Sdesstatic int 44678025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 44765633Sdes{ 44887275Srwatson char osname[LINUX_MAX_UTSNAME]; 44987275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 45087275Srwatson 45187275Srwatson linux_get_osname(td->td_proc, osname); 45287275Srwatson linux_get_osrelease(td->td_proc, osrelease); 45387275Srwatson 45478025Sdes sbuf_printf(sb, 45569995Sdes "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 45687275Srwatson " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 45778025Sdes return (0); 45865633Sdes} 45965633Sdes 46078113Sdes/* 46178113Sdes * Filler function for proc/loadavg 46278113Sdes */ 46378025Sdesstatic int 46478025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 46576839Sjlemon{ 46678025Sdes sbuf_printf(sb, 46776839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 46876839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 46976839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 47076839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 47176839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 47276839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 47376839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 47476839Sjlemon 1, /* number of running tasks */ 47576839Sjlemon nprocs, /* number of tasks */ 47678116Sdes lastpid /* the last pid */ 47776839Sjlemon ); 47878025Sdes 47978025Sdes return (0); 48076839Sjlemon} 48176839Sjlemon 48278113Sdes/* 48378113Sdes * Filler function for proc/pid/stat 48478113Sdes */ 48578025Sdesstatic int 48678025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 48767588Sdes{ 48869995Sdes struct kinfo_proc kp; 48967588Sdes 49069995Sdes fill_kinfo_proc(p, &kp); 49178025Sdes sbuf_printf(sb, "%d", p->p_pid); 49278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 49367588Sdes PS_ADD("comm", "(%s)", p->p_comm); 49467588Sdes PS_ADD("statr", "%c", '0'); /* XXX */ 49573923Sjhb PROC_LOCK(p); 49673923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 49773923Sjhb PROC_UNLOCK(p); 49867588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 49967588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 50067588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 50167588Sdes PS_ADD("tpgid", "%d", 0); /* XXX */ 50267588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 50367588Sdes PS_ADD("minflt", "%u", 0); /* XXX */ 50467588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50567588Sdes PS_ADD("majflt", "%u", 0); /* XXX */ 50667588Sdes PS_ADD("cminflt", "%u", 0); /* XXX */ 50767588Sdes PS_ADD("utime", "%d", 0); /* XXX */ 50867588Sdes PS_ADD("stime", "%d", 0); /* XXX */ 50967588Sdes PS_ADD("cutime", "%d", 0); /* XXX */ 51067588Sdes PS_ADD("cstime", "%d", 0); /* XXX */ 51167588Sdes PS_ADD("counter", "%d", 0); /* XXX */ 51267588Sdes PS_ADD("priority", "%d", 0); /* XXX */ 51367588Sdes PS_ADD("timeout", "%u", 0); /* XXX */ 51467588Sdes PS_ADD("itrealvalue", "%u", 0); /* XXX */ 51567588Sdes PS_ADD("starttime", "%d", 0); /* XXX */ 51669995Sdes PS_ADD("vsize", "%u", kp.ki_size); 51769995Sdes PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 51867588Sdes PS_ADD("rlim", "%u", 0); /* XXX */ 51969995Sdes PS_ADD("startcode", "%u", (unsigned)0); 52067588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 52167588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 52269799Sdes PS_ADD("esp", "%u", 0); /* XXX */ 52369799Sdes PS_ADD("eip", "%u", 0); /* XXX */ 52467588Sdes PS_ADD("signal", "%d", 0); /* XXX */ 52567588Sdes PS_ADD("blocked", "%d", 0); /* XXX */ 52667588Sdes PS_ADD("sigignore", "%d", 0); /* XXX */ 52767588Sdes PS_ADD("sigcatch", "%d", 0); /* XXX */ 52867588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 52969799Sdes PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 53069799Sdes PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 53169799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 53269799Sdes PS_ADD("processor", "%d", 0); /* XXX */ 53367588Sdes#undef PS_ADD 53478025Sdes sbuf_putc(sb, '\n'); 53567588Sdes 53678025Sdes return (0); 53767588Sdes} 53867588Sdes 53967588Sdes/* 54067588Sdes * Map process state to descriptive letter. Note that this does not 54167588Sdes * quite correspond to what Linux outputs, but it's close enough. 54267588Sdes */ 54367588Sdesstatic char *state_str[] = { 54467588Sdes "? (unknown)", 54567588Sdes "I (idle)", 54667588Sdes "R (running)", 54767588Sdes "S (sleeping)", 54867588Sdes "T (stopped)", 54967588Sdes "Z (zombie)", 55067588Sdes "W (waiting)", 55167588Sdes "M (mutex)" 55267588Sdes}; 55367588Sdes 55478113Sdes/* 55578113Sdes * Filler function for proc/pid/status 55678113Sdes */ 55778025Sdesstatic int 55878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 55967588Sdes{ 56069995Sdes struct kinfo_proc kp; 56167588Sdes char *state; 56269799Sdes segsz_t lsize; 56374135Sjlemon int i; 56467588Sdes 56572200Sbmilekic mtx_lock_spin(&sched_lock); 56667588Sdes if (p->p_stat > sizeof state_str / sizeof *state_str) 56767588Sdes state = state_str[0]; 56867588Sdes else 56967588Sdes state = state_str[(int)p->p_stat]; 57072200Sbmilekic mtx_unlock_spin(&sched_lock); 57167588Sdes 57269995Sdes fill_kinfo_proc(p, &kp); 57378025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 57478031Sdes sbuf_printf(sb, "State:\t%s\n", state); 57567588Sdes 57667588Sdes /* 57767588Sdes * Credentials 57867588Sdes */ 57978025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 58071471Sjhb PROC_LOCK(p); 58178025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 58273923Sjhb p->p_pptr->p_pid : 0); 58378031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 58478031Sdes p->p_ucred->cr_uid, 58578031Sdes p->p_ucred->cr_svuid, 58678031Sdes /* FreeBSD doesn't have fsuid */ 58778031Sdes p->p_ucred->cr_uid); 58878031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 58978031Sdes p->p_ucred->cr_gid, 59078031Sdes p->p_ucred->cr_svgid, 59178031Sdes /* FreeBSD doesn't have fsgid */ 59278031Sdes p->p_ucred->cr_gid); 59378025Sdes sbuf_cat(sb, "Groups:\t"); 59467588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 59578031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 59671471Sjhb PROC_UNLOCK(p); 59778025Sdes sbuf_putc(sb, '\n'); 59867588Sdes 59967588Sdes /* 60067588Sdes * Memory 60169799Sdes * 60269799Sdes * While our approximation of VmLib may not be accurate (I 60369799Sdes * don't know of a simple way to verify it, and I'm not sure 60469799Sdes * it has much meaning anyway), I believe it's good enough. 60569799Sdes * 60669799Sdes * The same code that could (I think) accurately compute VmLib 60769799Sdes * could also compute VmLck, but I don't really care enough to 60869799Sdes * implement it. Submissions are welcome. 60967588Sdes */ 61078025Sdes sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 61178025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 61278025Sdes sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 61378025Sdes sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 61478025Sdes sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 61578025Sdes sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 61669995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 61769995Sdes kp.ki_ssize - kp.ki_tsize - 1; 61878025Sdes sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 61967588Sdes 62067588Sdes /* 62167588Sdes * Signal masks 62267588Sdes * 62367588Sdes * We support up to 128 signals, while Linux supports 32, 62467588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 62567588Sdes * just show the lower 32 bits of each mask. XXX hack. 62667588Sdes * 62767588Sdes * NB: on certain platforms (Sparc at least) Linux actually 62867588Sdes * supports 64 signals, but this code is a long way from 62967588Sdes * running on anything but i386, so ignore that for now. 63067588Sdes */ 63171471Sjhb PROC_LOCK(p); 63278025Sdes sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 63369799Sdes /* 63469799Sdes * I can't seem to find out where the signal mask is in 63569799Sdes * relation to struct proc, so SigBlk is left unimplemented. 63669799Sdes */ 63778025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 63878025Sdes sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 63978025Sdes sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 64071471Sjhb PROC_UNLOCK(p); 64167588Sdes 64267588Sdes /* 64367588Sdes * Linux also prints the capability masks, but we don't have 64467588Sdes * capabilities yet, and when we do get them they're likely to 64567588Sdes * be meaningless to Linux programs, so we lie. XXX 64667588Sdes */ 64778025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 64878025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 64978025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 65078025Sdes 65178025Sdes return (0); 65267588Sdes} 65374135Sjlemon 65478113Sdes/* 65578113Sdes * Filler function for proc/pid/cmdline 65678113Sdes */ 65778025Sdesstatic int 65878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 65978113Sdes{ 66078113Sdes struct ps_strings pstr; 66178113Sdes int error, i; 66278113Sdes 66378113Sdes /* 66478113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 66578113Sdes * revert back to the old way which only implements full cmdline 66678113Sdes * for the currept process and just p->p_comm for all other 66778113Sdes * processes. 66878113Sdes * Note that if the argv is no longer available, we deliberately 66978113Sdes * don't fall back on p->p_comm or return an error: the authentic 67078113Sdes * Linux behaviour is to return zero-length in this case. 67178113Sdes */ 67278113Sdes 67383366Sjulian if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) { 67478113Sdes sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 67583366Sjulian } else if (p != td->td_proc) { 67678113Sdes sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 67778113Sdes } else { 67878113Sdes error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); 67978113Sdes if (error) 68078113Sdes return (error); 68178113Sdes for (i = 0; i < pstr.ps_nargvstr; i++) { 68278113Sdes sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 68378113Sdes sbuf_printf(sb, "%c", '\0'); 68478113Sdes } 68578113Sdes } 68678113Sdes 68778113Sdes return (0); 68878113Sdes} 68978113Sdes 69078113Sdes/* 69178113Sdes * Filler function for proc/net/dev 69278113Sdes */ 69378025Sdesstatic int 69478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 69574135Sjlemon{ 69685129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 69774135Sjlemon struct ifnet *ifp; 69874135Sjlemon 69985129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 70083926Sdes "Inter-", " Receive", " Transmit", " face", 70185129Sdes "bytes packets errs drop fifo frame compressed", 70283926Sdes "bytes packets errs drop fifo frame compressed"); 70374135Sjlemon 70474135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 70585129Sdes linux_ifname(ifp, ifname, sizeof ifname); 70685129Sdes sbuf_printf(sb, "%6.6s:", ifname); 70783926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 70883926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 70983926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 71083926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 71174135Sjlemon } 71278025Sdes 71378025Sdes return (0); 71474135Sjlemon} 71574135Sjlemon 71685538Sphk#if 0 71785538Sphkextern struct cdevsw *cdevsw[]; 71885538Sphk 71978113Sdes/* 72078113Sdes * Filler function for proc/devices 72178113Sdes */ 72278025Sdesstatic int 72378025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 72474135Sjlemon{ 72574135Sjlemon int i; 72674135Sjlemon 72778025Sdes sbuf_printf(sb, "Character devices:\n"); 72874135Sjlemon 72978025Sdes for (i = 0; i < NUMCDEVSW; i++) 73074135Sjlemon if (cdevsw[i] != NULL) 73178025Sdes sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 73274135Sjlemon 73378025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 73478025Sdes 73578025Sdes return (0); 73674135Sjlemon} 73785538Sphk#endif 73874135Sjlemon 73978113Sdes/* 74078113Sdes * Filler function for proc/cmdline 74178113Sdes */ 74278025Sdesstatic int 74378025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 74474135Sjlemon{ 74578025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 74678025Sdes sbuf_printf(sb, " ro root=302\n"); 74778025Sdes return (0); 74878025Sdes} 74974135Sjlemon 75083926Sdes#if 0 75178025Sdes/* 75283926Sdes * Filler function for proc/modules 75383926Sdes */ 75483926Sdesstatic int 75583926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 75683926Sdes{ 75783926Sdes struct linker_file *lf; 75883926Sdes 75983926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 76083926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 76183926Sdes (unsigned long)lf->size, lf->refs); 76283926Sdes } 76383926Sdes return (0); 76483926Sdes} 76583926Sdes#endif 76683926Sdes 76783926Sdes/* 76885129Sdes * Constructor 76978025Sdes */ 77085129Sdesstatic int 77185129Sdeslinprocfs_init(PFS_INIT_ARGS) 77285129Sdes{ 77385129Sdes struct pfs_node *root; 77485129Sdes struct pfs_node *dir; 77574135Sjlemon 77685129Sdes root = pi->pi_root; 77778025Sdes 77885129Sdes#define PFS_CREATE_FILE(name) \ 77985129Sdes pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 78085129Sdes PFS_CREATE_FILE(cmdline); 78185129Sdes PFS_CREATE_FILE(cpuinfo); 78285538Sphk#if 0 78385129Sdes PFS_CREATE_FILE(devices); 78485538Sphk#endif 78585129Sdes PFS_CREATE_FILE(loadavg); 78685129Sdes PFS_CREATE_FILE(meminfo); 78783926Sdes#if 0 78885129Sdes PFS_CREATE_FILE(modules); 78983926Sdes#endif 79085289Sdes PFS_CREATE_FILE(mtab); 79185129Sdes PFS_CREATE_FILE(stat); 79285129Sdes PFS_CREATE_FILE(uptime); 79385129Sdes PFS_CREATE_FILE(version); 79485129Sdes#undef PFS_CREATE_FILE 79587543Sdes pfs_create_link(root, "self", &procfs_docurproc, 79685129Sdes NULL, NULL, 0); 79778025Sdes 79885129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 79985129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 80085129Sdes NULL, NULL, PFS_RD); 80178025Sdes 80285129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 80385129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 80485129Sdes NULL, NULL, PFS_RD); 80587543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 80687543Sdes NULL, &procfs_notsystem, 0); 80785129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 80885129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 80985129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 81085129Sdes NULL, NULL, PFS_RD); 81185129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 81285129Sdes NULL, NULL, PFS_RD); 81385129Sdes 81485129Sdes return (0); 81585129Sdes} 81685129Sdes 81785129Sdes/* 81885129Sdes * Destructor 81985129Sdes */ 82085129Sdesstatic int 82185129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 82285129Sdes{ 82385129Sdes 82485129Sdes /* nothing to do, pseudofs will GC */ 82585129Sdes return (0); 82685129Sdes} 82785129Sdes 82885129SdesPSEUDOFS(linprocfs, 1); 82978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 83078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 831