linprocfs.c revision 205541
1139743Simp/*- 2184691Sdes * 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 42182141Sjulian#include "opt_compat.h" 43182141Sjulian 44116173Sobrien#include <sys/cdefs.h> 45116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 205541 2010-03-23 21:49:33Z jhb $"); 46116173Sobrien 4759412Smsmith#include <sys/param.h> 4883926Sdes#include <sys/queue.h> 4976166Smarkm#include <sys/blist.h> 5074135Sjlemon#include <sys/conf.h> 5183926Sdes#include <sys/exec.h> 52177785Skib#include <sys/fcntl.h> 53119911Sdes#include <sys/filedesc.h> 5476166Smarkm#include <sys/jail.h> 5565633Sdes#include <sys/kernel.h> 5683926Sdes#include <sys/linker.h> 5776166Smarkm#include <sys/lock.h> 5874135Sjlemon#include <sys/malloc.h> 5978025Sdes#include <sys/mount.h> 60168067Sjkim#include <sys/msg.h> 6176827Salfred#include <sys/mutex.h> 6285289Sdes#include <sys/namei.h> 6365633Sdes#include <sys/proc.h> 6465633Sdes#include <sys/resourcevar.h> 6569995Sdes#include <sys/sbuf.h> 66168067Sjkim#include <sys/sem.h> 67123246Sdes#include <sys/smp.h> 6883926Sdes#include <sys/socket.h> 6976839Sjlemon#include <sys/sysctl.h> 7083926Sdes#include <sys/systm.h> 71159995Snetchild#include <sys/time.h> 7265633Sdes#include <sys/tty.h> 7383926Sdes#include <sys/user.h> 7483926Sdes#include <sys/vmmeter.h> 7559412Smsmith#include <sys/vnode.h> 76190445Sambrisko#include <sys/bus.h> 7759412Smsmith 7883926Sdes#include <net/if.h> 79185571Sbz#include <net/vnet.h> 8083926Sdes 8159412Smsmith#include <vm/vm.h> 82185984Skib#include <vm/vm_extern.h> 8359412Smsmith#include <vm/pmap.h> 8467588Sdes#include <vm/vm_map.h> 8559412Smsmith#include <vm/vm_param.h> 8660860Sdes#include <vm/vm_object.h> 8759412Smsmith#include <vm/swap_pager.h> 8869799Sdes 8967589Sdes#include <machine/clock.h> 9078113Sdes 91190445Sambrisko#include <geom/geom.h> 92190445Sambrisko#include <geom/geom_int.h> 93190445Sambrisko 94133822Stjr#if defined(__i386__) || defined(__amd64__) 9567589Sdes#include <machine/cputypes.h> 9659412Smsmith#include <machine/md_var.h> 97133822Stjr#endif /* __i386__ || __amd64__ */ 9859412Smsmith 99140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 100140214Sobrien#include <machine/../linux32/linux.h> 101140214Sobrien#else 10287275Srwatson#include <machine/../linux/linux.h> 103133822Stjr#endif 10485129Sdes#include <compat/linux/linux_ioctl.h> 10569995Sdes#include <compat/linux/linux_mib.h> 10685289Sdes#include <compat/linux/linux_util.h> 10778025Sdes#include <fs/pseudofs/pseudofs.h> 10884248Sdes#include <fs/procfs/procfs.h> 10959412Smsmith 11067588Sdes/* 11167588Sdes * Various conversion macros 11267588Sdes */ 11376405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 11467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 11567588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 11669799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 11767588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11867588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11974135Sjlemon 120159995Snetchild/** 121159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 122159995Snetchild * 123159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 124159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 125172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 126159995Snetchild * or stopped, or process is paging respectively. 127159995Snetchild * 128159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 129159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 130159995Snetchild * 131159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 132159995Snetchild * map our states to suitable linux states. 133159995Snetchild */ 134166140Snetchildstatic char linux_state[] = "RRSTZDD"; 135159995Snetchild 13678113Sdes/* 13778113Sdes * Filler function for proc/meminfo 13878113Sdes */ 13978025Sdesstatic int 14078025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 14159412Smsmith{ 14259412Smsmith unsigned long memtotal; /* total memory in bytes */ 14359412Smsmith unsigned long memused; /* used memory in bytes */ 14459412Smsmith unsigned long memfree; /* free memory in bytes */ 14559412Smsmith unsigned long memshared; /* shared memory ??? */ 14659412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 147113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 148113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 149113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 15060860Sdes vm_object_t object; 151117723Sphk int i, j; 15259412Smsmith 15359412Smsmith memtotal = physmem * PAGE_SIZE; 15459412Smsmith /* 15559412Smsmith * The correct thing here would be: 15659412Smsmith * 157170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15859412Smsmith memused = memtotal - memfree; 15959412Smsmith * 16059412Smsmith * but it might mislead linux binaries into thinking there 16159412Smsmith * is very little memory left, so we cheat and tell them that 16259412Smsmith * all memory that isn't wired down is free. 16359412Smsmith */ 164170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 16559412Smsmith memfree = memtotal - memused; 166117723Sphk swap_pager_status(&i, &j); 167153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 168153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 169117723Sphk swapfree = swaptotal - swapused; 17060860Sdes memshared = 0; 171124082Salc mtx_lock(&vm_object_list_mtx); 17271471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 17360860Sdes if (object->shadow_count > 1) 17460860Sdes memshared += object->resident_page_count; 175124082Salc mtx_unlock(&vm_object_list_mtx); 17660860Sdes memshared *= PAGE_SIZE; 17759412Smsmith /* 17859412Smsmith * We'd love to be able to write: 17959412Smsmith * 18059412Smsmith buffers = bufspace; 18159412Smsmith * 18259412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 18359412Smsmith * like unstaticizing it just for linprocfs's sake. 18459412Smsmith */ 18559412Smsmith buffers = 0; 186170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 18759412Smsmith 18878025Sdes sbuf_printf(sb, 18978031Sdes " total: used: free: shared: buffers: cached:\n" 19069799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 19176839Sjlemon "Swap: %llu %llu %llu\n" 19269799Sdes "MemTotal: %9lu kB\n" 19369799Sdes "MemFree: %9lu kB\n" 19469799Sdes "MemShared:%9lu kB\n" 19569799Sdes "Buffers: %9lu kB\n" 19669799Sdes "Cached: %9lu kB\n" 19776839Sjlemon "SwapTotal:%9llu kB\n" 19876839Sjlemon "SwapFree: %9llu kB\n", 19969799Sdes memtotal, memused, memfree, memshared, buffers, cached, 20069799Sdes swaptotal, swapused, swapfree, 20169799Sdes B2K(memtotal), B2K(memfree), 20269799Sdes B2K(memshared), B2K(buffers), B2K(cached), 20369799Sdes B2K(swaptotal), B2K(swapfree)); 20459412Smsmith 20578025Sdes return (0); 20659412Smsmith} 20759412Smsmith 208133822Stjr#if defined(__i386__) || defined(__amd64__) 20978113Sdes/* 210133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 21178113Sdes */ 21278113Sdesstatic int 21378113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 21478113Sdes{ 215159544Sdes int hw_model[2]; 216159544Sdes char model[128]; 217159544Sdes size_t size; 218123246Sdes int class, fqmhz, fqkhz; 219118421Sdes int i; 22059412Smsmith 22169799Sdes /* 22278031Sdes * We default the flags to include all non-conflicting flags, 22378031Sdes * and the Intel versions of conflicting flags. 22469799Sdes */ 22578031Sdes static char *flags[] = { 22678031Sdes "fpu", "vme", "de", "pse", "tsc", 22778031Sdes "msr", "pae", "mce", "cx8", "apic", 22878031Sdes "sep", "sep", "mtrr", "pge", "mca", 22978031Sdes "cmov", "pat", "pse36", "pn", "b19", 23078031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 231183385Scognet "xmm", "sse2", "b27", "b28", "b29", 23267589Sdes "3dnowext", "3dnow" 23367589Sdes }; 23467589Sdes 23559412Smsmith switch (cpu_class) { 236133822Stjr#ifdef __i386__ 23759412Smsmith case CPUCLASS_286: 23867589Sdes class = 2; 23959412Smsmith break; 24059412Smsmith case CPUCLASS_386: 24167589Sdes class = 3; 24259412Smsmith break; 24359412Smsmith case CPUCLASS_486: 24467589Sdes class = 4; 24559412Smsmith break; 24659412Smsmith case CPUCLASS_586: 24767589Sdes class = 5; 24859412Smsmith break; 24959412Smsmith case CPUCLASS_686: 25067589Sdes class = 6; 25159412Smsmith break; 25259412Smsmith default: 25378031Sdes class = 0; 25459412Smsmith break; 255159170Sdes#else /* __amd64__ */ 256133822Stjr default: 257159170Sdes class = 15; 258133822Stjr break; 259133822Stjr#endif 26059412Smsmith } 26159412Smsmith 262159544Sdes hw_model[0] = CTL_HW; 263159544Sdes hw_model[1] = HW_MODEL; 264159544Sdes model[0] = '\0'; 265159544Sdes size = sizeof(model); 266159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 267159544Sdes strcpy(model, "unknown"); 268123246Sdes for (i = 0; i < mp_ncpus; ++i) { 269118421Sdes sbuf_printf(sb, 270118421Sdes "processor\t: %d\n" 271118421Sdes "vendor_id\t: %.20s\n" 272118421Sdes "cpu family\t: %d\n" 273118421Sdes "model\t\t: %d\n" 274159544Sdes "model name\t: %s\n" 275118421Sdes "stepping\t: %d\n", 276159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 277159544Sdes /* XXX per-cpu vendor / class / model / id? */ 278118421Sdes } 27959412Smsmith 280185766Skib sbuf_cat(sb, "flags\t\t:"); 28167589Sdes 282187594Sjkim#ifdef __i386__ 283187594Sjkim switch (cpu_vendor_id) { 284187594Sjkim case CPU_VENDOR_AMD: 285187594Sjkim if (class < 6) 286187594Sjkim flags[16] = "fcmov"; 287187594Sjkim break; 288187594Sjkim case CPU_VENDOR_CYRIX: 28967589Sdes flags[24] = "cxmmx"; 290187594Sjkim break; 29178031Sdes } 292187594Sjkim#endif 293119068Sdes 29478031Sdes for (i = 0; i < 32; i++) 29567589Sdes if (cpu_feature & (1 << i)) 29678025Sdes sbuf_printf(sb, " %s", flags[i]); 29778025Sdes sbuf_cat(sb, "\n"); 29878031Sdes if (class >= 5) { 29969799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 30069799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 30178025Sdes sbuf_printf(sb, 30269799Sdes "cpu MHz\t\t: %d.%02d\n" 30369799Sdes "bogomips\t: %d.%02d\n", 30469799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 30578031Sdes } 30669995Sdes 30778025Sdes return (0); 30859412Smsmith} 309133822Stjr#endif /* __i386__ || __amd64__ */ 31065633Sdes 31178113Sdes/* 31285289Sdes * Filler function for proc/mtab 31385289Sdes * 31485289Sdes * This file doesn't exist in Linux' procfs, but is included here so 31585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 31685289Sdes */ 31785289Sdesstatic int 31885289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 31985289Sdes{ 32085289Sdes struct nameidata nd; 32185289Sdes struct mount *mp; 32291334Sjulian const char *lep; 32391334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 32485289Sdes size_t lep_len; 32585289Sdes int error; 32685289Sdes 32785289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 328168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 32985289Sdes flep = NULL; 330168942Sdes error = namei(&nd); 331184649Sjhb lep = linux_emul_path; 332184649Sjhb if (error == 0) { 333188579Sjhb if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 334184649Sjhb lep = dlep; 335184649Sjhb vrele(nd.ni_vp); 336184649Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 337184649Sjhb } 33885289Sdes lep_len = strlen(lep); 339119068Sdes 34085289Sdes mtx_lock(&mountlist_mtx); 34185289Sdes error = 0; 34285289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 34385289Sdes /* determine device name */ 34485289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 345119068Sdes 34685289Sdes /* determine mount point */ 34785289Sdes mntto = mp->mnt_stat.f_mntonname; 34885289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 34985289Sdes mntto[lep_len] == '/') 35085289Sdes mntto += lep_len; 35185289Sdes 35285289Sdes /* determine fs type */ 35385289Sdes fstype = mp->mnt_stat.f_fstypename; 35485289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 35585289Sdes mntfrom = fstype = "proc"; 35685289Sdes else if (strcmp(fstype, "procfs") == 0) 35785289Sdes continue; 358119068Sdes 359158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 360158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 361158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 362158311Sambrisko } else { 363190445Sambrisko /* For Linux msdosfs is called vfat */ 364190445Sambrisko if (strcmp(fstype, "msdosfs") == 0) 365190445Sambrisko fstype = "vfat"; 366158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 367158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 368158311Sambrisko } 36985289Sdes#define ADD_OPTION(opt, name) \ 37085289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 37185289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 37285289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 37385289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 37485289Sdes ADD_OPTION(MNT_UNION, "union"); 37585289Sdes ADD_OPTION(MNT_ASYNC, "async"); 37685289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 37785289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 37885289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 37985289Sdes#undef ADD_OPTION 38085289Sdes /* a real Linux mtab will also show NFS options */ 38185289Sdes sbuf_printf(sb, " 0 0\n"); 38285289Sdes } 38385289Sdes mtx_unlock(&mountlist_mtx); 38485289Sdes if (flep != NULL) 38585289Sdes free(flep, M_TEMP); 38685289Sdes return (error); 38785289Sdes} 38885289Sdes 38985289Sdes/* 390190445Sambrisko * Filler function for proc/partitions 391190445Sambrisko * 392190445Sambrisko */ 393190445Sambriskostatic int 394190445Sambriskolinprocfs_dopartitions(PFS_FILL_ARGS) 395190445Sambrisko{ 396190445Sambrisko struct g_class *cp; 397190445Sambrisko struct g_geom *gp; 398190445Sambrisko struct g_provider *pp; 399190445Sambrisko struct nameidata nd; 400190445Sambrisko const char *lep; 401190445Sambrisko char *dlep, *flep; 402190445Sambrisko size_t lep_len; 403190445Sambrisko int error; 404190445Sambrisko int major, minor; 405190445Sambrisko 406190445Sambrisko /* resolve symlinks etc. in the emulation tree prefix */ 407190445Sambrisko NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 408190445Sambrisko flep = NULL; 409190445Sambrisko error = namei(&nd); 410190445Sambrisko lep = linux_emul_path; 411190445Sambrisko if (error == 0) { 412190445Sambrisko if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 413190445Sambrisko lep = dlep; 414190445Sambrisko vrele(nd.ni_vp); 415190445Sambrisko VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 416190445Sambrisko } 417190445Sambrisko lep_len = strlen(lep); 418190445Sambrisko 419190445Sambrisko g_topology_lock(); 420190445Sambrisko error = 0; 421190445Sambrisko sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 422190445Sambrisko "ruse wio wmerge wsect wuse running use aveq\n"); 423190445Sambrisko 424190445Sambrisko LIST_FOREACH(cp, &g_classes, class) { 425190445Sambrisko if (strcmp(cp->name, "DISK") == 0 || 426190445Sambrisko strcmp(cp->name, "PART") == 0) 427190445Sambrisko LIST_FOREACH(gp, &cp->geom, geom) { 428190445Sambrisko LIST_FOREACH(pp, &gp->provider, provider) { 429190445Sambrisko if (linux_driver_get_major_minor( 430190445Sambrisko pp->name, &major, &minor) != 0) { 431190445Sambrisko major = 0; 432190445Sambrisko minor = 0; 433190445Sambrisko } 434190445Sambrisko sbuf_printf(sb, "%d %d %lld %s " 435190445Sambrisko "%d %d %d %d %d " 436190445Sambrisko "%d %d %d %d %d %d\n", 437190445Sambrisko major, minor, 438190445Sambrisko (long long)pp->mediasize, pp->name, 439190445Sambrisko 0, 0, 0, 0, 0, 440190445Sambrisko 0, 0, 0, 0, 0, 0); 441190445Sambrisko } 442190445Sambrisko } 443190445Sambrisko } 444190445Sambrisko g_topology_unlock(); 445190445Sambrisko 446190445Sambrisko if (flep != NULL) 447190445Sambrisko free(flep, M_TEMP); 448190445Sambrisko return (error); 449190445Sambrisko} 450190445Sambrisko 451190445Sambrisko 452190445Sambrisko/* 45378113Sdes * Filler function for proc/stat 45478113Sdes */ 45578025Sdesstatic int 45678025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 45765633Sdes{ 458174070Speter struct pcpu *pcpu; 459174070Speter long cp_time[CPUSTATES]; 460174070Speter long *cp; 461123246Sdes int i; 462120339Sdes 463174070Speter read_cpu_time(cp_time); 464120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 465120339Sdes T2J(cp_time[CP_USER]), 466120339Sdes T2J(cp_time[CP_NICE]), 467120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 468120339Sdes T2J(cp_time[CP_IDLE])); 469174070Speter for (i = 0; i <= mp_maxid; ++i) { 470174070Speter if (CPU_ABSENT(i)) 471174070Speter continue; 472174070Speter pcpu = pcpu_find(i); 473174070Speter cp = pcpu->pc_cp_time; 474143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 475174070Speter T2J(cp[CP_USER]), 476174070Speter T2J(cp[CP_NICE]), 477174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 478174070Speter T2J(cp[CP_IDLE])); 479174070Speter } 48078025Sdes sbuf_printf(sb, 48169799Sdes "disk 0 0 0 0\n" 48269799Sdes "page %u %u\n" 48369799Sdes "swap %u %u\n" 48469799Sdes "intr %u\n" 48569799Sdes "ctxt %u\n" 48685657Sdillon "btime %lld\n", 487170170Sattilio cnt.v_vnodepgsin, 488170170Sattilio cnt.v_vnodepgsout, 489170170Sattilio cnt.v_swappgsin, 490170170Sattilio cnt.v_swappgsout, 491170170Sattilio cnt.v_intr, 492170170Sattilio cnt.v_swtch, 493113574Sjhb (long long)boottime.tv_sec); 49478025Sdes return (0); 49565633Sdes} 49665633Sdes 49778113Sdes/* 49878113Sdes * Filler function for proc/uptime 49978113Sdes */ 50078025Sdesstatic int 50178025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 50265633Sdes{ 503174070Speter long cp_time[CPUSTATES]; 50465633Sdes struct timeval tv; 50565633Sdes 50665633Sdes getmicrouptime(&tv); 507174070Speter read_cpu_time(cp_time); 50885657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 509113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 51069799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 51178025Sdes return (0); 51265633Sdes} 51365633Sdes 51478113Sdes/* 515167159Sjkim * Get OS build date 516167159Sjkim */ 517167159Sjkimstatic void 518167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 519167159Sjkim{ 520167159Sjkim#if 0 521167159Sjkim char osbuild[256]; 522167159Sjkim char *cp1, *cp2; 523167159Sjkim 524167159Sjkim strncpy(osbuild, version, 256); 525167159Sjkim osbuild[255] = '\0'; 526167159Sjkim cp1 = strstr(osbuild, "\n"); 527167159Sjkim cp2 = strstr(osbuild, ":"); 528167159Sjkim if (cp1 && cp2) { 529167159Sjkim *cp1 = *cp2 = '\0'; 530167159Sjkim cp1 = strstr(osbuild, "#"); 531167159Sjkim } else 532167159Sjkim cp1 = NULL; 533167159Sjkim if (cp1) 534167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 535167159Sjkim else 536167159Sjkim#endif 537167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 538167159Sjkim} 539167159Sjkim 540167159Sjkim/* 541167159Sjkim * Get OS builder 542167159Sjkim */ 543167159Sjkimstatic void 544167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 545167159Sjkim{ 546168762Sdes#if 0 547167159Sjkim char builder[256]; 548167159Sjkim char *cp; 549167159Sjkim 550167159Sjkim cp = strstr(version, "\n "); 551167159Sjkim if (cp) { 552167159Sjkim strncpy(builder, cp + 5, 256); 553167159Sjkim builder[255] = '\0'; 554167159Sjkim cp = strstr(builder, ":"); 555167159Sjkim if (cp) 556167159Sjkim *cp = '\0'; 557167159Sjkim } 558167159Sjkim if (cp) 559167159Sjkim sbuf_cat(sb, builder); 560167159Sjkim else 561168762Sdes#endif 562167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 563167159Sjkim} 564167159Sjkim 565167159Sjkim/* 56678113Sdes * Filler function for proc/version 56778113Sdes */ 56878025Sdesstatic int 56978025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 57065633Sdes{ 57187275Srwatson char osname[LINUX_MAX_UTSNAME]; 57287275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 57387275Srwatson 574112206Sjhb linux_get_osname(td, osname); 575112206Sjhb linux_get_osrelease(td, osrelease); 576167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 577167159Sjkim linprocfs_osbuilder(td, sb); 578167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 579167159Sjkim linprocfs_osbuild(td, sb); 580167159Sjkim sbuf_cat(sb, "\n"); 58187275Srwatson 58278025Sdes return (0); 58365633Sdes} 58465633Sdes 58578113Sdes/* 58678113Sdes * Filler function for proc/loadavg 58778113Sdes */ 58878025Sdesstatic int 58978025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 59076839Sjlemon{ 591168762Sdes 59278025Sdes sbuf_printf(sb, 59376839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 59476839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 59576839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 59676839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 59776839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 59876839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 59976839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 60076839Sjlemon 1, /* number of running tasks */ 60176839Sjlemon nprocs, /* number of tasks */ 60278116Sdes lastpid /* the last pid */ 60376839Sjlemon ); 60478025Sdes return (0); 60576839Sjlemon} 60676839Sjlemon 60778113Sdes/* 60878113Sdes * Filler function for proc/pid/stat 60978113Sdes */ 61078025Sdesstatic int 61178025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 61267588Sdes{ 61369995Sdes struct kinfo_proc kp; 614166140Snetchild char state; 615166140Snetchild static int ratelimit = 0; 61667588Sdes 61794307Sjhb PROC_LOCK(p); 61869995Sdes fill_kinfo_proc(p, &kp); 61978025Sdes sbuf_printf(sb, "%d", p->p_pid); 62078025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 62167588Sdes PS_ADD("comm", "(%s)", p->p_comm); 622166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 623166140Snetchild state = 'R'; 624166140Snetchild 625166141Snetchild if (ratelimit == 0) { 626166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 627166162Snetchild kp.ki_stat, sizeof(linux_state)); 628166141Snetchild ++ratelimit; 629166141Snetchild } 630166140Snetchild } else 631166140Snetchild state = linux_state[kp.ki_stat - 1]; 632166140Snetchild PS_ADD("state", "%c", state); 63373923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 63467588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 63567588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 63691140Stanimura PROC_UNLOCK(p); 63767588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 638159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 63967588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 640159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 641159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 642159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 643159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 644159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 645159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 646159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 647159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 648159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 649159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 650159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 651159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 652159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 653159995Snetchild It should be the number of jiffies between system boot and process 654159995Snetchild start. */ 655159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 656159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 657159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 658159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 65969995Sdes PS_ADD("startcode", "%u", (unsigned)0); 66067588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 66167588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 662159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 663159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 664159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 665159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 666159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 667159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 66867588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 669159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 670159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 67169799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 672159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 673159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 674159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 67567588Sdes#undef PS_ADD 67678025Sdes sbuf_putc(sb, '\n'); 677119068Sdes 67878025Sdes return (0); 67967588Sdes} 68067588Sdes 68167588Sdes/* 682119911Sdes * Filler function for proc/pid/statm 683119911Sdes */ 684119911Sdesstatic int 685119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 686119911Sdes{ 687119911Sdes struct kinfo_proc kp; 688119911Sdes segsz_t lsize; 689120340Sdes 690119911Sdes PROC_LOCK(p); 691119911Sdes fill_kinfo_proc(p, &kp); 692119911Sdes PROC_UNLOCK(p); 693119911Sdes 694119911Sdes /* 695119911Sdes * See comments in linprocfs_doprocstatus() regarding the 696119911Sdes * computation of lsize. 697119911Sdes */ 698119911Sdes /* size resident share trs drs lrs dt */ 699119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 700119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 701119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 702119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 703119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 704119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 705119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 706119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 707119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 708119911Sdes 709119911Sdes return (0); 710119911Sdes} 711119911Sdes 712119911Sdes/* 71378113Sdes * Filler function for proc/pid/status 71478113Sdes */ 71578025Sdesstatic int 71678025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 71767588Sdes{ 71869995Sdes struct kinfo_proc kp; 71967588Sdes char *state; 72069799Sdes segsz_t lsize; 72199072Sjulian struct thread *td2; 722114983Sjhb struct sigacts *ps; 72374135Sjlemon int i; 72467588Sdes 725113611Sjhb PROC_LOCK(p); 72699072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 72799072Sjulian 72899072Sjulian if (P_SHOULDSTOP(p)) { 72999072Sjulian state = "T (stopped)"; 73099072Sjulian } else { 731170307Sjeff PROC_SLOCK(p); 73299072Sjulian switch(p->p_state) { 73399072Sjulian case PRS_NEW: 73499072Sjulian state = "I (idle)"; 73599072Sjulian break; 73699072Sjulian case PRS_NORMAL: 73799072Sjulian if (p->p_flag & P_WEXIT) { 73899072Sjulian state = "X (exiting)"; 73999072Sjulian break; 74099072Sjulian } 74199072Sjulian switch(td2->td_state) { 742103216Sjulian case TDS_INHIBITED: 74399072Sjulian state = "S (sleeping)"; 74499072Sjulian break; 74599072Sjulian case TDS_RUNQ: 74699072Sjulian case TDS_RUNNING: 74799072Sjulian state = "R (running)"; 74899072Sjulian break; 74999072Sjulian default: 75099072Sjulian state = "? (unknown)"; 75199072Sjulian break; 75299072Sjulian } 75399072Sjulian break; 75499072Sjulian case PRS_ZOMBIE: 75599072Sjulian state = "Z (zombie)"; 75699072Sjulian break; 75799072Sjulian default: 75899072Sjulian state = "? (unknown)"; 75999072Sjulian break; 76099072Sjulian } 761170307Sjeff PROC_SUNLOCK(p); 76299072Sjulian } 76367588Sdes 76469995Sdes fill_kinfo_proc(p, &kp); 76578025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 76678031Sdes sbuf_printf(sb, "State:\t%s\n", state); 76767588Sdes 76867588Sdes /* 76967588Sdes * Credentials 77067588Sdes */ 77178025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 77278025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 77373923Sjhb p->p_pptr->p_pid : 0); 77478031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 77578031Sdes p->p_ucred->cr_uid, 77678031Sdes p->p_ucred->cr_svuid, 77778031Sdes /* FreeBSD doesn't have fsuid */ 77878031Sdes p->p_ucred->cr_uid); 77978031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 78078031Sdes p->p_ucred->cr_gid, 78178031Sdes p->p_ucred->cr_svgid, 78278031Sdes /* FreeBSD doesn't have fsgid */ 78378031Sdes p->p_ucred->cr_gid); 78478025Sdes sbuf_cat(sb, "Groups:\t"); 78567588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 78678031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 78771471Sjhb PROC_UNLOCK(p); 78878025Sdes sbuf_putc(sb, '\n'); 789119068Sdes 79067588Sdes /* 79167588Sdes * Memory 79269799Sdes * 79369799Sdes * While our approximation of VmLib may not be accurate (I 79469799Sdes * don't know of a simple way to verify it, and I'm not sure 79569799Sdes * it has much meaning anyway), I believe it's good enough. 79669799Sdes * 79769799Sdes * The same code that could (I think) accurately compute VmLib 79869799Sdes * could also compute VmLck, but I don't really care enough to 79969799Sdes * implement it. Submissions are welcome. 80067588Sdes */ 801113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 80278025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 803113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 804113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 805113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 806113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 80769995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 80869995Sdes kp.ki_ssize - kp.ki_tsize - 1; 809113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 81067588Sdes 81167588Sdes /* 81267588Sdes * Signal masks 81367588Sdes * 81467588Sdes * We support up to 128 signals, while Linux supports 32, 81567588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 81667588Sdes * just show the lower 32 bits of each mask. XXX hack. 81767588Sdes * 81867588Sdes * NB: on certain platforms (Sparc at least) Linux actually 81967588Sdes * supports 64 signals, but this code is a long way from 82067588Sdes * running on anything but i386, so ignore that for now. 82167588Sdes */ 82271471Sjhb PROC_LOCK(p); 823104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 82469799Sdes /* 82569799Sdes * I can't seem to find out where the signal mask is in 82669799Sdes * relation to struct proc, so SigBlk is left unimplemented. 82769799Sdes */ 82878025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 829114983Sjhb ps = p->p_sigacts; 830114983Sjhb mtx_lock(&ps->ps_mtx); 831114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 832114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 833114983Sjhb mtx_unlock(&ps->ps_mtx); 83471471Sjhb PROC_UNLOCK(p); 835119068Sdes 83667588Sdes /* 83767588Sdes * Linux also prints the capability masks, but we don't have 83867588Sdes * capabilities yet, and when we do get them they're likely to 83967588Sdes * be meaningless to Linux programs, so we lie. XXX 84067588Sdes */ 84178025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 84278025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 84378025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 844119068Sdes 84578025Sdes return (0); 84667588Sdes} 84774135Sjlemon 848119911Sdes 84978113Sdes/* 850119911Sdes * Filler function for proc/pid/cwd 851119911Sdes */ 852119911Sdesstatic int 853119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 854119911Sdes{ 855119911Sdes char *fullpath = "unknown"; 856119911Sdes char *freepath = NULL; 857119911Sdes 858119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 859119911Sdes sbuf_printf(sb, "%s", fullpath); 860119911Sdes if (freepath) 861119911Sdes free(freepath, M_TEMP); 862119911Sdes return (0); 863119911Sdes} 864119911Sdes 865119911Sdes/* 866119911Sdes * Filler function for proc/pid/root 867119911Sdes */ 868119911Sdesstatic int 869119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 870119911Sdes{ 871119911Sdes struct vnode *rvp; 872119911Sdes char *fullpath = "unknown"; 873119911Sdes char *freepath = NULL; 874119911Sdes 875119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 876119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 877119911Sdes sbuf_printf(sb, "%s", fullpath); 878119911Sdes if (freepath) 879119911Sdes free(freepath, M_TEMP); 880119911Sdes return (0); 881119911Sdes} 882119911Sdes 883119911Sdes/* 88478113Sdes * Filler function for proc/pid/cmdline 88578113Sdes */ 88678025Sdesstatic int 88778113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 88878113Sdes{ 88978113Sdes struct ps_strings pstr; 890138281Scperciva char **ps_argvstr; 89178113Sdes int error, i; 89278113Sdes 89378113Sdes /* 89478113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 89578113Sdes * revert back to the old way which only implements full cmdline 89678113Sdes * for the currept process and just p->p_comm for all other 89778113Sdes * processes. 89878113Sdes * Note that if the argv is no longer available, we deliberately 89978113Sdes * don't fall back on p->p_comm or return an error: the authentic 90078113Sdes * Linux behaviour is to return zero-length in this case. 90178113Sdes */ 90278113Sdes 90394620Sjhb PROC_LOCK(p); 904127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 90594620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 90694620Sjhb PROC_UNLOCK(p); 90794620Sjhb } else if (p != td->td_proc) { 90894620Sjhb PROC_UNLOCK(p); 90994620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 91094620Sjhb } else { 91194620Sjhb PROC_UNLOCK(p); 912103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 913103767Sjake sizeof(pstr)); 91494620Sjhb if (error) 91594620Sjhb return (error); 916138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 917138281Scperciva return (E2BIG); 918138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 919138281Scperciva M_TEMP, M_WAITOK); 920138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 921138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 922138281Scperciva if (error) { 923138281Scperciva free(ps_argvstr, M_TEMP); 924138281Scperciva return (error); 925138281Scperciva } 92694620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 927138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 92894620Sjhb sbuf_printf(sb, "%c", '\0'); 92978113Sdes } 930138281Scperciva free(ps_argvstr, M_TEMP); 93178113Sdes } 93278113Sdes 93378113Sdes return (0); 93478113Sdes} 93578113Sdes 93678113Sdes/* 937116173Sobrien * Filler function for proc/pid/environ 938116173Sobrien */ 939116173Sobrienstatic int 940116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 941116173Sobrien{ 942168762Sdes 943116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 944116173Sobrien return (0); 945116173Sobrien} 946116173Sobrien 947116173Sobrien/* 948116173Sobrien * Filler function for proc/pid/maps 949116173Sobrien */ 950116173Sobrienstatic int 951116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 952116173Sobrien{ 953185984Skib struct vmspace *vm; 954185984Skib vm_map_t map; 955185765Skib vm_map_entry_t entry, tmp_entry; 956121265Scognet vm_object_t obj, tobj, lobj; 957185765Skib vm_offset_t e_start, e_end; 958121265Scognet vm_ooffset_t off = 0; 959185765Skib vm_prot_t e_prot; 960185765Skib unsigned int last_timestamp; 961121265Scognet char *name = "", *freename = NULL; 962121265Scognet ino_t ino; 963121265Scognet int ref_count, shadow_count, flags; 964121265Scognet int error; 965137507Sphk struct vnode *vp; 966137507Sphk struct vattr vat; 967161094Skib int locked; 968168762Sdes 969121246Scognet PROC_LOCK(p); 970121246Scognet error = p_candebug(td, p); 971121246Scognet PROC_UNLOCK(p); 972121246Scognet if (error) 973121246Scognet return (error); 974168762Sdes 975121246Scognet if (uio->uio_rw != UIO_READ) 976121246Scognet return (EOPNOTSUPP); 977168762Sdes 978121246Scognet error = 0; 979185984Skib vm = vmspace_acquire_ref(p); 980185984Skib if (vm == NULL) 981185984Skib return (ESRCH); 982185984Skib map = &vm->vm_map; 983169156Salc vm_map_lock_read(map); 984183600Skib for (entry = map->header.next; entry != &map->header; 985121246Scognet entry = entry->next) { 986121265Scognet name = ""; 987121265Scognet freename = NULL; 988121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 989121246Scognet continue; 990185765Skib e_prot = entry->protection; 991185765Skib e_start = entry->start; 992185765Skib e_end = entry->end; 993121246Scognet obj = entry->object.vm_object; 994169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 995169156Salc VM_OBJECT_LOCK(tobj); 996169156Salc if (lobj != obj) 997169156Salc VM_OBJECT_UNLOCK(lobj); 998121246Scognet lobj = tobj; 999169156Salc } 1000185765Skib last_timestamp = map->timestamp; 1001185765Skib vm_map_unlock_read(map); 1002121246Scognet ino = 0; 1003121246Scognet if (lobj) { 1004121246Scognet off = IDX_TO_OFF(lobj->size); 1005161094Skib if (lobj->type == OBJT_VNODE) { 1006161094Skib vp = lobj->handle; 1007161094Skib if (vp) 1008161094Skib vref(vp); 1009121246Scognet } 1010161094Skib else 1011161094Skib vp = NULL; 1012169156Salc if (lobj != obj) 1013169156Salc VM_OBJECT_UNLOCK(lobj); 1014121246Scognet flags = obj->flags; 1015121246Scognet ref_count = obj->ref_count; 1016121246Scognet shadow_count = obj->shadow_count; 1017169156Salc VM_OBJECT_UNLOCK(obj); 1018161094Skib if (vp) { 1019161094Skib vn_fullpath(td, vp, &name, &freename); 1020161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 1021175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 1022182371Sattilio VOP_GETATTR(vp, &vat, td->td_ucred); 1023161094Skib ino = vat.va_fileid; 1024161094Skib vput(vp); 1025161094Skib VFS_UNLOCK_GIANT(locked); 1026161094Skib } 1027121246Scognet } else { 1028121246Scognet flags = 0; 1029121246Scognet ref_count = 0; 1030121246Scognet shadow_count = 0; 1031121246Scognet } 1032168762Sdes 1033121246Scognet /* 1034168762Sdes * format: 1035121246Scognet * start, end, access, offset, major, minor, inode, name. 1036121246Scognet */ 1037183600Skib error = sbuf_printf(sb, 1038121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1039185765Skib (u_long)e_start, (u_long)e_end, 1040185765Skib (e_prot & VM_PROT_READ)?"r":"-", 1041185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 1042185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 1043121246Scognet "p", 1044121265Scognet (u_long)off, 1045121246Scognet 0, 1046121246Scognet 0, 1047121265Scognet (u_long)ino, 1048121246Scognet *name ? " " : "", 1049121246Scognet name 1050121246Scognet ); 1051121246Scognet if (freename) 1052121246Scognet free(freename, M_TEMP); 1053185864Skib vm_map_lock_read(map); 1054183600Skib if (error == -1) { 1055183600Skib error = 0; 1056121246Scognet break; 1057169156Salc } 1058186563Skib if (last_timestamp != map->timestamp) { 1059185765Skib /* 1060185765Skib * Look again for the entry because the map was 1061185765Skib * modified while it was unlocked. Specifically, 1062185765Skib * the entry may have been clipped, merged, or deleted. 1063185765Skib */ 1064185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1065185765Skib entry = tmp_entry; 1066185765Skib } 1067121246Scognet } 1068169156Salc vm_map_unlock_read(map); 1069185984Skib vmspace_free(vm); 1070168762Sdes 1071121246Scognet return (error); 1072168762Sdes} 1073168762Sdes 1074116173Sobrien/* 107578113Sdes * Filler function for proc/net/dev 107678113Sdes */ 107778025Sdesstatic int 107878025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 107974135Sjlemon{ 108085129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 108174135Sjlemon struct ifnet *ifp; 108274135Sjlemon 108385129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 108483926Sdes "Inter-", " Receive", " Transmit", " face", 108585129Sdes "bytes packets errs drop fifo frame compressed", 108683926Sdes "bytes packets errs drop fifo frame compressed"); 108774135Sjlemon 1088196635Szec CURVNET_SET(TD_TO_VNET(curthread)); 1089108172Shsu IFNET_RLOCK(); 1090181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 109185129Sdes linux_ifname(ifp, ifname, sizeof ifname); 109285129Sdes sbuf_printf(sb, "%6.6s:", ifname); 109383926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 109483926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 109583926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 109683926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 109774135Sjlemon } 1098108172Shsu IFNET_RUNLOCK(); 1099196635Szec CURVNET_RESTORE(); 1100119068Sdes 110178025Sdes return (0); 110274135Sjlemon} 110374135Sjlemon 1104158311Sambrisko/* 1105167159Sjkim * Filler function for proc/sys/kernel/osrelease 1106167159Sjkim */ 1107167159Sjkimstatic int 1108167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1109167159Sjkim{ 1110167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1111167159Sjkim 1112167159Sjkim linux_get_osrelease(td, osrelease); 1113167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1114167159Sjkim 1115167159Sjkim return (0); 1116167159Sjkim} 1117167159Sjkim 1118167159Sjkim/* 1119167159Sjkim * Filler function for proc/sys/kernel/ostype 1120167159Sjkim */ 1121167159Sjkimstatic int 1122167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1123167159Sjkim{ 1124167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1125167159Sjkim 1126167159Sjkim linux_get_osname(td, osname); 1127167159Sjkim sbuf_printf(sb, "%s\n", osname); 1128167159Sjkim 1129167159Sjkim return (0); 1130167159Sjkim} 1131167159Sjkim 1132167159Sjkim/* 1133167159Sjkim * Filler function for proc/sys/kernel/version 1134167159Sjkim */ 1135167159Sjkimstatic int 1136167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1137167159Sjkim{ 1138168762Sdes 1139167159Sjkim linprocfs_osbuild(td, sb); 1140167159Sjkim sbuf_cat(sb, "\n"); 1141167159Sjkim return (0); 1142167159Sjkim} 1143167159Sjkim 1144167159Sjkim/* 1145164692Sjkim * Filler function for proc/sys/kernel/msgmni 1146164692Sjkim */ 1147164692Sjkimstatic int 1148164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1149164692Sjkim{ 1150164692Sjkim 1151168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1152164692Sjkim return (0); 1153164692Sjkim} 1154164692Sjkim 1155164692Sjkim/* 1156163251Skeramida * Filler function for proc/sys/kernel/pid_max 1157163129Snetchild */ 1158163129Snetchildstatic int 1159163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1160163129Snetchild{ 1161163757Snetchild 1162163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1163163129Snetchild return (0); 1164163129Snetchild} 1165163129Snetchild 1166163129Snetchild/* 1167164692Sjkim * Filler function for proc/sys/kernel/sem 1168164692Sjkim */ 1169164692Sjkimstatic int 1170164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1171164692Sjkim{ 1172164692Sjkim 1173168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1174168067Sjkim seminfo.semopm, seminfo.semmni); 1175164692Sjkim return (0); 1176164692Sjkim} 1177164692Sjkim 1178164692Sjkim/* 1179158311Sambrisko * Filler function for proc/scsi/device_info 1180158311Sambrisko */ 1181158311Sambriskostatic int 1182158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1183158311Sambrisko{ 1184168762Sdes 1185158311Sambrisko return (0); 1186158311Sambrisko} 1187158311Sambrisko 1188158311Sambrisko/* 1189158311Sambrisko * Filler function for proc/scsi/scsi 1190158311Sambrisko */ 1191158311Sambriskostatic int 1192158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1193158311Sambrisko{ 1194168762Sdes 1195158311Sambrisko return (0); 1196158311Sambrisko} 1197158311Sambrisko 119885538Sphkextern struct cdevsw *cdevsw[]; 119985538Sphk 120078113Sdes/* 120178113Sdes * Filler function for proc/devices 120278113Sdes */ 120378025Sdesstatic int 120478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 120574135Sjlemon{ 1206158311Sambrisko char *char_devices; 120778025Sdes sbuf_printf(sb, "Character devices:\n"); 120874135Sjlemon 1209158311Sambrisko char_devices = linux_get_char_devices(); 1210158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1211158311Sambrisko linux_free_get_char_devices(char_devices); 121274135Sjlemon 121378025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1214119068Sdes 121578025Sdes return (0); 121674135Sjlemon} 121774135Sjlemon 121878113Sdes/* 121978113Sdes * Filler function for proc/cmdline 122078113Sdes */ 122178025Sdesstatic int 122278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 122374135Sjlemon{ 1224168762Sdes 122578025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 122678025Sdes sbuf_printf(sb, " ro root=302\n"); 122778025Sdes return (0); 122878025Sdes} 122974135Sjlemon 1230205541Sjhb/* 1231205541Sjhb * Filler function for proc/filesystems 1232205541Sjhb */ 1233205541Sjhbstatic int 1234205541Sjhblinprocfs_dofilesystems(PFS_FILL_ARGS) 1235205541Sjhb{ 1236205541Sjhb struct vfsconf *vfsp; 1237205541Sjhb 1238205541Sjhb TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1239205541Sjhb if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1240205541Sjhb sbuf_printf(sb, "nodev"); 1241205541Sjhb sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1242205541Sjhb } 1243205541Sjhb return(0); 1244205541Sjhb} 1245205541Sjhb 124683926Sdes#if 0 124778025Sdes/* 124883926Sdes * Filler function for proc/modules 124983926Sdes */ 125083926Sdesstatic int 125183926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 125283926Sdes{ 125383926Sdes struct linker_file *lf; 1254119068Sdes 125583926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 125683926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 125783926Sdes (unsigned long)lf->size, lf->refs); 125883926Sdes } 125983926Sdes return (0); 126083926Sdes} 126183926Sdes#endif 126283926Sdes 126383926Sdes/* 1264204825Sed * Filler function for proc/pid/fd 1265204825Sed */ 1266204825Sedstatic int 1267204825Sedlinprocfs_dofdescfs(PFS_FILL_ARGS) 1268204825Sed{ 1269204825Sed 1270204825Sed if (p == curproc) 1271204825Sed sbuf_printf(sb, "/dev/fd"); 1272204825Sed else 1273204825Sed sbuf_printf(sb, "unknown"); 1274204825Sed return (0); 1275204825Sed} 1276204825Sed 1277204825Sed/* 127885129Sdes * Constructor 127978025Sdes */ 128085129Sdesstatic int 128185129Sdeslinprocfs_init(PFS_INIT_ARGS) 128285129Sdes{ 128385129Sdes struct pfs_node *root; 128485129Sdes struct pfs_node *dir; 128574135Sjlemon 128685129Sdes root = pi->pi_root; 128778025Sdes 1288119923Sdes /* /proc/... */ 1289119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1290167482Sdes NULL, NULL, NULL, PFS_RD); 1291119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1292167482Sdes NULL, NULL, NULL, PFS_RD); 1293119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1294167482Sdes NULL, NULL, NULL, PFS_RD); 1295205541Sjhb pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1296205541Sjhb NULL, NULL, NULL, PFS_RD); 1297119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1298167482Sdes NULL, NULL, NULL, PFS_RD); 1299119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1300167482Sdes NULL, NULL, NULL, PFS_RD); 130183926Sdes#if 0 1302119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1303167482Sdes NULL, NULL, NULL, PFS_RD); 130483926Sdes#endif 1305158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1306167482Sdes NULL, NULL, NULL, PFS_RD); 1307119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1308167482Sdes NULL, NULL, NULL, PFS_RD); 1309190445Sambrisko pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1310190445Sambrisko NULL, NULL, NULL, PFS_RD); 131187543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1312167482Sdes NULL, NULL, NULL, 0); 1313119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1314167482Sdes NULL, NULL, NULL, PFS_RD); 1315119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1316167482Sdes NULL, NULL, NULL, PFS_RD); 1317119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1318167482Sdes NULL, NULL, NULL, PFS_RD); 131978025Sdes 1320119923Sdes /* /proc/net/... */ 1321167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 132285129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1323167482Sdes NULL, NULL, NULL, PFS_RD); 132478025Sdes 1325119923Sdes /* /proc/<pid>/... */ 1326167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 132785129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1328167482Sdes NULL, NULL, NULL, PFS_RD); 1329119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1330167482Sdes NULL, NULL, NULL, 0); 1331116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1332167482Sdes NULL, NULL, NULL, PFS_RD); 133387543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1334167482Sdes NULL, &procfs_notsystem, NULL, 0); 1335116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1336167482Sdes NULL, NULL, NULL, PFS_RD); 133785129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1338167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1339119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1340167482Sdes NULL, NULL, NULL, 0); 134185129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1342167482Sdes NULL, NULL, NULL, PFS_RD); 1343119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1344167482Sdes NULL, NULL, NULL, PFS_RD); 134585129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1346167482Sdes NULL, NULL, NULL, PFS_RD); 1347204825Sed pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1348204825Sed NULL, NULL, NULL, 0); 134985129Sdes 1350158311Sambrisko /* /proc/scsi/... */ 1351167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1352158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1353167482Sdes NULL, NULL, NULL, PFS_RD); 1354158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1355167482Sdes NULL, NULL, NULL, PFS_RD); 1356163129Snetchild 1357163129Snetchild /* /proc/sys/... */ 1358167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1359163129Snetchild /* /proc/sys/kernel/... */ 1360167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1361167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1362167482Sdes NULL, NULL, NULL, PFS_RD); 1363167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1364167482Sdes NULL, NULL, NULL, PFS_RD); 1365167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1366167482Sdes NULL, NULL, NULL, PFS_RD); 1367164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1368167482Sdes NULL, NULL, NULL, PFS_RD); 1369163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1370167482Sdes NULL, NULL, NULL, PFS_RD); 1371164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1372167482Sdes NULL, NULL, NULL, PFS_RD); 1373163129Snetchild 137485129Sdes return (0); 137585129Sdes} 137685129Sdes 137785129Sdes/* 137885129Sdes * Destructor 137985129Sdes */ 138085129Sdesstatic int 138185129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 138285129Sdes{ 138385129Sdes 138485129Sdes /* nothing to do, pseudofs will GC */ 138585129Sdes return (0); 138685129Sdes} 138785129Sdes 138885129SdesPSEUDOFS(linprocfs, 1); 138978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 139078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1391168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1392168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1393