linprocfs.c revision 186563
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 186563 2008-12-29 12:45:11Z kib $"); 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 27978031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 28067589Sdes flags[16] = "fcmov"; 28178031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 28267589Sdes flags[24] = "cxmmx"; 28378031Sdes } 284119068Sdes 28578031Sdes for (i = 0; i < 32; i++) 28667589Sdes if (cpu_feature & (1 << i)) 28778025Sdes sbuf_printf(sb, " %s", flags[i]); 28878025Sdes sbuf_cat(sb, "\n"); 28978031Sdes if (class >= 5) { 29069799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 29169799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 29278025Sdes sbuf_printf(sb, 29369799Sdes "cpu MHz\t\t: %d.%02d\n" 29469799Sdes "bogomips\t: %d.%02d\n", 29569799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29678031Sdes } 29769995Sdes 29878025Sdes return (0); 29959412Smsmith} 300133822Stjr#endif /* __i386__ || __amd64__ */ 30165633Sdes 30278113Sdes/* 30385289Sdes * Filler function for proc/mtab 30485289Sdes * 30585289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30685289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30785289Sdes */ 30885289Sdesstatic int 30985289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 31085289Sdes{ 31185289Sdes struct nameidata nd; 31285289Sdes struct mount *mp; 31391334Sjulian const char *lep; 31491334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 31585289Sdes size_t lep_len; 31685289Sdes int error; 31785289Sdes 31885289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 319168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 32085289Sdes flep = NULL; 321168942Sdes error = namei(&nd); 322184649Sjhb lep = linux_emul_path; 323184649Sjhb if (error == 0) { 324184649Sjhb if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 325184649Sjhb lep = dlep; 326184649Sjhb vrele(nd.ni_vp); 327184649Sjhb VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 328184649Sjhb } 32985289Sdes lep_len = strlen(lep); 330119068Sdes 33185289Sdes mtx_lock(&mountlist_mtx); 33285289Sdes error = 0; 33385289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 33485289Sdes /* determine device name */ 33585289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 336119068Sdes 33785289Sdes /* determine mount point */ 33885289Sdes mntto = mp->mnt_stat.f_mntonname; 33985289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 34085289Sdes mntto[lep_len] == '/') 34185289Sdes mntto += lep_len; 34285289Sdes 34385289Sdes /* determine fs type */ 34485289Sdes fstype = mp->mnt_stat.f_fstypename; 34585289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 34685289Sdes mntfrom = fstype = "proc"; 34785289Sdes else if (strcmp(fstype, "procfs") == 0) 34885289Sdes continue; 349119068Sdes 350158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 351158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 352158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 353158311Sambrisko } else { 354158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 355158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 356158311Sambrisko } 35785289Sdes#define ADD_OPTION(opt, name) \ 35885289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 35985289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 36085289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 36185289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 36285289Sdes ADD_OPTION(MNT_UNION, "union"); 36385289Sdes ADD_OPTION(MNT_ASYNC, "async"); 36485289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 36585289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 36685289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 36785289Sdes#undef ADD_OPTION 36885289Sdes /* a real Linux mtab will also show NFS options */ 36985289Sdes sbuf_printf(sb, " 0 0\n"); 37085289Sdes } 37185289Sdes mtx_unlock(&mountlist_mtx); 37285289Sdes if (flep != NULL) 37385289Sdes free(flep, M_TEMP); 37485289Sdes return (error); 37585289Sdes} 37685289Sdes 37785289Sdes/* 37878113Sdes * Filler function for proc/stat 37978113Sdes */ 38078025Sdesstatic int 38178025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 38265633Sdes{ 383174070Speter struct pcpu *pcpu; 384174070Speter long cp_time[CPUSTATES]; 385174070Speter long *cp; 386123246Sdes int i; 387120339Sdes 388174070Speter read_cpu_time(cp_time); 389120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 390120339Sdes T2J(cp_time[CP_USER]), 391120339Sdes T2J(cp_time[CP_NICE]), 392120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 393120339Sdes T2J(cp_time[CP_IDLE])); 394174070Speter for (i = 0; i <= mp_maxid; ++i) { 395174070Speter if (CPU_ABSENT(i)) 396174070Speter continue; 397174070Speter pcpu = pcpu_find(i); 398174070Speter cp = pcpu->pc_cp_time; 399143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 400174070Speter T2J(cp[CP_USER]), 401174070Speter T2J(cp[CP_NICE]), 402174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 403174070Speter T2J(cp[CP_IDLE])); 404174070Speter } 40578025Sdes sbuf_printf(sb, 40669799Sdes "disk 0 0 0 0\n" 40769799Sdes "page %u %u\n" 40869799Sdes "swap %u %u\n" 40969799Sdes "intr %u\n" 41069799Sdes "ctxt %u\n" 41185657Sdillon "btime %lld\n", 412170170Sattilio cnt.v_vnodepgsin, 413170170Sattilio cnt.v_vnodepgsout, 414170170Sattilio cnt.v_swappgsin, 415170170Sattilio cnt.v_swappgsout, 416170170Sattilio cnt.v_intr, 417170170Sattilio cnt.v_swtch, 418113574Sjhb (long long)boottime.tv_sec); 41978025Sdes return (0); 42065633Sdes} 42165633Sdes 42278113Sdes/* 42378113Sdes * Filler function for proc/uptime 42478113Sdes */ 42578025Sdesstatic int 42678025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 42765633Sdes{ 428174070Speter long cp_time[CPUSTATES]; 42965633Sdes struct timeval tv; 43065633Sdes 43165633Sdes getmicrouptime(&tv); 432174070Speter read_cpu_time(cp_time); 43385657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 434113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 43569799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43678025Sdes return (0); 43765633Sdes} 43865633Sdes 43978113Sdes/* 440167159Sjkim * Get OS build date 441167159Sjkim */ 442167159Sjkimstatic void 443167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 444167159Sjkim{ 445167159Sjkim#if 0 446167159Sjkim char osbuild[256]; 447167159Sjkim char *cp1, *cp2; 448167159Sjkim 449167159Sjkim strncpy(osbuild, version, 256); 450167159Sjkim osbuild[255] = '\0'; 451167159Sjkim cp1 = strstr(osbuild, "\n"); 452167159Sjkim cp2 = strstr(osbuild, ":"); 453167159Sjkim if (cp1 && cp2) { 454167159Sjkim *cp1 = *cp2 = '\0'; 455167159Sjkim cp1 = strstr(osbuild, "#"); 456167159Sjkim } else 457167159Sjkim cp1 = NULL; 458167159Sjkim if (cp1) 459167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 460167159Sjkim else 461167159Sjkim#endif 462167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 463167159Sjkim} 464167159Sjkim 465167159Sjkim/* 466167159Sjkim * Get OS builder 467167159Sjkim */ 468167159Sjkimstatic void 469167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 470167159Sjkim{ 471168762Sdes#if 0 472167159Sjkim char builder[256]; 473167159Sjkim char *cp; 474167159Sjkim 475167159Sjkim cp = strstr(version, "\n "); 476167159Sjkim if (cp) { 477167159Sjkim strncpy(builder, cp + 5, 256); 478167159Sjkim builder[255] = '\0'; 479167159Sjkim cp = strstr(builder, ":"); 480167159Sjkim if (cp) 481167159Sjkim *cp = '\0'; 482167159Sjkim } 483167159Sjkim if (cp) 484167159Sjkim sbuf_cat(sb, builder); 485167159Sjkim else 486168762Sdes#endif 487167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 488167159Sjkim} 489167159Sjkim 490167159Sjkim/* 49178113Sdes * Filler function for proc/version 49278113Sdes */ 49378025Sdesstatic int 49478025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 49565633Sdes{ 49687275Srwatson char osname[LINUX_MAX_UTSNAME]; 49787275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 49887275Srwatson 499112206Sjhb linux_get_osname(td, osname); 500112206Sjhb linux_get_osrelease(td, osrelease); 501167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 502167159Sjkim linprocfs_osbuilder(td, sb); 503167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 504167159Sjkim linprocfs_osbuild(td, sb); 505167159Sjkim sbuf_cat(sb, "\n"); 50687275Srwatson 50778025Sdes return (0); 50865633Sdes} 50965633Sdes 51078113Sdes/* 51178113Sdes * Filler function for proc/loadavg 51278113Sdes */ 51378025Sdesstatic int 51478025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 51576839Sjlemon{ 516168762Sdes 51778025Sdes sbuf_printf(sb, 51876839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 51976839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 52076839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 52176839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 52276839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 52376839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 52476839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 52576839Sjlemon 1, /* number of running tasks */ 52676839Sjlemon nprocs, /* number of tasks */ 52778116Sdes lastpid /* the last pid */ 52876839Sjlemon ); 52978025Sdes return (0); 53076839Sjlemon} 53176839Sjlemon 53278113Sdes/* 53378113Sdes * Filler function for proc/pid/stat 53478113Sdes */ 53578025Sdesstatic int 53678025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 53767588Sdes{ 53869995Sdes struct kinfo_proc kp; 539166140Snetchild char state; 540166140Snetchild static int ratelimit = 0; 54167588Sdes 54294307Sjhb PROC_LOCK(p); 54369995Sdes fill_kinfo_proc(p, &kp); 54478025Sdes sbuf_printf(sb, "%d", p->p_pid); 54578025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 54667588Sdes PS_ADD("comm", "(%s)", p->p_comm); 547166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 548166140Snetchild state = 'R'; 549166140Snetchild 550166141Snetchild if (ratelimit == 0) { 551166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 552166162Snetchild kp.ki_stat, sizeof(linux_state)); 553166141Snetchild ++ratelimit; 554166141Snetchild } 555166140Snetchild } else 556166140Snetchild state = linux_state[kp.ki_stat - 1]; 557166140Snetchild PS_ADD("state", "%c", state); 55873923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 55967588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 56067588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 56191140Stanimura PROC_UNLOCK(p); 56267588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 563159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 56467588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 565159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 566159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 567159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 568159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 569159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 570159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 571159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 572159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 573159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 574159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 575159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 576159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 577159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 578159995Snetchild It should be the number of jiffies between system boot and process 579159995Snetchild start. */ 580159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 581159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 582159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 583159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 58469995Sdes PS_ADD("startcode", "%u", (unsigned)0); 58567588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 58667588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 587159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 588159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 589159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 590159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 591159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 592159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 59367588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 594159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 595159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 59669799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 597159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 598159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 599159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 60067588Sdes#undef PS_ADD 60178025Sdes sbuf_putc(sb, '\n'); 602119068Sdes 60378025Sdes return (0); 60467588Sdes} 60567588Sdes 60667588Sdes/* 607119911Sdes * Filler function for proc/pid/statm 608119911Sdes */ 609119911Sdesstatic int 610119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 611119911Sdes{ 612119911Sdes struct kinfo_proc kp; 613119911Sdes segsz_t lsize; 614120340Sdes 615119911Sdes PROC_LOCK(p); 616119911Sdes fill_kinfo_proc(p, &kp); 617119911Sdes PROC_UNLOCK(p); 618119911Sdes 619119911Sdes /* 620119911Sdes * See comments in linprocfs_doprocstatus() regarding the 621119911Sdes * computation of lsize. 622119911Sdes */ 623119911Sdes /* size resident share trs drs lrs dt */ 624119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 625119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 626119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 627119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 628119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 629119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 630119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 631119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 632119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 633119911Sdes 634119911Sdes return (0); 635119911Sdes} 636119911Sdes 637119911Sdes/* 63878113Sdes * Filler function for proc/pid/status 63978113Sdes */ 64078025Sdesstatic int 64178025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 64267588Sdes{ 64369995Sdes struct kinfo_proc kp; 64467588Sdes char *state; 64569799Sdes segsz_t lsize; 64699072Sjulian struct thread *td2; 647114983Sjhb struct sigacts *ps; 64874135Sjlemon int i; 64967588Sdes 650113611Sjhb PROC_LOCK(p); 65199072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 65299072Sjulian 65399072Sjulian if (P_SHOULDSTOP(p)) { 65499072Sjulian state = "T (stopped)"; 65599072Sjulian } else { 656170307Sjeff PROC_SLOCK(p); 65799072Sjulian switch(p->p_state) { 65899072Sjulian case PRS_NEW: 65999072Sjulian state = "I (idle)"; 66099072Sjulian break; 66199072Sjulian case PRS_NORMAL: 66299072Sjulian if (p->p_flag & P_WEXIT) { 66399072Sjulian state = "X (exiting)"; 66499072Sjulian break; 66599072Sjulian } 66699072Sjulian switch(td2->td_state) { 667103216Sjulian case TDS_INHIBITED: 66899072Sjulian state = "S (sleeping)"; 66999072Sjulian break; 67099072Sjulian case TDS_RUNQ: 67199072Sjulian case TDS_RUNNING: 67299072Sjulian state = "R (running)"; 67399072Sjulian break; 67499072Sjulian default: 67599072Sjulian state = "? (unknown)"; 67699072Sjulian break; 67799072Sjulian } 67899072Sjulian break; 67999072Sjulian case PRS_ZOMBIE: 68099072Sjulian state = "Z (zombie)"; 68199072Sjulian break; 68299072Sjulian default: 68399072Sjulian state = "? (unknown)"; 68499072Sjulian break; 68599072Sjulian } 686170307Sjeff PROC_SUNLOCK(p); 68799072Sjulian } 68867588Sdes 68969995Sdes fill_kinfo_proc(p, &kp); 69078025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 69178031Sdes sbuf_printf(sb, "State:\t%s\n", state); 69267588Sdes 69367588Sdes /* 69467588Sdes * Credentials 69567588Sdes */ 69678025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 69778025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 69873923Sjhb p->p_pptr->p_pid : 0); 69978031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 70078031Sdes p->p_ucred->cr_uid, 70178031Sdes p->p_ucred->cr_svuid, 70278031Sdes /* FreeBSD doesn't have fsuid */ 70378031Sdes p->p_ucred->cr_uid); 70478031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 70578031Sdes p->p_ucred->cr_gid, 70678031Sdes p->p_ucred->cr_svgid, 70778031Sdes /* FreeBSD doesn't have fsgid */ 70878031Sdes p->p_ucred->cr_gid); 70978025Sdes sbuf_cat(sb, "Groups:\t"); 71067588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 71178031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 71271471Sjhb PROC_UNLOCK(p); 71378025Sdes sbuf_putc(sb, '\n'); 714119068Sdes 71567588Sdes /* 71667588Sdes * Memory 71769799Sdes * 71869799Sdes * While our approximation of VmLib may not be accurate (I 71969799Sdes * don't know of a simple way to verify it, and I'm not sure 72069799Sdes * it has much meaning anyway), I believe it's good enough. 72169799Sdes * 72269799Sdes * The same code that could (I think) accurately compute VmLib 72369799Sdes * could also compute VmLck, but I don't really care enough to 72469799Sdes * implement it. Submissions are welcome. 72567588Sdes */ 726113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 72778025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 728113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 729113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 730113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 731113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 73269995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 73369995Sdes kp.ki_ssize - kp.ki_tsize - 1; 734113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 73567588Sdes 73667588Sdes /* 73767588Sdes * Signal masks 73867588Sdes * 73967588Sdes * We support up to 128 signals, while Linux supports 32, 74067588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 74167588Sdes * just show the lower 32 bits of each mask. XXX hack. 74267588Sdes * 74367588Sdes * NB: on certain platforms (Sparc at least) Linux actually 74467588Sdes * supports 64 signals, but this code is a long way from 74567588Sdes * running on anything but i386, so ignore that for now. 74667588Sdes */ 74771471Sjhb PROC_LOCK(p); 748104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 74969799Sdes /* 75069799Sdes * I can't seem to find out where the signal mask is in 75169799Sdes * relation to struct proc, so SigBlk is left unimplemented. 75269799Sdes */ 75378025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 754114983Sjhb ps = p->p_sigacts; 755114983Sjhb mtx_lock(&ps->ps_mtx); 756114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 757114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 758114983Sjhb mtx_unlock(&ps->ps_mtx); 75971471Sjhb PROC_UNLOCK(p); 760119068Sdes 76167588Sdes /* 76267588Sdes * Linux also prints the capability masks, but we don't have 76367588Sdes * capabilities yet, and when we do get them they're likely to 76467588Sdes * be meaningless to Linux programs, so we lie. XXX 76567588Sdes */ 76678025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 76778025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 76878025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 769119068Sdes 77078025Sdes return (0); 77167588Sdes} 77274135Sjlemon 773119911Sdes 77478113Sdes/* 775119911Sdes * Filler function for proc/pid/cwd 776119911Sdes */ 777119911Sdesstatic int 778119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 779119911Sdes{ 780119911Sdes char *fullpath = "unknown"; 781119911Sdes char *freepath = NULL; 782119911Sdes 783119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 784119911Sdes sbuf_printf(sb, "%s", fullpath); 785119911Sdes if (freepath) 786119911Sdes free(freepath, M_TEMP); 787119911Sdes return (0); 788119911Sdes} 789119911Sdes 790119911Sdes/* 791119911Sdes * Filler function for proc/pid/root 792119911Sdes */ 793119911Sdesstatic int 794119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 795119911Sdes{ 796119911Sdes struct vnode *rvp; 797119911Sdes char *fullpath = "unknown"; 798119911Sdes char *freepath = NULL; 799119911Sdes 800119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 801119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 802119911Sdes sbuf_printf(sb, "%s", fullpath); 803119911Sdes if (freepath) 804119911Sdes free(freepath, M_TEMP); 805119911Sdes return (0); 806119911Sdes} 807119911Sdes 808119911Sdes/* 80978113Sdes * Filler function for proc/pid/cmdline 81078113Sdes */ 81178025Sdesstatic int 81278113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 81378113Sdes{ 81478113Sdes struct ps_strings pstr; 815138281Scperciva char **ps_argvstr; 81678113Sdes int error, i; 81778113Sdes 81878113Sdes /* 81978113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 82078113Sdes * revert back to the old way which only implements full cmdline 82178113Sdes * for the currept process and just p->p_comm for all other 82278113Sdes * processes. 82378113Sdes * Note that if the argv is no longer available, we deliberately 82478113Sdes * don't fall back on p->p_comm or return an error: the authentic 82578113Sdes * Linux behaviour is to return zero-length in this case. 82678113Sdes */ 82778113Sdes 82894620Sjhb PROC_LOCK(p); 829127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 83094620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 83194620Sjhb PROC_UNLOCK(p); 83294620Sjhb } else if (p != td->td_proc) { 83394620Sjhb PROC_UNLOCK(p); 83494620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 83594620Sjhb } else { 83694620Sjhb PROC_UNLOCK(p); 837103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 838103767Sjake sizeof(pstr)); 83994620Sjhb if (error) 84094620Sjhb return (error); 841138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 842138281Scperciva return (E2BIG); 843138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 844138281Scperciva M_TEMP, M_WAITOK); 845138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 846138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 847138281Scperciva if (error) { 848138281Scperciva free(ps_argvstr, M_TEMP); 849138281Scperciva return (error); 850138281Scperciva } 85194620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 852138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 85394620Sjhb sbuf_printf(sb, "%c", '\0'); 85478113Sdes } 855138281Scperciva free(ps_argvstr, M_TEMP); 85678113Sdes } 85778113Sdes 85878113Sdes return (0); 85978113Sdes} 86078113Sdes 86178113Sdes/* 862116173Sobrien * Filler function for proc/pid/environ 863116173Sobrien */ 864116173Sobrienstatic int 865116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 866116173Sobrien{ 867168762Sdes 868116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 869116173Sobrien return (0); 870116173Sobrien} 871116173Sobrien 872116173Sobrien/* 873116173Sobrien * Filler function for proc/pid/maps 874116173Sobrien */ 875116173Sobrienstatic int 876116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 877116173Sobrien{ 878185984Skib struct vmspace *vm; 879185984Skib vm_map_t map; 880185765Skib vm_map_entry_t entry, tmp_entry; 881121265Scognet vm_object_t obj, tobj, lobj; 882185765Skib vm_offset_t e_start, e_end; 883121265Scognet vm_ooffset_t off = 0; 884185765Skib vm_prot_t e_prot; 885185765Skib unsigned int last_timestamp; 886121265Scognet char *name = "", *freename = NULL; 887121265Scognet ino_t ino; 888121265Scognet int ref_count, shadow_count, flags; 889121265Scognet int error; 890137507Sphk struct vnode *vp; 891137507Sphk struct vattr vat; 892161094Skib int locked; 893168762Sdes 894121246Scognet PROC_LOCK(p); 895121246Scognet error = p_candebug(td, p); 896121246Scognet PROC_UNLOCK(p); 897121246Scognet if (error) 898121246Scognet return (error); 899168762Sdes 900121246Scognet if (uio->uio_rw != UIO_READ) 901121246Scognet return (EOPNOTSUPP); 902168762Sdes 903121246Scognet error = 0; 904185984Skib vm = vmspace_acquire_ref(p); 905185984Skib if (vm == NULL) 906185984Skib return (ESRCH); 907185984Skib map = &vm->vm_map; 908169156Salc vm_map_lock_read(map); 909183600Skib for (entry = map->header.next; entry != &map->header; 910121246Scognet entry = entry->next) { 911121265Scognet name = ""; 912121265Scognet freename = NULL; 913121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 914121246Scognet continue; 915185765Skib e_prot = entry->protection; 916185765Skib e_start = entry->start; 917185765Skib e_end = entry->end; 918121246Scognet obj = entry->object.vm_object; 919169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 920169156Salc VM_OBJECT_LOCK(tobj); 921169156Salc if (lobj != obj) 922169156Salc VM_OBJECT_UNLOCK(lobj); 923121246Scognet lobj = tobj; 924169156Salc } 925185765Skib last_timestamp = map->timestamp; 926185765Skib vm_map_unlock_read(map); 927121246Scognet ino = 0; 928121246Scognet if (lobj) { 929121246Scognet off = IDX_TO_OFF(lobj->size); 930161094Skib if (lobj->type == OBJT_VNODE) { 931161094Skib vp = lobj->handle; 932161094Skib if (vp) 933161094Skib vref(vp); 934121246Scognet } 935161094Skib else 936161094Skib vp = NULL; 937169156Salc if (lobj != obj) 938169156Salc VM_OBJECT_UNLOCK(lobj); 939121246Scognet flags = obj->flags; 940121246Scognet ref_count = obj->ref_count; 941121246Scognet shadow_count = obj->shadow_count; 942169156Salc VM_OBJECT_UNLOCK(obj); 943161094Skib if (vp) { 944161094Skib vn_fullpath(td, vp, &name, &freename); 945161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 946175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 947182371Sattilio VOP_GETATTR(vp, &vat, td->td_ucred); 948161094Skib ino = vat.va_fileid; 949161094Skib vput(vp); 950161094Skib VFS_UNLOCK_GIANT(locked); 951161094Skib } 952121246Scognet } else { 953121246Scognet flags = 0; 954121246Scognet ref_count = 0; 955121246Scognet shadow_count = 0; 956121246Scognet } 957168762Sdes 958121246Scognet /* 959168762Sdes * format: 960121246Scognet * start, end, access, offset, major, minor, inode, name. 961121246Scognet */ 962183600Skib error = sbuf_printf(sb, 963121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 964185765Skib (u_long)e_start, (u_long)e_end, 965185765Skib (e_prot & VM_PROT_READ)?"r":"-", 966185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 967185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 968121246Scognet "p", 969121265Scognet (u_long)off, 970121246Scognet 0, 971121246Scognet 0, 972121265Scognet (u_long)ino, 973121246Scognet *name ? " " : "", 974121246Scognet name 975121246Scognet ); 976121246Scognet if (freename) 977121246Scognet free(freename, M_TEMP); 978185864Skib vm_map_lock_read(map); 979183600Skib if (error == -1) { 980183600Skib error = 0; 981121246Scognet break; 982169156Salc } 983186563Skib if (last_timestamp != map->timestamp) { 984185765Skib /* 985185765Skib * Look again for the entry because the map was 986185765Skib * modified while it was unlocked. Specifically, 987185765Skib * the entry may have been clipped, merged, or deleted. 988185765Skib */ 989185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 990185765Skib entry = tmp_entry; 991185765Skib } 992121246Scognet } 993169156Salc vm_map_unlock_read(map); 994185984Skib vmspace_free(vm); 995168762Sdes 996121246Scognet return (error); 997168762Sdes} 998168762Sdes 999116173Sobrien/* 100078113Sdes * Filler function for proc/net/dev 100178113Sdes */ 100278025Sdesstatic int 100378025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 100474135Sjlemon{ 1005183550Szec INIT_VNET_NET(TD_TO_VNET(curthread)); 100685129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 100774135Sjlemon struct ifnet *ifp; 100874135Sjlemon 100985129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 101083926Sdes "Inter-", " Receive", " Transmit", " face", 101185129Sdes "bytes packets errs drop fifo frame compressed", 101283926Sdes "bytes packets errs drop fifo frame compressed"); 101374135Sjlemon 1014108172Shsu IFNET_RLOCK(); 1015181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 101685129Sdes linux_ifname(ifp, ifname, sizeof ifname); 101785129Sdes sbuf_printf(sb, "%6.6s:", ifname); 101883926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 101983926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 102083926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 102183926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 102274135Sjlemon } 1023108172Shsu IFNET_RUNLOCK(); 1024119068Sdes 102578025Sdes return (0); 102674135Sjlemon} 102774135Sjlemon 1028158311Sambrisko/* 1029167159Sjkim * Filler function for proc/sys/kernel/osrelease 1030167159Sjkim */ 1031167159Sjkimstatic int 1032167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1033167159Sjkim{ 1034167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1035167159Sjkim 1036167159Sjkim linux_get_osrelease(td, osrelease); 1037167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1038167159Sjkim 1039167159Sjkim return (0); 1040167159Sjkim} 1041167159Sjkim 1042167159Sjkim/* 1043167159Sjkim * Filler function for proc/sys/kernel/ostype 1044167159Sjkim */ 1045167159Sjkimstatic int 1046167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1047167159Sjkim{ 1048167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1049167159Sjkim 1050167159Sjkim linux_get_osname(td, osname); 1051167159Sjkim sbuf_printf(sb, "%s\n", osname); 1052167159Sjkim 1053167159Sjkim return (0); 1054167159Sjkim} 1055167159Sjkim 1056167159Sjkim/* 1057167159Sjkim * Filler function for proc/sys/kernel/version 1058167159Sjkim */ 1059167159Sjkimstatic int 1060167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1061167159Sjkim{ 1062168762Sdes 1063167159Sjkim linprocfs_osbuild(td, sb); 1064167159Sjkim sbuf_cat(sb, "\n"); 1065167159Sjkim return (0); 1066167159Sjkim} 1067167159Sjkim 1068167159Sjkim/* 1069164692Sjkim * Filler function for proc/sys/kernel/msgmni 1070164692Sjkim */ 1071164692Sjkimstatic int 1072164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1073164692Sjkim{ 1074164692Sjkim 1075168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1076164692Sjkim return (0); 1077164692Sjkim} 1078164692Sjkim 1079164692Sjkim/* 1080163251Skeramida * Filler function for proc/sys/kernel/pid_max 1081163129Snetchild */ 1082163129Snetchildstatic int 1083163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1084163129Snetchild{ 1085163757Snetchild 1086163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1087163129Snetchild return (0); 1088163129Snetchild} 1089163129Snetchild 1090163129Snetchild/* 1091164692Sjkim * Filler function for proc/sys/kernel/sem 1092164692Sjkim */ 1093164692Sjkimstatic int 1094164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1095164692Sjkim{ 1096164692Sjkim 1097168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1098168067Sjkim seminfo.semopm, seminfo.semmni); 1099164692Sjkim return (0); 1100164692Sjkim} 1101164692Sjkim 1102164692Sjkim/* 1103158311Sambrisko * Filler function for proc/scsi/device_info 1104158311Sambrisko */ 1105158311Sambriskostatic int 1106158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1107158311Sambrisko{ 1108168762Sdes 1109158311Sambrisko return (0); 1110158311Sambrisko} 1111158311Sambrisko 1112158311Sambrisko/* 1113158311Sambrisko * Filler function for proc/scsi/scsi 1114158311Sambrisko */ 1115158311Sambriskostatic int 1116158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1117158311Sambrisko{ 1118168762Sdes 1119158311Sambrisko return (0); 1120158311Sambrisko} 1121158311Sambrisko 112285538Sphkextern struct cdevsw *cdevsw[]; 112385538Sphk 112478113Sdes/* 112578113Sdes * Filler function for proc/devices 112678113Sdes */ 112778025Sdesstatic int 112878025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112974135Sjlemon{ 1130158311Sambrisko char *char_devices; 113178025Sdes sbuf_printf(sb, "Character devices:\n"); 113274135Sjlemon 1133158311Sambrisko char_devices = linux_get_char_devices(); 1134158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1135158311Sambrisko linux_free_get_char_devices(char_devices); 113674135Sjlemon 113778025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1138119068Sdes 113978025Sdes return (0); 114074135Sjlemon} 114174135Sjlemon 114278113Sdes/* 114378113Sdes * Filler function for proc/cmdline 114478113Sdes */ 114578025Sdesstatic int 114678025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 114774135Sjlemon{ 1148168762Sdes 114978025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 115078025Sdes sbuf_printf(sb, " ro root=302\n"); 115178025Sdes return (0); 115278025Sdes} 115374135Sjlemon 115483926Sdes#if 0 115578025Sdes/* 115683926Sdes * Filler function for proc/modules 115783926Sdes */ 115883926Sdesstatic int 115983926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 116083926Sdes{ 116183926Sdes struct linker_file *lf; 1162119068Sdes 116383926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 116483926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 116583926Sdes (unsigned long)lf->size, lf->refs); 116683926Sdes } 116783926Sdes return (0); 116883926Sdes} 116983926Sdes#endif 117083926Sdes 117183926Sdes/* 117285129Sdes * Constructor 117378025Sdes */ 117485129Sdesstatic int 117585129Sdeslinprocfs_init(PFS_INIT_ARGS) 117685129Sdes{ 117785129Sdes struct pfs_node *root; 117885129Sdes struct pfs_node *dir; 117974135Sjlemon 118085129Sdes root = pi->pi_root; 118178025Sdes 1182119923Sdes /* /proc/... */ 1183119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1184167482Sdes NULL, NULL, NULL, PFS_RD); 1185119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1186167482Sdes NULL, NULL, NULL, PFS_RD); 1187119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1188167482Sdes NULL, NULL, NULL, PFS_RD); 1189119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1190167482Sdes NULL, NULL, NULL, PFS_RD); 1191119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1192167482Sdes NULL, NULL, NULL, PFS_RD); 119383926Sdes#if 0 1194119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1195167482Sdes NULL, NULL, NULL, PFS_RD); 119683926Sdes#endif 1197158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1198167482Sdes NULL, NULL, NULL, PFS_RD); 1199119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1200167482Sdes NULL, NULL, NULL, PFS_RD); 120187543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1202167482Sdes NULL, NULL, NULL, 0); 1203119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1204167482Sdes NULL, NULL, NULL, PFS_RD); 1205119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1206167482Sdes NULL, NULL, NULL, PFS_RD); 1207119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1208167482Sdes NULL, NULL, NULL, PFS_RD); 120978025Sdes 1210119923Sdes /* /proc/net/... */ 1211167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 121285129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1213167482Sdes NULL, NULL, NULL, PFS_RD); 121478025Sdes 1215119923Sdes /* /proc/<pid>/... */ 1216167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 121785129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1218167482Sdes NULL, NULL, NULL, PFS_RD); 1219119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1220167482Sdes NULL, NULL, NULL, 0); 1221116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1222167482Sdes NULL, NULL, NULL, PFS_RD); 122387543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1224167482Sdes NULL, &procfs_notsystem, NULL, 0); 1225116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1226167482Sdes NULL, NULL, NULL, PFS_RD); 122785129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1228167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1229119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1230167482Sdes NULL, NULL, NULL, 0); 123185129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1232167482Sdes NULL, NULL, NULL, PFS_RD); 1233119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1234167482Sdes NULL, NULL, NULL, PFS_RD); 123585129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1236167482Sdes NULL, NULL, NULL, PFS_RD); 123785129Sdes 1238158311Sambrisko /* /proc/scsi/... */ 1239167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1240158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1241167482Sdes NULL, NULL, NULL, PFS_RD); 1242158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1243167482Sdes NULL, NULL, NULL, PFS_RD); 1244163129Snetchild 1245163129Snetchild /* /proc/sys/... */ 1246167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1247163129Snetchild /* /proc/sys/kernel/... */ 1248167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1249167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1250167482Sdes NULL, NULL, NULL, PFS_RD); 1251167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1252167482Sdes NULL, NULL, NULL, PFS_RD); 1253167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1254167482Sdes NULL, NULL, NULL, PFS_RD); 1255164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1256167482Sdes NULL, NULL, NULL, PFS_RD); 1257163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1258167482Sdes NULL, NULL, NULL, PFS_RD); 1259164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1260167482Sdes NULL, NULL, NULL, PFS_RD); 1261163129Snetchild 126285129Sdes return (0); 126385129Sdes} 126485129Sdes 126585129Sdes/* 126685129Sdes * Destructor 126785129Sdes */ 126885129Sdesstatic int 126985129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 127085129Sdes{ 127185129Sdes 127285129Sdes /* nothing to do, pseudofs will GC */ 127385129Sdes return (0); 127485129Sdes} 127585129Sdes 127685129SdesPSEUDOFS(linprocfs, 1); 127778025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 127878025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1279168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1280168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1281