linprocfs.c revision 188579
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 188579 2009-02-13 15:32:03Z 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> 76181803Sbz#include <sys/vimage.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 91133822Stjr#if defined(__i386__) || defined(__amd64__) 9267589Sdes#include <machine/cputypes.h> 9359412Smsmith#include <machine/md_var.h> 94133822Stjr#endif /* __i386__ || __amd64__ */ 9559412Smsmith 96140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 97140214Sobrien#include <machine/../linux32/linux.h> 98140214Sobrien#else 9987275Srwatson#include <machine/../linux/linux.h> 100133822Stjr#endif 10185129Sdes#include <compat/linux/linux_ioctl.h> 10269995Sdes#include <compat/linux/linux_mib.h> 10385289Sdes#include <compat/linux/linux_util.h> 10478025Sdes#include <fs/pseudofs/pseudofs.h> 10584248Sdes#include <fs/procfs/procfs.h> 10659412Smsmith 10767588Sdes/* 10867588Sdes * Various conversion macros 10967588Sdes */ 11076405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 11167588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 11267588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 11369799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 11467588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11567588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11674135Sjlemon 117159995Snetchild/** 118159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 119159995Snetchild * 120159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 121159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 122172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 123159995Snetchild * or stopped, or process is paging respectively. 124159995Snetchild * 125159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 126159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 127159995Snetchild * 128159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 129159995Snetchild * map our states to suitable linux states. 130159995Snetchild */ 131166140Snetchildstatic char linux_state[] = "RRSTZDD"; 132159995Snetchild 13378113Sdes/* 13478113Sdes * Filler function for proc/meminfo 13578113Sdes */ 13678025Sdesstatic int 13778025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13859412Smsmith{ 13959412Smsmith unsigned long memtotal; /* total memory in bytes */ 14059412Smsmith unsigned long memused; /* used memory in bytes */ 14159412Smsmith unsigned long memfree; /* free memory in bytes */ 14259412Smsmith unsigned long memshared; /* shared memory ??? */ 14359412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 144113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 145113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 146113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14760860Sdes vm_object_t object; 148117723Sphk int i, j; 14959412Smsmith 15059412Smsmith memtotal = physmem * PAGE_SIZE; 15159412Smsmith /* 15259412Smsmith * The correct thing here would be: 15359412Smsmith * 154170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15559412Smsmith memused = memtotal - memfree; 15659412Smsmith * 15759412Smsmith * but it might mislead linux binaries into thinking there 15859412Smsmith * is very little memory left, so we cheat and tell them that 15959412Smsmith * all memory that isn't wired down is free. 16059412Smsmith */ 161170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 16259412Smsmith memfree = memtotal - memused; 163117723Sphk swap_pager_status(&i, &j); 164153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 165153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 166117723Sphk swapfree = swaptotal - swapused; 16760860Sdes memshared = 0; 168124082Salc mtx_lock(&vm_object_list_mtx); 16971471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 17060860Sdes if (object->shadow_count > 1) 17160860Sdes memshared += object->resident_page_count; 172124082Salc mtx_unlock(&vm_object_list_mtx); 17360860Sdes memshared *= PAGE_SIZE; 17459412Smsmith /* 17559412Smsmith * We'd love to be able to write: 17659412Smsmith * 17759412Smsmith buffers = bufspace; 17859412Smsmith * 17959412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 18059412Smsmith * like unstaticizing it just for linprocfs's sake. 18159412Smsmith */ 18259412Smsmith buffers = 0; 183170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 18459412Smsmith 18578025Sdes sbuf_printf(sb, 18678031Sdes " total: used: free: shared: buffers: cached:\n" 18769799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18876839Sjlemon "Swap: %llu %llu %llu\n" 18969799Sdes "MemTotal: %9lu kB\n" 19069799Sdes "MemFree: %9lu kB\n" 19169799Sdes "MemShared:%9lu kB\n" 19269799Sdes "Buffers: %9lu kB\n" 19369799Sdes "Cached: %9lu kB\n" 19476839Sjlemon "SwapTotal:%9llu kB\n" 19576839Sjlemon "SwapFree: %9llu kB\n", 19669799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19769799Sdes swaptotal, swapused, swapfree, 19869799Sdes B2K(memtotal), B2K(memfree), 19969799Sdes B2K(memshared), B2K(buffers), B2K(cached), 20069799Sdes B2K(swaptotal), B2K(swapfree)); 20159412Smsmith 20278025Sdes return (0); 20359412Smsmith} 20459412Smsmith 205133822Stjr#if defined(__i386__) || defined(__amd64__) 20678113Sdes/* 207133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20878113Sdes */ 20978113Sdesstatic int 21078113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 21178113Sdes{ 212159544Sdes int hw_model[2]; 213159544Sdes char model[128]; 214159544Sdes size_t size; 215123246Sdes int class, fqmhz, fqkhz; 216118421Sdes int i; 21759412Smsmith 21869799Sdes /* 21978031Sdes * We default the flags to include all non-conflicting flags, 22078031Sdes * and the Intel versions of conflicting flags. 22169799Sdes */ 22278031Sdes static char *flags[] = { 22378031Sdes "fpu", "vme", "de", "pse", "tsc", 22478031Sdes "msr", "pae", "mce", "cx8", "apic", 22578031Sdes "sep", "sep", "mtrr", "pge", "mca", 22678031Sdes "cmov", "pat", "pse36", "pn", "b19", 22778031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 228183385Scognet "xmm", "sse2", "b27", "b28", "b29", 22967589Sdes "3dnowext", "3dnow" 23067589Sdes }; 23167589Sdes 23259412Smsmith switch (cpu_class) { 233133822Stjr#ifdef __i386__ 23459412Smsmith case CPUCLASS_286: 23567589Sdes class = 2; 23659412Smsmith break; 23759412Smsmith case CPUCLASS_386: 23867589Sdes class = 3; 23959412Smsmith break; 24059412Smsmith case CPUCLASS_486: 24167589Sdes class = 4; 24259412Smsmith break; 24359412Smsmith case CPUCLASS_586: 24467589Sdes class = 5; 24559412Smsmith break; 24659412Smsmith case CPUCLASS_686: 24767589Sdes class = 6; 24859412Smsmith break; 24959412Smsmith default: 25078031Sdes class = 0; 25159412Smsmith break; 252159170Sdes#else /* __amd64__ */ 253133822Stjr default: 254159170Sdes class = 15; 255133822Stjr break; 256133822Stjr#endif 25759412Smsmith } 25859412Smsmith 259159544Sdes hw_model[0] = CTL_HW; 260159544Sdes hw_model[1] = HW_MODEL; 261159544Sdes model[0] = '\0'; 262159544Sdes size = sizeof(model); 263159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 264159544Sdes strcpy(model, "unknown"); 265123246Sdes for (i = 0; i < mp_ncpus; ++i) { 266118421Sdes sbuf_printf(sb, 267118421Sdes "processor\t: %d\n" 268118421Sdes "vendor_id\t: %.20s\n" 269118421Sdes "cpu family\t: %d\n" 270118421Sdes "model\t\t: %d\n" 271159544Sdes "model name\t: %s\n" 272118421Sdes "stepping\t: %d\n", 273159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 274159544Sdes /* XXX per-cpu vendor / class / model / id? */ 275118421Sdes } 27659412Smsmith 277185766Skib sbuf_cat(sb, "flags\t\t:"); 27867589Sdes 279187594Sjkim#ifdef __i386__ 280187594Sjkim switch (cpu_vendor_id) { 281187594Sjkim case CPU_VENDOR_AMD: 282187594Sjkim if (class < 6) 283187594Sjkim flags[16] = "fcmov"; 284187594Sjkim break; 285187594Sjkim case CPU_VENDOR_CYRIX: 28667589Sdes flags[24] = "cxmmx"; 287187594Sjkim break; 28878031Sdes } 289187594Sjkim#endif 290119068Sdes 29178031Sdes for (i = 0; i < 32; i++) 29267589Sdes if (cpu_feature & (1 << i)) 29378025Sdes sbuf_printf(sb, " %s", flags[i]); 29478025Sdes sbuf_cat(sb, "\n"); 29578031Sdes if (class >= 5) { 29669799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 29769799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 29878025Sdes sbuf_printf(sb, 29969799Sdes "cpu MHz\t\t: %d.%02d\n" 30069799Sdes "bogomips\t: %d.%02d\n", 30169799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 30278031Sdes } 30369995Sdes 30478025Sdes return (0); 30559412Smsmith} 306133822Stjr#endif /* __i386__ || __amd64__ */ 30765633Sdes 30878113Sdes/* 30985289Sdes * Filler function for proc/mtab 31085289Sdes * 31185289Sdes * This file doesn't exist in Linux' procfs, but is included here so 31285289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 31385289Sdes */ 31485289Sdesstatic int 31585289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 31685289Sdes{ 31785289Sdes struct nameidata nd; 31885289Sdes struct mount *mp; 31991334Sjulian const char *lep; 32091334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 32185289Sdes size_t lep_len; 32285289Sdes int error; 32385289Sdes 32485289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 325168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 32685289Sdes flep = NULL; 327168942Sdes error = namei(&nd); 328184649Sjhb lep = linux_emul_path; 329184649Sjhb if (error == 0) { 330188579Sjhb if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 331184649Sjhb lep = dlep; 332184649Sjhb vrele(nd.ni_vp); 333184649Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 334184649Sjhb } 33585289Sdes lep_len = strlen(lep); 336119068Sdes 33785289Sdes mtx_lock(&mountlist_mtx); 33885289Sdes error = 0; 33985289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 34085289Sdes /* determine device name */ 34185289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 342119068Sdes 34385289Sdes /* determine mount point */ 34485289Sdes mntto = mp->mnt_stat.f_mntonname; 34585289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 34685289Sdes mntto[lep_len] == '/') 34785289Sdes mntto += lep_len; 34885289Sdes 34985289Sdes /* determine fs type */ 35085289Sdes fstype = mp->mnt_stat.f_fstypename; 35185289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 35285289Sdes mntfrom = fstype = "proc"; 35385289Sdes else if (strcmp(fstype, "procfs") == 0) 35485289Sdes continue; 355119068Sdes 356158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 357158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 358158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 359158311Sambrisko } else { 360158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 361158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 362158311Sambrisko } 36385289Sdes#define ADD_OPTION(opt, name) \ 36485289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 36585289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 36685289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 36785289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 36885289Sdes ADD_OPTION(MNT_UNION, "union"); 36985289Sdes ADD_OPTION(MNT_ASYNC, "async"); 37085289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 37185289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 37285289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 37385289Sdes#undef ADD_OPTION 37485289Sdes /* a real Linux mtab will also show NFS options */ 37585289Sdes sbuf_printf(sb, " 0 0\n"); 37685289Sdes } 37785289Sdes mtx_unlock(&mountlist_mtx); 37885289Sdes if (flep != NULL) 37985289Sdes free(flep, M_TEMP); 38085289Sdes return (error); 38185289Sdes} 38285289Sdes 38385289Sdes/* 38478113Sdes * Filler function for proc/stat 38578113Sdes */ 38678025Sdesstatic int 38778025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 38865633Sdes{ 389174070Speter struct pcpu *pcpu; 390174070Speter long cp_time[CPUSTATES]; 391174070Speter long *cp; 392123246Sdes int i; 393120339Sdes 394174070Speter read_cpu_time(cp_time); 395120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 396120339Sdes T2J(cp_time[CP_USER]), 397120339Sdes T2J(cp_time[CP_NICE]), 398120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 399120339Sdes T2J(cp_time[CP_IDLE])); 400174070Speter for (i = 0; i <= mp_maxid; ++i) { 401174070Speter if (CPU_ABSENT(i)) 402174070Speter continue; 403174070Speter pcpu = pcpu_find(i); 404174070Speter cp = pcpu->pc_cp_time; 405143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 406174070Speter T2J(cp[CP_USER]), 407174070Speter T2J(cp[CP_NICE]), 408174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 409174070Speter T2J(cp[CP_IDLE])); 410174070Speter } 41178025Sdes sbuf_printf(sb, 41269799Sdes "disk 0 0 0 0\n" 41369799Sdes "page %u %u\n" 41469799Sdes "swap %u %u\n" 41569799Sdes "intr %u\n" 41669799Sdes "ctxt %u\n" 41785657Sdillon "btime %lld\n", 418170170Sattilio cnt.v_vnodepgsin, 419170170Sattilio cnt.v_vnodepgsout, 420170170Sattilio cnt.v_swappgsin, 421170170Sattilio cnt.v_swappgsout, 422170170Sattilio cnt.v_intr, 423170170Sattilio 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{ 434174070Speter long cp_time[CPUSTATES]; 43565633Sdes struct timeval tv; 43665633Sdes 43765633Sdes getmicrouptime(&tv); 438174070Speter read_cpu_time(cp_time); 43985657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 440113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 44169799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 44278025Sdes return (0); 44365633Sdes} 44465633Sdes 44578113Sdes/* 446167159Sjkim * Get OS build date 447167159Sjkim */ 448167159Sjkimstatic void 449167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 450167159Sjkim{ 451167159Sjkim#if 0 452167159Sjkim char osbuild[256]; 453167159Sjkim char *cp1, *cp2; 454167159Sjkim 455167159Sjkim strncpy(osbuild, version, 256); 456167159Sjkim osbuild[255] = '\0'; 457167159Sjkim cp1 = strstr(osbuild, "\n"); 458167159Sjkim cp2 = strstr(osbuild, ":"); 459167159Sjkim if (cp1 && cp2) { 460167159Sjkim *cp1 = *cp2 = '\0'; 461167159Sjkim cp1 = strstr(osbuild, "#"); 462167159Sjkim } else 463167159Sjkim cp1 = NULL; 464167159Sjkim if (cp1) 465167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 466167159Sjkim else 467167159Sjkim#endif 468167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 469167159Sjkim} 470167159Sjkim 471167159Sjkim/* 472167159Sjkim * Get OS builder 473167159Sjkim */ 474167159Sjkimstatic void 475167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 476167159Sjkim{ 477168762Sdes#if 0 478167159Sjkim char builder[256]; 479167159Sjkim char *cp; 480167159Sjkim 481167159Sjkim cp = strstr(version, "\n "); 482167159Sjkim if (cp) { 483167159Sjkim strncpy(builder, cp + 5, 256); 484167159Sjkim builder[255] = '\0'; 485167159Sjkim cp = strstr(builder, ":"); 486167159Sjkim if (cp) 487167159Sjkim *cp = '\0'; 488167159Sjkim } 489167159Sjkim if (cp) 490167159Sjkim sbuf_cat(sb, builder); 491167159Sjkim else 492168762Sdes#endif 493167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 494167159Sjkim} 495167159Sjkim 496167159Sjkim/* 49778113Sdes * Filler function for proc/version 49878113Sdes */ 49978025Sdesstatic int 50078025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 50165633Sdes{ 50287275Srwatson char osname[LINUX_MAX_UTSNAME]; 50387275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 50487275Srwatson 505112206Sjhb linux_get_osname(td, osname); 506112206Sjhb linux_get_osrelease(td, osrelease); 507167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 508167159Sjkim linprocfs_osbuilder(td, sb); 509167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 510167159Sjkim linprocfs_osbuild(td, sb); 511167159Sjkim sbuf_cat(sb, "\n"); 51287275Srwatson 51378025Sdes return (0); 51465633Sdes} 51565633Sdes 51678113Sdes/* 51778113Sdes * Filler function for proc/loadavg 51878113Sdes */ 51978025Sdesstatic int 52078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 52176839Sjlemon{ 522168762Sdes 52378025Sdes sbuf_printf(sb, 52476839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 52576839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 52676839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 52776839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 52876839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 52976839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 53076839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 53176839Sjlemon 1, /* number of running tasks */ 53276839Sjlemon nprocs, /* number of tasks */ 53378116Sdes lastpid /* the last pid */ 53476839Sjlemon ); 53578025Sdes return (0); 53676839Sjlemon} 53776839Sjlemon 53878113Sdes/* 53978113Sdes * Filler function for proc/pid/stat 54078113Sdes */ 54178025Sdesstatic int 54278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 54367588Sdes{ 54469995Sdes struct kinfo_proc kp; 545166140Snetchild char state; 546166140Snetchild static int ratelimit = 0; 54767588Sdes 54894307Sjhb PROC_LOCK(p); 54969995Sdes fill_kinfo_proc(p, &kp); 55078025Sdes sbuf_printf(sb, "%d", p->p_pid); 55178025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 55267588Sdes PS_ADD("comm", "(%s)", p->p_comm); 553166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 554166140Snetchild state = 'R'; 555166140Snetchild 556166141Snetchild if (ratelimit == 0) { 557166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 558166162Snetchild kp.ki_stat, sizeof(linux_state)); 559166141Snetchild ++ratelimit; 560166141Snetchild } 561166140Snetchild } else 562166140Snetchild state = linux_state[kp.ki_stat - 1]; 563166140Snetchild PS_ADD("state", "%c", state); 56473923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 56567588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 56667588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 56791140Stanimura PROC_UNLOCK(p); 56867588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 569159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 57067588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 571159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 572159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 573159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 574159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 575159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 576159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 577159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 578159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 579159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 580159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 581159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 582159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 583159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 584159995Snetchild It should be the number of jiffies between system boot and process 585159995Snetchild start. */ 586159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 587159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 588159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 589159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 59069995Sdes PS_ADD("startcode", "%u", (unsigned)0); 59167588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 59267588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 593159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 594159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 595159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 596159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 597159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 598159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 59967588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 600159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 601159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 60269799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 603159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 604159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 605159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 60667588Sdes#undef PS_ADD 60778025Sdes sbuf_putc(sb, '\n'); 608119068Sdes 60978025Sdes return (0); 61067588Sdes} 61167588Sdes 61267588Sdes/* 613119911Sdes * Filler function for proc/pid/statm 614119911Sdes */ 615119911Sdesstatic int 616119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 617119911Sdes{ 618119911Sdes struct kinfo_proc kp; 619119911Sdes segsz_t lsize; 620120340Sdes 621119911Sdes PROC_LOCK(p); 622119911Sdes fill_kinfo_proc(p, &kp); 623119911Sdes PROC_UNLOCK(p); 624119911Sdes 625119911Sdes /* 626119911Sdes * See comments in linprocfs_doprocstatus() regarding the 627119911Sdes * computation of lsize. 628119911Sdes */ 629119911Sdes /* size resident share trs drs lrs dt */ 630119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 631119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 632119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 633119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 634119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 635119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 636119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 637119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 638119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 639119911Sdes 640119911Sdes return (0); 641119911Sdes} 642119911Sdes 643119911Sdes/* 64478113Sdes * Filler function for proc/pid/status 64578113Sdes */ 64678025Sdesstatic int 64778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 64867588Sdes{ 64969995Sdes struct kinfo_proc kp; 65067588Sdes char *state; 65169799Sdes segsz_t lsize; 65299072Sjulian struct thread *td2; 653114983Sjhb struct sigacts *ps; 65474135Sjlemon int i; 65567588Sdes 656113611Sjhb PROC_LOCK(p); 65799072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 65899072Sjulian 65999072Sjulian if (P_SHOULDSTOP(p)) { 66099072Sjulian state = "T (stopped)"; 66199072Sjulian } else { 662170307Sjeff PROC_SLOCK(p); 66399072Sjulian switch(p->p_state) { 66499072Sjulian case PRS_NEW: 66599072Sjulian state = "I (idle)"; 66699072Sjulian break; 66799072Sjulian case PRS_NORMAL: 66899072Sjulian if (p->p_flag & P_WEXIT) { 66999072Sjulian state = "X (exiting)"; 67099072Sjulian break; 67199072Sjulian } 67299072Sjulian switch(td2->td_state) { 673103216Sjulian case TDS_INHIBITED: 67499072Sjulian state = "S (sleeping)"; 67599072Sjulian break; 67699072Sjulian case TDS_RUNQ: 67799072Sjulian case TDS_RUNNING: 67899072Sjulian state = "R (running)"; 67999072Sjulian break; 68099072Sjulian default: 68199072Sjulian state = "? (unknown)"; 68299072Sjulian break; 68399072Sjulian } 68499072Sjulian break; 68599072Sjulian case PRS_ZOMBIE: 68699072Sjulian state = "Z (zombie)"; 68799072Sjulian break; 68899072Sjulian default: 68999072Sjulian state = "? (unknown)"; 69099072Sjulian break; 69199072Sjulian } 692170307Sjeff PROC_SUNLOCK(p); 69399072Sjulian } 69467588Sdes 69569995Sdes fill_kinfo_proc(p, &kp); 69678025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 69778031Sdes sbuf_printf(sb, "State:\t%s\n", state); 69867588Sdes 69967588Sdes /* 70067588Sdes * Credentials 70167588Sdes */ 70278025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 70378025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 70473923Sjhb p->p_pptr->p_pid : 0); 70578031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 70678031Sdes p->p_ucred->cr_uid, 70778031Sdes p->p_ucred->cr_svuid, 70878031Sdes /* FreeBSD doesn't have fsuid */ 70978031Sdes p->p_ucred->cr_uid); 71078031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 71178031Sdes p->p_ucred->cr_gid, 71278031Sdes p->p_ucred->cr_svgid, 71378031Sdes /* FreeBSD doesn't have fsgid */ 71478031Sdes p->p_ucred->cr_gid); 71578025Sdes sbuf_cat(sb, "Groups:\t"); 71667588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 71778031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 71871471Sjhb PROC_UNLOCK(p); 71978025Sdes sbuf_putc(sb, '\n'); 720119068Sdes 72167588Sdes /* 72267588Sdes * Memory 72369799Sdes * 72469799Sdes * While our approximation of VmLib may not be accurate (I 72569799Sdes * don't know of a simple way to verify it, and I'm not sure 72669799Sdes * it has much meaning anyway), I believe it's good enough. 72769799Sdes * 72869799Sdes * The same code that could (I think) accurately compute VmLib 72969799Sdes * could also compute VmLck, but I don't really care enough to 73069799Sdes * implement it. Submissions are welcome. 73167588Sdes */ 732113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 73378025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 734113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 735113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 736113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 737113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 73869995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 73969995Sdes kp.ki_ssize - kp.ki_tsize - 1; 740113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 74167588Sdes 74267588Sdes /* 74367588Sdes * Signal masks 74467588Sdes * 74567588Sdes * We support up to 128 signals, while Linux supports 32, 74667588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 74767588Sdes * just show the lower 32 bits of each mask. XXX hack. 74867588Sdes * 74967588Sdes * NB: on certain platforms (Sparc at least) Linux actually 75067588Sdes * supports 64 signals, but this code is a long way from 75167588Sdes * running on anything but i386, so ignore that for now. 75267588Sdes */ 75371471Sjhb PROC_LOCK(p); 754104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 75569799Sdes /* 75669799Sdes * I can't seem to find out where the signal mask is in 75769799Sdes * relation to struct proc, so SigBlk is left unimplemented. 75869799Sdes */ 75978025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 760114983Sjhb ps = p->p_sigacts; 761114983Sjhb mtx_lock(&ps->ps_mtx); 762114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 763114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 764114983Sjhb mtx_unlock(&ps->ps_mtx); 76571471Sjhb PROC_UNLOCK(p); 766119068Sdes 76767588Sdes /* 76867588Sdes * Linux also prints the capability masks, but we don't have 76967588Sdes * capabilities yet, and when we do get them they're likely to 77067588Sdes * be meaningless to Linux programs, so we lie. XXX 77167588Sdes */ 77278025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 77378025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 77478025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 775119068Sdes 77678025Sdes return (0); 77767588Sdes} 77874135Sjlemon 779119911Sdes 78078113Sdes/* 781119911Sdes * Filler function for proc/pid/cwd 782119911Sdes */ 783119911Sdesstatic int 784119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 785119911Sdes{ 786119911Sdes char *fullpath = "unknown"; 787119911Sdes char *freepath = NULL; 788119911Sdes 789119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 790119911Sdes sbuf_printf(sb, "%s", fullpath); 791119911Sdes if (freepath) 792119911Sdes free(freepath, M_TEMP); 793119911Sdes return (0); 794119911Sdes} 795119911Sdes 796119911Sdes/* 797119911Sdes * Filler function for proc/pid/root 798119911Sdes */ 799119911Sdesstatic int 800119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 801119911Sdes{ 802119911Sdes struct vnode *rvp; 803119911Sdes char *fullpath = "unknown"; 804119911Sdes char *freepath = NULL; 805119911Sdes 806119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 807119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 808119911Sdes sbuf_printf(sb, "%s", fullpath); 809119911Sdes if (freepath) 810119911Sdes free(freepath, M_TEMP); 811119911Sdes return (0); 812119911Sdes} 813119911Sdes 814119911Sdes/* 81578113Sdes * Filler function for proc/pid/cmdline 81678113Sdes */ 81778025Sdesstatic int 81878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 81978113Sdes{ 82078113Sdes struct ps_strings pstr; 821138281Scperciva char **ps_argvstr; 82278113Sdes int error, i; 82378113Sdes 82478113Sdes /* 82578113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 82678113Sdes * revert back to the old way which only implements full cmdline 82778113Sdes * for the currept process and just p->p_comm for all other 82878113Sdes * processes. 82978113Sdes * Note that if the argv is no longer available, we deliberately 83078113Sdes * don't fall back on p->p_comm or return an error: the authentic 83178113Sdes * Linux behaviour is to return zero-length in this case. 83278113Sdes */ 83378113Sdes 83494620Sjhb PROC_LOCK(p); 835127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 83694620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 83794620Sjhb PROC_UNLOCK(p); 83894620Sjhb } else if (p != td->td_proc) { 83994620Sjhb PROC_UNLOCK(p); 84094620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 84194620Sjhb } else { 84294620Sjhb PROC_UNLOCK(p); 843103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 844103767Sjake sizeof(pstr)); 84594620Sjhb if (error) 84694620Sjhb return (error); 847138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 848138281Scperciva return (E2BIG); 849138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 850138281Scperciva M_TEMP, M_WAITOK); 851138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 852138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 853138281Scperciva if (error) { 854138281Scperciva free(ps_argvstr, M_TEMP); 855138281Scperciva return (error); 856138281Scperciva } 85794620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 858138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 85994620Sjhb sbuf_printf(sb, "%c", '\0'); 86078113Sdes } 861138281Scperciva free(ps_argvstr, M_TEMP); 86278113Sdes } 86378113Sdes 86478113Sdes return (0); 86578113Sdes} 86678113Sdes 86778113Sdes/* 868116173Sobrien * Filler function for proc/pid/environ 869116173Sobrien */ 870116173Sobrienstatic int 871116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 872116173Sobrien{ 873168762Sdes 874116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 875116173Sobrien return (0); 876116173Sobrien} 877116173Sobrien 878116173Sobrien/* 879116173Sobrien * Filler function for proc/pid/maps 880116173Sobrien */ 881116173Sobrienstatic int 882116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 883116173Sobrien{ 884185984Skib struct vmspace *vm; 885185984Skib vm_map_t map; 886185765Skib vm_map_entry_t entry, tmp_entry; 887121265Scognet vm_object_t obj, tobj, lobj; 888185765Skib vm_offset_t e_start, e_end; 889121265Scognet vm_ooffset_t off = 0; 890185765Skib vm_prot_t e_prot; 891185765Skib unsigned int last_timestamp; 892121265Scognet char *name = "", *freename = NULL; 893121265Scognet ino_t ino; 894121265Scognet int ref_count, shadow_count, flags; 895121265Scognet int error; 896137507Sphk struct vnode *vp; 897137507Sphk struct vattr vat; 898161094Skib int locked; 899168762Sdes 900121246Scognet PROC_LOCK(p); 901121246Scognet error = p_candebug(td, p); 902121246Scognet PROC_UNLOCK(p); 903121246Scognet if (error) 904121246Scognet return (error); 905168762Sdes 906121246Scognet if (uio->uio_rw != UIO_READ) 907121246Scognet return (EOPNOTSUPP); 908168762Sdes 909121246Scognet error = 0; 910185984Skib vm = vmspace_acquire_ref(p); 911185984Skib if (vm == NULL) 912185984Skib return (ESRCH); 913185984Skib map = &vm->vm_map; 914169156Salc vm_map_lock_read(map); 915183600Skib for (entry = map->header.next; entry != &map->header; 916121246Scognet entry = entry->next) { 917121265Scognet name = ""; 918121265Scognet freename = NULL; 919121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 920121246Scognet continue; 921185765Skib e_prot = entry->protection; 922185765Skib e_start = entry->start; 923185765Skib e_end = entry->end; 924121246Scognet obj = entry->object.vm_object; 925169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 926169156Salc VM_OBJECT_LOCK(tobj); 927169156Salc if (lobj != obj) 928169156Salc VM_OBJECT_UNLOCK(lobj); 929121246Scognet lobj = tobj; 930169156Salc } 931185765Skib last_timestamp = map->timestamp; 932185765Skib vm_map_unlock_read(map); 933121246Scognet ino = 0; 934121246Scognet if (lobj) { 935121246Scognet off = IDX_TO_OFF(lobj->size); 936161094Skib if (lobj->type == OBJT_VNODE) { 937161094Skib vp = lobj->handle; 938161094Skib if (vp) 939161094Skib vref(vp); 940121246Scognet } 941161094Skib else 942161094Skib vp = NULL; 943169156Salc if (lobj != obj) 944169156Salc VM_OBJECT_UNLOCK(lobj); 945121246Scognet flags = obj->flags; 946121246Scognet ref_count = obj->ref_count; 947121246Scognet shadow_count = obj->shadow_count; 948169156Salc VM_OBJECT_UNLOCK(obj); 949161094Skib if (vp) { 950161094Skib vn_fullpath(td, vp, &name, &freename); 951161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 952175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 953182371Sattilio VOP_GETATTR(vp, &vat, td->td_ucred); 954161094Skib ino = vat.va_fileid; 955161094Skib vput(vp); 956161094Skib VFS_UNLOCK_GIANT(locked); 957161094Skib } 958121246Scognet } else { 959121246Scognet flags = 0; 960121246Scognet ref_count = 0; 961121246Scognet shadow_count = 0; 962121246Scognet } 963168762Sdes 964121246Scognet /* 965168762Sdes * format: 966121246Scognet * start, end, access, offset, major, minor, inode, name. 967121246Scognet */ 968183600Skib error = sbuf_printf(sb, 969121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 970185765Skib (u_long)e_start, (u_long)e_end, 971185765Skib (e_prot & VM_PROT_READ)?"r":"-", 972185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 973185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 974121246Scognet "p", 975121265Scognet (u_long)off, 976121246Scognet 0, 977121246Scognet 0, 978121265Scognet (u_long)ino, 979121246Scognet *name ? " " : "", 980121246Scognet name 981121246Scognet ); 982121246Scognet if (freename) 983121246Scognet free(freename, M_TEMP); 984185864Skib vm_map_lock_read(map); 985183600Skib if (error == -1) { 986183600Skib error = 0; 987121246Scognet break; 988169156Salc } 989186563Skib if (last_timestamp != map->timestamp) { 990185765Skib /* 991185765Skib * Look again for the entry because the map was 992185765Skib * modified while it was unlocked. Specifically, 993185765Skib * the entry may have been clipped, merged, or deleted. 994185765Skib */ 995185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 996185765Skib entry = tmp_entry; 997185765Skib } 998121246Scognet } 999169156Salc vm_map_unlock_read(map); 1000185984Skib vmspace_free(vm); 1001168762Sdes 1002121246Scognet return (error); 1003168762Sdes} 1004168762Sdes 1005116173Sobrien/* 100678113Sdes * Filler function for proc/net/dev 100778113Sdes */ 100878025Sdesstatic int 100978025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 101074135Sjlemon{ 1011183550Szec INIT_VNET_NET(TD_TO_VNET(curthread)); 101285129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 101374135Sjlemon struct ifnet *ifp; 101474135Sjlemon 101585129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 101683926Sdes "Inter-", " Receive", " Transmit", " face", 101785129Sdes "bytes packets errs drop fifo frame compressed", 101883926Sdes "bytes packets errs drop fifo frame compressed"); 101974135Sjlemon 1020108172Shsu IFNET_RLOCK(); 1021181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 102285129Sdes linux_ifname(ifp, ifname, sizeof ifname); 102385129Sdes sbuf_printf(sb, "%6.6s:", ifname); 102483926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 102583926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 102683926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 102783926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 102874135Sjlemon } 1029108172Shsu IFNET_RUNLOCK(); 1030119068Sdes 103178025Sdes return (0); 103274135Sjlemon} 103374135Sjlemon 1034158311Sambrisko/* 1035167159Sjkim * Filler function for proc/sys/kernel/osrelease 1036167159Sjkim */ 1037167159Sjkimstatic int 1038167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1039167159Sjkim{ 1040167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1041167159Sjkim 1042167159Sjkim linux_get_osrelease(td, osrelease); 1043167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1044167159Sjkim 1045167159Sjkim return (0); 1046167159Sjkim} 1047167159Sjkim 1048167159Sjkim/* 1049167159Sjkim * Filler function for proc/sys/kernel/ostype 1050167159Sjkim */ 1051167159Sjkimstatic int 1052167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1053167159Sjkim{ 1054167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1055167159Sjkim 1056167159Sjkim linux_get_osname(td, osname); 1057167159Sjkim sbuf_printf(sb, "%s\n", osname); 1058167159Sjkim 1059167159Sjkim return (0); 1060167159Sjkim} 1061167159Sjkim 1062167159Sjkim/* 1063167159Sjkim * Filler function for proc/sys/kernel/version 1064167159Sjkim */ 1065167159Sjkimstatic int 1066167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1067167159Sjkim{ 1068168762Sdes 1069167159Sjkim linprocfs_osbuild(td, sb); 1070167159Sjkim sbuf_cat(sb, "\n"); 1071167159Sjkim return (0); 1072167159Sjkim} 1073167159Sjkim 1074167159Sjkim/* 1075164692Sjkim * Filler function for proc/sys/kernel/msgmni 1076164692Sjkim */ 1077164692Sjkimstatic int 1078164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1079164692Sjkim{ 1080164692Sjkim 1081168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1082164692Sjkim return (0); 1083164692Sjkim} 1084164692Sjkim 1085164692Sjkim/* 1086163251Skeramida * Filler function for proc/sys/kernel/pid_max 1087163129Snetchild */ 1088163129Snetchildstatic int 1089163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1090163129Snetchild{ 1091163757Snetchild 1092163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1093163129Snetchild return (0); 1094163129Snetchild} 1095163129Snetchild 1096163129Snetchild/* 1097164692Sjkim * Filler function for proc/sys/kernel/sem 1098164692Sjkim */ 1099164692Sjkimstatic int 1100164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1101164692Sjkim{ 1102164692Sjkim 1103168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1104168067Sjkim seminfo.semopm, seminfo.semmni); 1105164692Sjkim return (0); 1106164692Sjkim} 1107164692Sjkim 1108164692Sjkim/* 1109158311Sambrisko * Filler function for proc/scsi/device_info 1110158311Sambrisko */ 1111158311Sambriskostatic int 1112158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1113158311Sambrisko{ 1114168762Sdes 1115158311Sambrisko return (0); 1116158311Sambrisko} 1117158311Sambrisko 1118158311Sambrisko/* 1119158311Sambrisko * Filler function for proc/scsi/scsi 1120158311Sambrisko */ 1121158311Sambriskostatic int 1122158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1123158311Sambrisko{ 1124168762Sdes 1125158311Sambrisko return (0); 1126158311Sambrisko} 1127158311Sambrisko 112885538Sphkextern struct cdevsw *cdevsw[]; 112985538Sphk 113078113Sdes/* 113178113Sdes * Filler function for proc/devices 113278113Sdes */ 113378025Sdesstatic int 113478025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 113574135Sjlemon{ 1136158311Sambrisko char *char_devices; 113778025Sdes sbuf_printf(sb, "Character devices:\n"); 113874135Sjlemon 1139158311Sambrisko char_devices = linux_get_char_devices(); 1140158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1141158311Sambrisko linux_free_get_char_devices(char_devices); 114274135Sjlemon 114378025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1144119068Sdes 114578025Sdes return (0); 114674135Sjlemon} 114774135Sjlemon 114878113Sdes/* 114978113Sdes * Filler function for proc/cmdline 115078113Sdes */ 115178025Sdesstatic int 115278025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 115374135Sjlemon{ 1154168762Sdes 115578025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 115678025Sdes sbuf_printf(sb, " ro root=302\n"); 115778025Sdes return (0); 115878025Sdes} 115974135Sjlemon 116083926Sdes#if 0 116178025Sdes/* 116283926Sdes * Filler function for proc/modules 116383926Sdes */ 116483926Sdesstatic int 116583926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 116683926Sdes{ 116783926Sdes struct linker_file *lf; 1168119068Sdes 116983926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 117083926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 117183926Sdes (unsigned long)lf->size, lf->refs); 117283926Sdes } 117383926Sdes return (0); 117483926Sdes} 117583926Sdes#endif 117683926Sdes 117783926Sdes/* 117885129Sdes * Constructor 117978025Sdes */ 118085129Sdesstatic int 118185129Sdeslinprocfs_init(PFS_INIT_ARGS) 118285129Sdes{ 118385129Sdes struct pfs_node *root; 118485129Sdes struct pfs_node *dir; 118574135Sjlemon 118685129Sdes root = pi->pi_root; 118778025Sdes 1188119923Sdes /* /proc/... */ 1189119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1190167482Sdes NULL, NULL, NULL, PFS_RD); 1191119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1192167482Sdes NULL, NULL, NULL, PFS_RD); 1193119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1194167482Sdes NULL, NULL, NULL, PFS_RD); 1195119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1196167482Sdes NULL, NULL, NULL, PFS_RD); 1197119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1198167482Sdes NULL, NULL, NULL, PFS_RD); 119983926Sdes#if 0 1200119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1201167482Sdes NULL, NULL, NULL, PFS_RD); 120283926Sdes#endif 1203158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1204167482Sdes NULL, NULL, NULL, PFS_RD); 1205119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1206167482Sdes NULL, NULL, NULL, PFS_RD); 120787543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1208167482Sdes NULL, NULL, NULL, 0); 1209119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1210167482Sdes NULL, NULL, NULL, PFS_RD); 1211119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1212167482Sdes NULL, NULL, NULL, PFS_RD); 1213119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1214167482Sdes NULL, NULL, NULL, PFS_RD); 121578025Sdes 1216119923Sdes /* /proc/net/... */ 1217167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 121885129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1219167482Sdes NULL, NULL, NULL, PFS_RD); 122078025Sdes 1221119923Sdes /* /proc/<pid>/... */ 1222167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 122385129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1224167482Sdes NULL, NULL, NULL, PFS_RD); 1225119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1226167482Sdes NULL, NULL, NULL, 0); 1227116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1228167482Sdes NULL, NULL, NULL, PFS_RD); 122987543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1230167482Sdes NULL, &procfs_notsystem, NULL, 0); 1231116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1232167482Sdes NULL, NULL, NULL, PFS_RD); 123385129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1234167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1235119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1236167482Sdes NULL, NULL, NULL, 0); 123785129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1238167482Sdes NULL, NULL, NULL, PFS_RD); 1239119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1240167482Sdes NULL, NULL, NULL, PFS_RD); 124185129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1242167482Sdes NULL, NULL, NULL, PFS_RD); 124385129Sdes 1244158311Sambrisko /* /proc/scsi/... */ 1245167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1246158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1247167482Sdes NULL, NULL, NULL, PFS_RD); 1248158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1249167482Sdes NULL, NULL, NULL, PFS_RD); 1250163129Snetchild 1251163129Snetchild /* /proc/sys/... */ 1252167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1253163129Snetchild /* /proc/sys/kernel/... */ 1254167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1255167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1256167482Sdes NULL, NULL, NULL, PFS_RD); 1257167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1258167482Sdes NULL, NULL, NULL, PFS_RD); 1259167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1260167482Sdes NULL, NULL, NULL, PFS_RD); 1261164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1262167482Sdes NULL, NULL, NULL, PFS_RD); 1263163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1264167482Sdes NULL, NULL, NULL, PFS_RD); 1265164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1266167482Sdes NULL, NULL, NULL, PFS_RD); 1267163129Snetchild 126885129Sdes return (0); 126985129Sdes} 127085129Sdes 127185129Sdes/* 127285129Sdes * Destructor 127385129Sdes */ 127485129Sdesstatic int 127585129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 127685129Sdes{ 127785129Sdes 127885129Sdes /* nothing to do, pseudofs will GC */ 127985129Sdes return (0); 128085129Sdes} 128185129Sdes 128285129SdesPSEUDOFS(linprocfs, 1); 128378025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 128478025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1285168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1286168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1287