linprocfs.c revision 185765
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 185765 2008-12-08 12:34:52Z 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> 8259412Smsmith#include <vm/pmap.h> 8367588Sdes#include <vm/vm_map.h> 8459412Smsmith#include <vm/vm_param.h> 8560860Sdes#include <vm/vm_object.h> 8659412Smsmith#include <vm/swap_pager.h> 8769799Sdes 8867589Sdes#include <machine/clock.h> 8978113Sdes 90133822Stjr#if defined(__i386__) || defined(__amd64__) 9167589Sdes#include <machine/cputypes.h> 9259412Smsmith#include <machine/md_var.h> 93133822Stjr#endif /* __i386__ || __amd64__ */ 9459412Smsmith 95140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 96140214Sobrien#include <machine/../linux32/linux.h> 97140214Sobrien#else 9887275Srwatson#include <machine/../linux/linux.h> 99133822Stjr#endif 10085129Sdes#include <compat/linux/linux_ioctl.h> 10169995Sdes#include <compat/linux/linux_mib.h> 10285289Sdes#include <compat/linux/linux_util.h> 10378025Sdes#include <fs/pseudofs/pseudofs.h> 10484248Sdes#include <fs/procfs/procfs.h> 10559412Smsmith 10667588Sdes/* 10767588Sdes * Various conversion macros 10867588Sdes */ 10976405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 11067588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 11167588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 11269799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 11367588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11467588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11574135Sjlemon 116159995Snetchild/** 117159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 118159995Snetchild * 119159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 120159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 121172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 122159995Snetchild * or stopped, or process is paging respectively. 123159995Snetchild * 124159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 125159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 126159995Snetchild * 127159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 128159995Snetchild * map our states to suitable linux states. 129159995Snetchild */ 130166140Snetchildstatic char linux_state[] = "RRSTZDD"; 131159995Snetchild 13278113Sdes/* 13378113Sdes * Filler function for proc/meminfo 13478113Sdes */ 13578025Sdesstatic int 13678025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13759412Smsmith{ 13859412Smsmith unsigned long memtotal; /* total memory in bytes */ 13959412Smsmith unsigned long memused; /* used memory in bytes */ 14059412Smsmith unsigned long memfree; /* free memory in bytes */ 14159412Smsmith unsigned long memshared; /* shared memory ??? */ 14259412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 143113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 144113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 145113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14660860Sdes vm_object_t object; 147117723Sphk int i, j; 14859412Smsmith 14959412Smsmith memtotal = physmem * PAGE_SIZE; 15059412Smsmith /* 15159412Smsmith * The correct thing here would be: 15259412Smsmith * 153170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15459412Smsmith memused = memtotal - memfree; 15559412Smsmith * 15659412Smsmith * but it might mislead linux binaries into thinking there 15759412Smsmith * is very little memory left, so we cheat and tell them that 15859412Smsmith * all memory that isn't wired down is free. 15959412Smsmith */ 160170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 16159412Smsmith memfree = memtotal - memused; 162117723Sphk swap_pager_status(&i, &j); 163153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 164153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 165117723Sphk swapfree = swaptotal - swapused; 16660860Sdes memshared = 0; 167124082Salc mtx_lock(&vm_object_list_mtx); 16871471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16960860Sdes if (object->shadow_count > 1) 17060860Sdes memshared += object->resident_page_count; 171124082Salc mtx_unlock(&vm_object_list_mtx); 17260860Sdes memshared *= PAGE_SIZE; 17359412Smsmith /* 17459412Smsmith * We'd love to be able to write: 17559412Smsmith * 17659412Smsmith buffers = bufspace; 17759412Smsmith * 17859412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17959412Smsmith * like unstaticizing it just for linprocfs's sake. 18059412Smsmith */ 18159412Smsmith buffers = 0; 182170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 18359412Smsmith 18478025Sdes sbuf_printf(sb, 18578031Sdes " total: used: free: shared: buffers: cached:\n" 18669799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18776839Sjlemon "Swap: %llu %llu %llu\n" 18869799Sdes "MemTotal: %9lu kB\n" 18969799Sdes "MemFree: %9lu kB\n" 19069799Sdes "MemShared:%9lu kB\n" 19169799Sdes "Buffers: %9lu kB\n" 19269799Sdes "Cached: %9lu kB\n" 19376839Sjlemon "SwapTotal:%9llu kB\n" 19476839Sjlemon "SwapFree: %9llu kB\n", 19569799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19669799Sdes swaptotal, swapused, swapfree, 19769799Sdes B2K(memtotal), B2K(memfree), 19869799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19969799Sdes B2K(swaptotal), B2K(swapfree)); 20059412Smsmith 20178025Sdes return (0); 20259412Smsmith} 20359412Smsmith 204133822Stjr#if defined(__i386__) || defined(__amd64__) 20578113Sdes/* 206133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20778113Sdes */ 20878113Sdesstatic int 20978113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 21078113Sdes{ 211159544Sdes int hw_model[2]; 212159544Sdes char model[128]; 213159544Sdes size_t size; 214123246Sdes int class, fqmhz, fqkhz; 215118421Sdes int i; 21659412Smsmith 21769799Sdes /* 21878031Sdes * We default the flags to include all non-conflicting flags, 21978031Sdes * and the Intel versions of conflicting flags. 22069799Sdes */ 22178031Sdes static char *flags[] = { 22278031Sdes "fpu", "vme", "de", "pse", "tsc", 22378031Sdes "msr", "pae", "mce", "cx8", "apic", 22478031Sdes "sep", "sep", "mtrr", "pge", "mca", 22578031Sdes "cmov", "pat", "pse36", "pn", "b19", 22678031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 227183385Scognet "xmm", "sse2", "b27", "b28", "b29", 22867589Sdes "3dnowext", "3dnow" 22967589Sdes }; 23067589Sdes 23159412Smsmith switch (cpu_class) { 232133822Stjr#ifdef __i386__ 23359412Smsmith case CPUCLASS_286: 23467589Sdes class = 2; 23559412Smsmith break; 23659412Smsmith case CPUCLASS_386: 23767589Sdes class = 3; 23859412Smsmith break; 23959412Smsmith case CPUCLASS_486: 24067589Sdes class = 4; 24159412Smsmith break; 24259412Smsmith case CPUCLASS_586: 24367589Sdes class = 5; 24459412Smsmith break; 24559412Smsmith case CPUCLASS_686: 24667589Sdes class = 6; 24759412Smsmith break; 24859412Smsmith default: 24978031Sdes class = 0; 25059412Smsmith break; 251159170Sdes#else /* __amd64__ */ 252133822Stjr default: 253159170Sdes class = 15; 254133822Stjr break; 255133822Stjr#endif 25659412Smsmith } 25759412Smsmith 258159544Sdes hw_model[0] = CTL_HW; 259159544Sdes hw_model[1] = HW_MODEL; 260159544Sdes model[0] = '\0'; 261159544Sdes size = sizeof(model); 262159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 263159544Sdes strcpy(model, "unknown"); 264123246Sdes for (i = 0; i < mp_ncpus; ++i) { 265118421Sdes sbuf_printf(sb, 266118421Sdes "processor\t: %d\n" 267118421Sdes "vendor_id\t: %.20s\n" 268118421Sdes "cpu family\t: %d\n" 269118421Sdes "model\t\t: %d\n" 270159544Sdes "model name\t: %s\n" 271118421Sdes "stepping\t: %d\n", 272159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 273159544Sdes /* XXX per-cpu vendor / class / model / id? */ 274118421Sdes } 27559412Smsmith 27678031Sdes sbuf_cat(sb, 27778031Sdes "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{ 878121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 879185765Skib vm_map_entry_t entry, tmp_entry; 880121265Scognet vm_object_t obj, tobj, lobj; 881185765Skib vm_offset_t e_start, e_end; 882121265Scognet vm_ooffset_t off = 0; 883185765Skib vm_prot_t e_prot; 884185765Skib unsigned int last_timestamp; 885121265Scognet char *name = "", *freename = NULL; 886121265Scognet ino_t ino; 887121265Scognet int ref_count, shadow_count, flags; 888121265Scognet int error; 889137507Sphk struct vnode *vp; 890137507Sphk struct vattr vat; 891161094Skib int locked; 892168762Sdes 893121246Scognet PROC_LOCK(p); 894121246Scognet error = p_candebug(td, p); 895121246Scognet PROC_UNLOCK(p); 896121246Scognet if (error) 897121246Scognet return (error); 898168762Sdes 899121246Scognet if (uio->uio_rw != UIO_READ) 900121246Scognet return (EOPNOTSUPP); 901168762Sdes 902121246Scognet error = 0; 903169156Salc vm_map_lock_read(map); 904183600Skib for (entry = map->header.next; entry != &map->header; 905121246Scognet entry = entry->next) { 906121265Scognet name = ""; 907121265Scognet freename = NULL; 908121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 909121246Scognet continue; 910185765Skib e_prot = entry->protection; 911185765Skib e_start = entry->start; 912185765Skib e_end = entry->end; 913121246Scognet obj = entry->object.vm_object; 914169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 915169156Salc VM_OBJECT_LOCK(tobj); 916169156Salc if (lobj != obj) 917169156Salc VM_OBJECT_UNLOCK(lobj); 918121246Scognet lobj = tobj; 919169156Salc } 920185765Skib last_timestamp = map->timestamp; 921185765Skib vm_map_unlock_read(map); 922121246Scognet ino = 0; 923121246Scognet if (lobj) { 924121246Scognet off = IDX_TO_OFF(lobj->size); 925161094Skib if (lobj->type == OBJT_VNODE) { 926161094Skib vp = lobj->handle; 927161094Skib if (vp) 928161094Skib vref(vp); 929121246Scognet } 930161094Skib else 931161094Skib vp = NULL; 932169156Salc if (lobj != obj) 933169156Salc VM_OBJECT_UNLOCK(lobj); 934121246Scognet flags = obj->flags; 935121246Scognet ref_count = obj->ref_count; 936121246Scognet shadow_count = obj->shadow_count; 937169156Salc VM_OBJECT_UNLOCK(obj); 938161094Skib if (vp) { 939161094Skib vn_fullpath(td, vp, &name, &freename); 940161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 941175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 942182371Sattilio VOP_GETATTR(vp, &vat, td->td_ucred); 943161094Skib ino = vat.va_fileid; 944161094Skib vput(vp); 945161094Skib VFS_UNLOCK_GIANT(locked); 946161094Skib } 947121246Scognet } else { 948121246Scognet flags = 0; 949121246Scognet ref_count = 0; 950121246Scognet shadow_count = 0; 951121246Scognet } 952168762Sdes 953121246Scognet /* 954168762Sdes * format: 955121246Scognet * start, end, access, offset, major, minor, inode, name. 956121246Scognet */ 957183600Skib error = sbuf_printf(sb, 958121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 959185765Skib (u_long)e_start, (u_long)e_end, 960185765Skib (e_prot & VM_PROT_READ)?"r":"-", 961185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 962185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 963121246Scognet "p", 964121265Scognet (u_long)off, 965121246Scognet 0, 966121246Scognet 0, 967121265Scognet (u_long)ino, 968121246Scognet *name ? " " : "", 969121246Scognet name 970121246Scognet ); 971121246Scognet if (freename) 972121246Scognet free(freename, M_TEMP); 973183600Skib if (error == -1) { 974183600Skib error = 0; 975121246Scognet break; 976169156Salc } 977185765Skib vm_map_lock_read(map); 978185765Skib if (last_timestamp + 1 != map->timestamp) { 979185765Skib /* 980185765Skib * Look again for the entry because the map was 981185765Skib * modified while it was unlocked. Specifically, 982185765Skib * the entry may have been clipped, merged, or deleted. 983185765Skib */ 984185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 985185765Skib entry = tmp_entry; 986185765Skib } 987121246Scognet } 988169156Salc vm_map_unlock_read(map); 989168762Sdes 990121246Scognet return (error); 991168762Sdes} 992168762Sdes 993116173Sobrien/* 99478113Sdes * Filler function for proc/net/dev 99578113Sdes */ 99678025Sdesstatic int 99778025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 99874135Sjlemon{ 999183550Szec INIT_VNET_NET(TD_TO_VNET(curthread)); 100085129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 100174135Sjlemon struct ifnet *ifp; 100274135Sjlemon 100385129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 100483926Sdes "Inter-", " Receive", " Transmit", " face", 100585129Sdes "bytes packets errs drop fifo frame compressed", 100683926Sdes "bytes packets errs drop fifo frame compressed"); 100774135Sjlemon 1008108172Shsu IFNET_RLOCK(); 1009181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 101085129Sdes linux_ifname(ifp, ifname, sizeof ifname); 101185129Sdes sbuf_printf(sb, "%6.6s:", ifname); 101283926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 101383926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101483926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 101583926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101674135Sjlemon } 1017108172Shsu IFNET_RUNLOCK(); 1018119068Sdes 101978025Sdes return (0); 102074135Sjlemon} 102174135Sjlemon 1022158311Sambrisko/* 1023167159Sjkim * Filler function for proc/sys/kernel/osrelease 1024167159Sjkim */ 1025167159Sjkimstatic int 1026167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1027167159Sjkim{ 1028167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1029167159Sjkim 1030167159Sjkim linux_get_osrelease(td, osrelease); 1031167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1032167159Sjkim 1033167159Sjkim return (0); 1034167159Sjkim} 1035167159Sjkim 1036167159Sjkim/* 1037167159Sjkim * Filler function for proc/sys/kernel/ostype 1038167159Sjkim */ 1039167159Sjkimstatic int 1040167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1041167159Sjkim{ 1042167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1043167159Sjkim 1044167159Sjkim linux_get_osname(td, osname); 1045167159Sjkim sbuf_printf(sb, "%s\n", osname); 1046167159Sjkim 1047167159Sjkim return (0); 1048167159Sjkim} 1049167159Sjkim 1050167159Sjkim/* 1051167159Sjkim * Filler function for proc/sys/kernel/version 1052167159Sjkim */ 1053167159Sjkimstatic int 1054167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1055167159Sjkim{ 1056168762Sdes 1057167159Sjkim linprocfs_osbuild(td, sb); 1058167159Sjkim sbuf_cat(sb, "\n"); 1059167159Sjkim return (0); 1060167159Sjkim} 1061167159Sjkim 1062167159Sjkim/* 1063164692Sjkim * Filler function for proc/sys/kernel/msgmni 1064164692Sjkim */ 1065164692Sjkimstatic int 1066164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1067164692Sjkim{ 1068164692Sjkim 1069168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1070164692Sjkim return (0); 1071164692Sjkim} 1072164692Sjkim 1073164692Sjkim/* 1074163251Skeramida * Filler function for proc/sys/kernel/pid_max 1075163129Snetchild */ 1076163129Snetchildstatic int 1077163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1078163129Snetchild{ 1079163757Snetchild 1080163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1081163129Snetchild return (0); 1082163129Snetchild} 1083163129Snetchild 1084163129Snetchild/* 1085164692Sjkim * Filler function for proc/sys/kernel/sem 1086164692Sjkim */ 1087164692Sjkimstatic int 1088164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1089164692Sjkim{ 1090164692Sjkim 1091168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1092168067Sjkim seminfo.semopm, seminfo.semmni); 1093164692Sjkim return (0); 1094164692Sjkim} 1095164692Sjkim 1096164692Sjkim/* 1097158311Sambrisko * Filler function for proc/scsi/device_info 1098158311Sambrisko */ 1099158311Sambriskostatic int 1100158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1101158311Sambrisko{ 1102168762Sdes 1103158311Sambrisko return (0); 1104158311Sambrisko} 1105158311Sambrisko 1106158311Sambrisko/* 1107158311Sambrisko * Filler function for proc/scsi/scsi 1108158311Sambrisko */ 1109158311Sambriskostatic int 1110158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1111158311Sambrisko{ 1112168762Sdes 1113158311Sambrisko return (0); 1114158311Sambrisko} 1115158311Sambrisko 111685538Sphkextern struct cdevsw *cdevsw[]; 111785538Sphk 111878113Sdes/* 111978113Sdes * Filler function for proc/devices 112078113Sdes */ 112178025Sdesstatic int 112278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112374135Sjlemon{ 1124158311Sambrisko char *char_devices; 112578025Sdes sbuf_printf(sb, "Character devices:\n"); 112674135Sjlemon 1127158311Sambrisko char_devices = linux_get_char_devices(); 1128158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1129158311Sambrisko linux_free_get_char_devices(char_devices); 113074135Sjlemon 113178025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1132119068Sdes 113378025Sdes return (0); 113474135Sjlemon} 113574135Sjlemon 113678113Sdes/* 113778113Sdes * Filler function for proc/cmdline 113878113Sdes */ 113978025Sdesstatic int 114078025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 114174135Sjlemon{ 1142168762Sdes 114378025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 114478025Sdes sbuf_printf(sb, " ro root=302\n"); 114578025Sdes return (0); 114678025Sdes} 114774135Sjlemon 114883926Sdes#if 0 114978025Sdes/* 115083926Sdes * Filler function for proc/modules 115183926Sdes */ 115283926Sdesstatic int 115383926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 115483926Sdes{ 115583926Sdes struct linker_file *lf; 1156119068Sdes 115783926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 115883926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 115983926Sdes (unsigned long)lf->size, lf->refs); 116083926Sdes } 116183926Sdes return (0); 116283926Sdes} 116383926Sdes#endif 116483926Sdes 116583926Sdes/* 116685129Sdes * Constructor 116778025Sdes */ 116885129Sdesstatic int 116985129Sdeslinprocfs_init(PFS_INIT_ARGS) 117085129Sdes{ 117185129Sdes struct pfs_node *root; 117285129Sdes struct pfs_node *dir; 117374135Sjlemon 117485129Sdes root = pi->pi_root; 117578025Sdes 1176119923Sdes /* /proc/... */ 1177119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1178167482Sdes NULL, NULL, NULL, PFS_RD); 1179119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1180167482Sdes NULL, NULL, NULL, PFS_RD); 1181119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1182167482Sdes NULL, NULL, NULL, PFS_RD); 1183119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1184167482Sdes NULL, NULL, NULL, PFS_RD); 1185119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1186167482Sdes NULL, NULL, NULL, PFS_RD); 118783926Sdes#if 0 1188119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1189167482Sdes NULL, NULL, NULL, PFS_RD); 119083926Sdes#endif 1191158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1192167482Sdes NULL, NULL, NULL, PFS_RD); 1193119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1194167482Sdes NULL, NULL, NULL, PFS_RD); 119587543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1196167482Sdes NULL, NULL, NULL, 0); 1197119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1198167482Sdes NULL, NULL, NULL, PFS_RD); 1199119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1200167482Sdes NULL, NULL, NULL, PFS_RD); 1201119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1202167482Sdes NULL, NULL, NULL, PFS_RD); 120378025Sdes 1204119923Sdes /* /proc/net/... */ 1205167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 120685129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1207167482Sdes NULL, NULL, NULL, PFS_RD); 120878025Sdes 1209119923Sdes /* /proc/<pid>/... */ 1210167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 121185129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1212167482Sdes NULL, NULL, NULL, PFS_RD); 1213119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1214167482Sdes NULL, NULL, NULL, 0); 1215116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1216167482Sdes NULL, NULL, NULL, PFS_RD); 121787543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1218167482Sdes NULL, &procfs_notsystem, NULL, 0); 1219116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1220167482Sdes NULL, NULL, NULL, PFS_RD); 122185129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1222167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1223119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1224167482Sdes NULL, NULL, NULL, 0); 122585129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1226167482Sdes NULL, NULL, NULL, PFS_RD); 1227119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1228167482Sdes NULL, NULL, NULL, PFS_RD); 122985129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1230167482Sdes NULL, NULL, NULL, PFS_RD); 123185129Sdes 1232158311Sambrisko /* /proc/scsi/... */ 1233167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1234158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1235167482Sdes NULL, NULL, NULL, PFS_RD); 1236158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1237167482Sdes NULL, NULL, NULL, PFS_RD); 1238163129Snetchild 1239163129Snetchild /* /proc/sys/... */ 1240167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1241163129Snetchild /* /proc/sys/kernel/... */ 1242167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1243167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1244167482Sdes NULL, NULL, NULL, PFS_RD); 1245167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1246167482Sdes NULL, NULL, NULL, PFS_RD); 1247167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1248167482Sdes NULL, NULL, NULL, PFS_RD); 1249164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1250167482Sdes NULL, NULL, NULL, PFS_RD); 1251163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1252167482Sdes NULL, NULL, NULL, PFS_RD); 1253164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1254167482Sdes NULL, NULL, NULL, PFS_RD); 1255163129Snetchild 125685129Sdes return (0); 125785129Sdes} 125885129Sdes 125985129Sdes/* 126085129Sdes * Destructor 126185129Sdes */ 126285129Sdesstatic int 126385129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 126485129Sdes{ 126585129Sdes 126685129Sdes /* nothing to do, pseudofs will GC */ 126785129Sdes return (0); 126885129Sdes} 126985129Sdes 127085129SdesPSEUDOFS(linprocfs, 1); 127178025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 127278025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1273168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1274168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1275