linprocfs.c revision 174070
1139743Simp/*- 265577Sdes * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav 365577Sdes * Copyright (c) 1999 Pierre Beyssac 459412Smsmith * Copyright (c) 1993 Jan-Simon Pendry 559412Smsmith * Copyright (c) 1993 659412Smsmith * The Regents of the University of California. All rights reserved. 759412Smsmith * 859412Smsmith * This code is derived from software contributed to Berkeley by 959412Smsmith * Jan-Simon Pendry. 1059412Smsmith * 1159412Smsmith * Redistribution and use in source and binary forms, with or without 1259412Smsmith * modification, are permitted provided that the following conditions 1359412Smsmith * are met: 1459412Smsmith * 1. Redistributions of source code must retain the above copyright 1559412Smsmith * notice, this list of conditions and the following disclaimer. 1659412Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1759412Smsmith * notice, this list of conditions and the following disclaimer in the 1859412Smsmith * documentation and/or other materials provided with the distribution. 1959412Smsmith * 3. All advertising materials mentioning features or use of this software 2059412Smsmith * must display the following acknowledgement: 2159412Smsmith * This product includes software developed by the University of 2259412Smsmith * California, Berkeley and its contributors. 2359412Smsmith * 4. Neither the name of the University nor the names of its contributors 2459412Smsmith * may be used to endorse or promote products derived from this software 2559412Smsmith * without specific prior written permission. 2659412Smsmith * 2759412Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2859412Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2959412Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3059412Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3159412Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3259412Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3359412Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3459412Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3559412Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3659412Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3759412Smsmith * SUCH DAMAGE. 3859412Smsmith * 3959412Smsmith * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 4059412Smsmith */ 4159412Smsmith 42116173Sobrien#include <sys/cdefs.h> 43116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 174070 2007-11-29 06:34:30Z peter $"); 44116173Sobrien 4559412Smsmith#include <sys/param.h> 4683926Sdes#include <sys/queue.h> 4776166Smarkm#include <sys/blist.h> 4874135Sjlemon#include <sys/conf.h> 4983926Sdes#include <sys/exec.h> 50119911Sdes#include <sys/filedesc.h> 5176166Smarkm#include <sys/jail.h> 5265633Sdes#include <sys/kernel.h> 5383926Sdes#include <sys/linker.h> 5476166Smarkm#include <sys/lock.h> 5574135Sjlemon#include <sys/malloc.h> 5678025Sdes#include <sys/mount.h> 57168067Sjkim#include <sys/msg.h> 5876827Salfred#include <sys/mutex.h> 5985289Sdes#include <sys/namei.h> 6065633Sdes#include <sys/proc.h> 6165633Sdes#include <sys/resourcevar.h> 6269995Sdes#include <sys/sbuf.h> 63168067Sjkim#include <sys/sem.h> 64123246Sdes#include <sys/smp.h> 6583926Sdes#include <sys/socket.h> 6676839Sjlemon#include <sys/sysctl.h> 6783926Sdes#include <sys/systm.h> 68159995Snetchild#include <sys/time.h> 6965633Sdes#include <sys/tty.h> 7083926Sdes#include <sys/user.h> 7183926Sdes#include <sys/vmmeter.h> 7259412Smsmith#include <sys/vnode.h> 7359412Smsmith 7483926Sdes#include <net/if.h> 7583926Sdes 7659412Smsmith#include <vm/vm.h> 7759412Smsmith#include <vm/pmap.h> 7867588Sdes#include <vm/vm_map.h> 7959412Smsmith#include <vm/vm_param.h> 8060860Sdes#include <vm/vm_object.h> 8159412Smsmith#include <vm/swap_pager.h> 8269799Sdes 8367589Sdes#include <machine/clock.h> 8478113Sdes 85133822Stjr#if defined(__i386__) || defined(__amd64__) 8667589Sdes#include <machine/cputypes.h> 8759412Smsmith#include <machine/md_var.h> 88133822Stjr#endif /* __i386__ || __amd64__ */ 8959412Smsmith 90133822Stjr#include "opt_compat.h" 91140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 92140214Sobrien#include <machine/../linux32/linux.h> 93140214Sobrien#else 9487275Srwatson#include <machine/../linux/linux.h> 95133822Stjr#endif 9685129Sdes#include <compat/linux/linux_ioctl.h> 9769995Sdes#include <compat/linux/linux_mib.h> 9885289Sdes#include <compat/linux/linux_util.h> 9978025Sdes#include <fs/pseudofs/pseudofs.h> 10084248Sdes#include <fs/procfs/procfs.h> 10159412Smsmith 10267588Sdes/* 10367588Sdes * Various conversion macros 10467588Sdes */ 10576405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10667588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10767588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10869799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10967588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11067588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11174135Sjlemon 112159995Snetchild/** 113159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 114159995Snetchild * 115159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 116159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 117172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 118159995Snetchild * or stopped, or process is paging respectively. 119159995Snetchild * 120159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 121159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 122159995Snetchild * 123159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 124159995Snetchild * map our states to suitable linux states. 125159995Snetchild */ 126166140Snetchildstatic char linux_state[] = "RRSTZDD"; 127159995Snetchild 12878113Sdes/* 12978113Sdes * Filler function for proc/meminfo 13078113Sdes */ 13178025Sdesstatic int 13278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13359412Smsmith{ 13459412Smsmith unsigned long memtotal; /* total memory in bytes */ 13559412Smsmith unsigned long memused; /* used memory in bytes */ 13659412Smsmith unsigned long memfree; /* free memory in bytes */ 13759412Smsmith unsigned long memshared; /* shared memory ??? */ 13859412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 139113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 140113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 141113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14260860Sdes vm_object_t object; 143117723Sphk int i, j; 14459412Smsmith 14559412Smsmith memtotal = physmem * PAGE_SIZE; 14659412Smsmith /* 14759412Smsmith * The correct thing here would be: 14859412Smsmith * 149170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15059412Smsmith memused = memtotal - memfree; 15159412Smsmith * 15259412Smsmith * but it might mislead linux binaries into thinking there 15359412Smsmith * is very little memory left, so we cheat and tell them that 15459412Smsmith * all memory that isn't wired down is free. 15559412Smsmith */ 156170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 15759412Smsmith memfree = memtotal - memused; 158117723Sphk swap_pager_status(&i, &j); 159153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 160153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 161117723Sphk swapfree = swaptotal - swapused; 16260860Sdes memshared = 0; 163124082Salc mtx_lock(&vm_object_list_mtx); 16471471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16560860Sdes if (object->shadow_count > 1) 16660860Sdes memshared += object->resident_page_count; 167124082Salc mtx_unlock(&vm_object_list_mtx); 16860860Sdes memshared *= PAGE_SIZE; 16959412Smsmith /* 17059412Smsmith * We'd love to be able to write: 17159412Smsmith * 17259412Smsmith buffers = bufspace; 17359412Smsmith * 17459412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17559412Smsmith * like unstaticizing it just for linprocfs's sake. 17659412Smsmith */ 17759412Smsmith buffers = 0; 178170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 17959412Smsmith 18078025Sdes sbuf_printf(sb, 18178031Sdes " total: used: free: shared: buffers: cached:\n" 18269799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18376839Sjlemon "Swap: %llu %llu %llu\n" 18469799Sdes "MemTotal: %9lu kB\n" 18569799Sdes "MemFree: %9lu kB\n" 18669799Sdes "MemShared:%9lu kB\n" 18769799Sdes "Buffers: %9lu kB\n" 18869799Sdes "Cached: %9lu kB\n" 18976839Sjlemon "SwapTotal:%9llu kB\n" 19076839Sjlemon "SwapFree: %9llu kB\n", 19169799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19269799Sdes swaptotal, swapused, swapfree, 19369799Sdes B2K(memtotal), B2K(memfree), 19469799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19569799Sdes B2K(swaptotal), B2K(swapfree)); 19659412Smsmith 19778025Sdes return (0); 19859412Smsmith} 19959412Smsmith 200133822Stjr#if defined(__i386__) || defined(__amd64__) 20178113Sdes/* 202133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20378113Sdes */ 20478113Sdesstatic int 20578113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 20678113Sdes{ 207159544Sdes int hw_model[2]; 208159544Sdes char model[128]; 209159544Sdes size_t size; 210123246Sdes int class, fqmhz, fqkhz; 211118421Sdes int i; 21259412Smsmith 21369799Sdes /* 21478031Sdes * We default the flags to include all non-conflicting flags, 21578031Sdes * and the Intel versions of conflicting flags. 21669799Sdes */ 21778031Sdes static char *flags[] = { 21878031Sdes "fpu", "vme", "de", "pse", "tsc", 21978031Sdes "msr", "pae", "mce", "cx8", "apic", 22078031Sdes "sep", "sep", "mtrr", "pge", "mca", 22178031Sdes "cmov", "pat", "pse36", "pn", "b19", 22278031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 22378031Sdes "xmm", "b26", "b27", "b28", "b29", 22467589Sdes "3dnowext", "3dnow" 22567589Sdes }; 22667589Sdes 22759412Smsmith switch (cpu_class) { 228133822Stjr#ifdef __i386__ 22959412Smsmith case CPUCLASS_286: 23067589Sdes class = 2; 23159412Smsmith break; 23259412Smsmith case CPUCLASS_386: 23367589Sdes class = 3; 23459412Smsmith break; 23559412Smsmith case CPUCLASS_486: 23667589Sdes class = 4; 23759412Smsmith break; 23859412Smsmith case CPUCLASS_586: 23967589Sdes class = 5; 24059412Smsmith break; 24159412Smsmith case CPUCLASS_686: 24267589Sdes class = 6; 24359412Smsmith break; 24459412Smsmith default: 24578031Sdes class = 0; 24659412Smsmith break; 247159170Sdes#else /* __amd64__ */ 248133822Stjr default: 249159170Sdes class = 15; 250133822Stjr break; 251133822Stjr#endif 25259412Smsmith } 25359412Smsmith 254159544Sdes hw_model[0] = CTL_HW; 255159544Sdes hw_model[1] = HW_MODEL; 256159544Sdes model[0] = '\0'; 257159544Sdes size = sizeof(model); 258159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 259159544Sdes strcpy(model, "unknown"); 260123246Sdes for (i = 0; i < mp_ncpus; ++i) { 261118421Sdes sbuf_printf(sb, 262118421Sdes "processor\t: %d\n" 263118421Sdes "vendor_id\t: %.20s\n" 264118421Sdes "cpu family\t: %d\n" 265118421Sdes "model\t\t: %d\n" 266159544Sdes "model name\t: %s\n" 267118421Sdes "stepping\t: %d\n", 268159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 269159544Sdes /* XXX per-cpu vendor / class / model / id? */ 270118421Sdes } 27159412Smsmith 27278031Sdes sbuf_cat(sb, 27378031Sdes "flags\t\t:"); 27467589Sdes 27578031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27667589Sdes flags[16] = "fcmov"; 27778031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 27867589Sdes flags[24] = "cxmmx"; 27978031Sdes } 280119068Sdes 28178031Sdes for (i = 0; i < 32; i++) 28267589Sdes if (cpu_feature & (1 << i)) 28378025Sdes sbuf_printf(sb, " %s", flags[i]); 28478025Sdes sbuf_cat(sb, "\n"); 28578031Sdes if (class >= 5) { 28669799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 28769799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 28878025Sdes sbuf_printf(sb, 28969799Sdes "cpu MHz\t\t: %d.%02d\n" 29069799Sdes "bogomips\t: %d.%02d\n", 29169799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29278031Sdes } 29369995Sdes 29478025Sdes return (0); 29559412Smsmith} 296133822Stjr#endif /* __i386__ || __amd64__ */ 29765633Sdes 29878113Sdes/* 29985289Sdes * Filler function for proc/mtab 30085289Sdes * 30185289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30285289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30385289Sdes */ 30485289Sdesstatic int 30585289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 30685289Sdes{ 30785289Sdes struct nameidata nd; 30885289Sdes struct mount *mp; 30991334Sjulian const char *lep; 31091334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 31185289Sdes size_t lep_len; 31285289Sdes int error; 31385289Sdes 31485289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 315168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 31685289Sdes flep = NULL; 317168942Sdes error = namei(&nd); 318168942Sdes VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 319168942Sdes if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 32085289Sdes lep = linux_emul_path; 32191334Sjulian else 32291334Sjulian lep = dlep; 32385289Sdes lep_len = strlen(lep); 324119068Sdes 32585289Sdes mtx_lock(&mountlist_mtx); 32685289Sdes error = 0; 32785289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 32885289Sdes /* determine device name */ 32985289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 330119068Sdes 33185289Sdes /* determine mount point */ 33285289Sdes mntto = mp->mnt_stat.f_mntonname; 33385289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 33485289Sdes mntto[lep_len] == '/') 33585289Sdes mntto += lep_len; 33685289Sdes 33785289Sdes /* determine fs type */ 33885289Sdes fstype = mp->mnt_stat.f_fstypename; 33985289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 34085289Sdes mntfrom = fstype = "proc"; 34185289Sdes else if (strcmp(fstype, "procfs") == 0) 34285289Sdes continue; 343119068Sdes 344158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 345158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 346158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 347158311Sambrisko } else { 348158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 349158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 350158311Sambrisko } 35185289Sdes#define ADD_OPTION(opt, name) \ 35285289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 35385289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35485289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 35585289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 35685289Sdes ADD_OPTION(MNT_UNION, "union"); 35785289Sdes ADD_OPTION(MNT_ASYNC, "async"); 35885289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 35985289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 36085289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 36185289Sdes#undef ADD_OPTION 36285289Sdes /* a real Linux mtab will also show NFS options */ 36385289Sdes sbuf_printf(sb, " 0 0\n"); 36485289Sdes } 36585289Sdes mtx_unlock(&mountlist_mtx); 36685289Sdes if (flep != NULL) 36785289Sdes free(flep, M_TEMP); 36885289Sdes return (error); 36985289Sdes} 37085289Sdes 37185289Sdes/* 37278113Sdes * Filler function for proc/stat 37378113Sdes */ 37478025Sdesstatic int 37578025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 37665633Sdes{ 377174070Speter struct pcpu *pcpu; 378174070Speter long cp_time[CPUSTATES]; 379174070Speter long *cp; 380123246Sdes int i; 381120339Sdes 382174070Speter read_cpu_time(cp_time); 383120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 384120339Sdes T2J(cp_time[CP_USER]), 385120339Sdes T2J(cp_time[CP_NICE]), 386120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 387120339Sdes T2J(cp_time[CP_IDLE])); 388174070Speter for (i = 0; i <= mp_maxid; ++i) { 389174070Speter if (CPU_ABSENT(i)) 390174070Speter continue; 391174070Speter pcpu = pcpu_find(i); 392174070Speter cp = pcpu->pc_cp_time; 393143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 394174070Speter T2J(cp[CP_USER]), 395174070Speter T2J(cp[CP_NICE]), 396174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 397174070Speter T2J(cp[CP_IDLE])); 398174070Speter } 39978025Sdes sbuf_printf(sb, 40069799Sdes "disk 0 0 0 0\n" 40169799Sdes "page %u %u\n" 40269799Sdes "swap %u %u\n" 40369799Sdes "intr %u\n" 40469799Sdes "ctxt %u\n" 40585657Sdillon "btime %lld\n", 406170170Sattilio cnt.v_vnodepgsin, 407170170Sattilio cnt.v_vnodepgsout, 408170170Sattilio cnt.v_swappgsin, 409170170Sattilio cnt.v_swappgsout, 410170170Sattilio cnt.v_intr, 411170170Sattilio cnt.v_swtch, 412113574Sjhb (long long)boottime.tv_sec); 41378025Sdes return (0); 41465633Sdes} 41565633Sdes 41678113Sdes/* 41778113Sdes * Filler function for proc/uptime 41878113Sdes */ 41978025Sdesstatic int 42078025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 42165633Sdes{ 422174070Speter long cp_time[CPUSTATES]; 42365633Sdes struct timeval tv; 42465633Sdes 42565633Sdes getmicrouptime(&tv); 426174070Speter read_cpu_time(cp_time); 42785657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 428113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 42969799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43078025Sdes return (0); 43165633Sdes} 43265633Sdes 43378113Sdes/* 434167159Sjkim * Get OS build date 435167159Sjkim */ 436167159Sjkimstatic void 437167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 438167159Sjkim{ 439167159Sjkim#if 0 440167159Sjkim char osbuild[256]; 441167159Sjkim char *cp1, *cp2; 442167159Sjkim 443167159Sjkim strncpy(osbuild, version, 256); 444167159Sjkim osbuild[255] = '\0'; 445167159Sjkim cp1 = strstr(osbuild, "\n"); 446167159Sjkim cp2 = strstr(osbuild, ":"); 447167159Sjkim if (cp1 && cp2) { 448167159Sjkim *cp1 = *cp2 = '\0'; 449167159Sjkim cp1 = strstr(osbuild, "#"); 450167159Sjkim } else 451167159Sjkim cp1 = NULL; 452167159Sjkim if (cp1) 453167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 454167159Sjkim else 455167159Sjkim#endif 456167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 457167159Sjkim} 458167159Sjkim 459167159Sjkim/* 460167159Sjkim * Get OS builder 461167159Sjkim */ 462167159Sjkimstatic void 463167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 464167159Sjkim{ 465168762Sdes#if 0 466167159Sjkim char builder[256]; 467167159Sjkim char *cp; 468167159Sjkim 469167159Sjkim cp = strstr(version, "\n "); 470167159Sjkim if (cp) { 471167159Sjkim strncpy(builder, cp + 5, 256); 472167159Sjkim builder[255] = '\0'; 473167159Sjkim cp = strstr(builder, ":"); 474167159Sjkim if (cp) 475167159Sjkim *cp = '\0'; 476167159Sjkim } 477167159Sjkim if (cp) 478167159Sjkim sbuf_cat(sb, builder); 479167159Sjkim else 480168762Sdes#endif 481167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 482167159Sjkim} 483167159Sjkim 484167159Sjkim/* 48578113Sdes * Filler function for proc/version 48678113Sdes */ 48778025Sdesstatic int 48878025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 48965633Sdes{ 49087275Srwatson char osname[LINUX_MAX_UTSNAME]; 49187275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 49287275Srwatson 493112206Sjhb linux_get_osname(td, osname); 494112206Sjhb linux_get_osrelease(td, osrelease); 495167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 496167159Sjkim linprocfs_osbuilder(td, sb); 497167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 498167159Sjkim linprocfs_osbuild(td, sb); 499167159Sjkim sbuf_cat(sb, "\n"); 50087275Srwatson 50178025Sdes return (0); 50265633Sdes} 50365633Sdes 50478113Sdes/* 50578113Sdes * Filler function for proc/loadavg 50678113Sdes */ 50778025Sdesstatic int 50878025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 50976839Sjlemon{ 510168762Sdes 51178025Sdes sbuf_printf(sb, 51276839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 51376839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 51476839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 51576839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 51676839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 51776839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 51876839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 51976839Sjlemon 1, /* number of running tasks */ 52076839Sjlemon nprocs, /* number of tasks */ 52178116Sdes lastpid /* the last pid */ 52276839Sjlemon ); 52378025Sdes return (0); 52476839Sjlemon} 52576839Sjlemon 52678113Sdes/* 52778113Sdes * Filler function for proc/pid/stat 52878113Sdes */ 52978025Sdesstatic int 53078025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 53167588Sdes{ 53269995Sdes struct kinfo_proc kp; 533166140Snetchild char state; 534166140Snetchild static int ratelimit = 0; 53567588Sdes 53694307Sjhb PROC_LOCK(p); 53769995Sdes fill_kinfo_proc(p, &kp); 53878025Sdes sbuf_printf(sb, "%d", p->p_pid); 53978025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 54067588Sdes PS_ADD("comm", "(%s)", p->p_comm); 541166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 542166140Snetchild state = 'R'; 543166140Snetchild 544166141Snetchild if (ratelimit == 0) { 545166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 546166162Snetchild kp.ki_stat, sizeof(linux_state)); 547166141Snetchild ++ratelimit; 548166141Snetchild } 549166140Snetchild } else 550166140Snetchild state = linux_state[kp.ki_stat - 1]; 551166140Snetchild PS_ADD("state", "%c", state); 55273923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 55367588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 55467588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 55591140Stanimura PROC_UNLOCK(p); 55667588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 557159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 55867588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 559159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 560159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 561159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 562159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 563159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 564159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 565159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 566159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 567159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 568159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 569159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 570159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 571159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 572159995Snetchild It should be the number of jiffies between system boot and process 573159995Snetchild start. */ 574159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 575159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 576159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 577159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 57869995Sdes PS_ADD("startcode", "%u", (unsigned)0); 57967588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 58067588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 581159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 582159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 583159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 584159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 585159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 586159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 58767588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 588159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 589159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 59069799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 591159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 592159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 593159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 59467588Sdes#undef PS_ADD 59578025Sdes sbuf_putc(sb, '\n'); 596119068Sdes 59778025Sdes return (0); 59867588Sdes} 59967588Sdes 60067588Sdes/* 601119911Sdes * Filler function for proc/pid/statm 602119911Sdes */ 603119911Sdesstatic int 604119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 605119911Sdes{ 606119911Sdes struct kinfo_proc kp; 607119911Sdes segsz_t lsize; 608120340Sdes 609119911Sdes PROC_LOCK(p); 610119911Sdes fill_kinfo_proc(p, &kp); 611119911Sdes PROC_UNLOCK(p); 612119911Sdes 613119911Sdes /* 614119911Sdes * See comments in linprocfs_doprocstatus() regarding the 615119911Sdes * computation of lsize. 616119911Sdes */ 617119911Sdes /* size resident share trs drs lrs dt */ 618119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 619119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 620119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 621119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 622119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 623119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 624119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 625119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 626119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 627119911Sdes 628119911Sdes return (0); 629119911Sdes} 630119911Sdes 631119911Sdes/* 63278113Sdes * Filler function for proc/pid/status 63378113Sdes */ 63478025Sdesstatic int 63578025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 63667588Sdes{ 63769995Sdes struct kinfo_proc kp; 63867588Sdes char *state; 63969799Sdes segsz_t lsize; 64099072Sjulian struct thread *td2; 641114983Sjhb struct sigacts *ps; 64274135Sjlemon int i; 64367588Sdes 644113611Sjhb PROC_LOCK(p); 64599072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 64699072Sjulian 64799072Sjulian if (P_SHOULDSTOP(p)) { 64899072Sjulian state = "T (stopped)"; 64999072Sjulian } else { 650170307Sjeff PROC_SLOCK(p); 65199072Sjulian switch(p->p_state) { 65299072Sjulian case PRS_NEW: 65399072Sjulian state = "I (idle)"; 65499072Sjulian break; 65599072Sjulian case PRS_NORMAL: 65699072Sjulian if (p->p_flag & P_WEXIT) { 65799072Sjulian state = "X (exiting)"; 65899072Sjulian break; 65999072Sjulian } 66099072Sjulian switch(td2->td_state) { 661103216Sjulian case TDS_INHIBITED: 66299072Sjulian state = "S (sleeping)"; 66399072Sjulian break; 66499072Sjulian case TDS_RUNQ: 66599072Sjulian case TDS_RUNNING: 66699072Sjulian state = "R (running)"; 66799072Sjulian break; 66899072Sjulian default: 66999072Sjulian state = "? (unknown)"; 67099072Sjulian break; 67199072Sjulian } 67299072Sjulian break; 67399072Sjulian case PRS_ZOMBIE: 67499072Sjulian state = "Z (zombie)"; 67599072Sjulian break; 67699072Sjulian default: 67799072Sjulian state = "? (unknown)"; 67899072Sjulian break; 67999072Sjulian } 680170307Sjeff PROC_SUNLOCK(p); 68199072Sjulian } 68267588Sdes 68369995Sdes fill_kinfo_proc(p, &kp); 68478025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 68578031Sdes sbuf_printf(sb, "State:\t%s\n", state); 68667588Sdes 68767588Sdes /* 68867588Sdes * Credentials 68967588Sdes */ 69078025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 69178025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 69273923Sjhb p->p_pptr->p_pid : 0); 69378031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 69478031Sdes p->p_ucred->cr_uid, 69578031Sdes p->p_ucred->cr_svuid, 69678031Sdes /* FreeBSD doesn't have fsuid */ 69778031Sdes p->p_ucred->cr_uid); 69878031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 69978031Sdes p->p_ucred->cr_gid, 70078031Sdes p->p_ucred->cr_svgid, 70178031Sdes /* FreeBSD doesn't have fsgid */ 70278031Sdes p->p_ucred->cr_gid); 70378025Sdes sbuf_cat(sb, "Groups:\t"); 70467588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 70578031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 70671471Sjhb PROC_UNLOCK(p); 70778025Sdes sbuf_putc(sb, '\n'); 708119068Sdes 70967588Sdes /* 71067588Sdes * Memory 71169799Sdes * 71269799Sdes * While our approximation of VmLib may not be accurate (I 71369799Sdes * don't know of a simple way to verify it, and I'm not sure 71469799Sdes * it has much meaning anyway), I believe it's good enough. 71569799Sdes * 71669799Sdes * The same code that could (I think) accurately compute VmLib 71769799Sdes * could also compute VmLck, but I don't really care enough to 71869799Sdes * implement it. Submissions are welcome. 71967588Sdes */ 720113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 72178025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 722113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 723113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 724113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 725113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 72669995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 72769995Sdes kp.ki_ssize - kp.ki_tsize - 1; 728113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 72967588Sdes 73067588Sdes /* 73167588Sdes * Signal masks 73267588Sdes * 73367588Sdes * We support up to 128 signals, while Linux supports 32, 73467588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 73567588Sdes * just show the lower 32 bits of each mask. XXX hack. 73667588Sdes * 73767588Sdes * NB: on certain platforms (Sparc at least) Linux actually 73867588Sdes * supports 64 signals, but this code is a long way from 73967588Sdes * running on anything but i386, so ignore that for now. 74067588Sdes */ 74171471Sjhb PROC_LOCK(p); 742104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 74369799Sdes /* 74469799Sdes * I can't seem to find out where the signal mask is in 74569799Sdes * relation to struct proc, so SigBlk is left unimplemented. 74669799Sdes */ 74778025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 748114983Sjhb ps = p->p_sigacts; 749114983Sjhb mtx_lock(&ps->ps_mtx); 750114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 751114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 752114983Sjhb mtx_unlock(&ps->ps_mtx); 75371471Sjhb PROC_UNLOCK(p); 754119068Sdes 75567588Sdes /* 75667588Sdes * Linux also prints the capability masks, but we don't have 75767588Sdes * capabilities yet, and when we do get them they're likely to 75867588Sdes * be meaningless to Linux programs, so we lie. XXX 75967588Sdes */ 76078025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 76178025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 76278025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 763119068Sdes 76478025Sdes return (0); 76567588Sdes} 76674135Sjlemon 767119911Sdes 76878113Sdes/* 769119911Sdes * Filler function for proc/pid/cwd 770119911Sdes */ 771119911Sdesstatic int 772119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 773119911Sdes{ 774119911Sdes char *fullpath = "unknown"; 775119911Sdes char *freepath = NULL; 776119911Sdes 777119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 778119911Sdes sbuf_printf(sb, "%s", fullpath); 779119911Sdes if (freepath) 780119911Sdes free(freepath, M_TEMP); 781119911Sdes return (0); 782119911Sdes} 783119911Sdes 784119911Sdes/* 785119911Sdes * Filler function for proc/pid/root 786119911Sdes */ 787119911Sdesstatic int 788119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 789119911Sdes{ 790119911Sdes struct vnode *rvp; 791119911Sdes char *fullpath = "unknown"; 792119911Sdes char *freepath = NULL; 793119911Sdes 794119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 795119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 796119911Sdes sbuf_printf(sb, "%s", fullpath); 797119911Sdes if (freepath) 798119911Sdes free(freepath, M_TEMP); 799119911Sdes return (0); 800119911Sdes} 801119911Sdes 802119911Sdes/* 80378113Sdes * Filler function for proc/pid/cmdline 80478113Sdes */ 80578025Sdesstatic int 80678113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 80778113Sdes{ 80878113Sdes struct ps_strings pstr; 809138281Scperciva char **ps_argvstr; 81078113Sdes int error, i; 81178113Sdes 81278113Sdes /* 81378113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 81478113Sdes * revert back to the old way which only implements full cmdline 81578113Sdes * for the currept process and just p->p_comm for all other 81678113Sdes * processes. 81778113Sdes * Note that if the argv is no longer available, we deliberately 81878113Sdes * don't fall back on p->p_comm or return an error: the authentic 81978113Sdes * Linux behaviour is to return zero-length in this case. 82078113Sdes */ 82178113Sdes 82294620Sjhb PROC_LOCK(p); 823127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 82494620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 82594620Sjhb PROC_UNLOCK(p); 82694620Sjhb } else if (p != td->td_proc) { 82794620Sjhb PROC_UNLOCK(p); 82894620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 82994620Sjhb } else { 83094620Sjhb PROC_UNLOCK(p); 831103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 832103767Sjake sizeof(pstr)); 83394620Sjhb if (error) 83494620Sjhb return (error); 835138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 836138281Scperciva return (E2BIG); 837138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 838138281Scperciva M_TEMP, M_WAITOK); 839138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 840138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 841138281Scperciva if (error) { 842138281Scperciva free(ps_argvstr, M_TEMP); 843138281Scperciva return (error); 844138281Scperciva } 84594620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 846138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 84794620Sjhb sbuf_printf(sb, "%c", '\0'); 84878113Sdes } 849138281Scperciva free(ps_argvstr, M_TEMP); 85078113Sdes } 85178113Sdes 85278113Sdes return (0); 85378113Sdes} 85478113Sdes 85578113Sdes/* 856116173Sobrien * Filler function for proc/pid/environ 857116173Sobrien */ 858116173Sobrienstatic int 859116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 860116173Sobrien{ 861168762Sdes 862116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 863116173Sobrien return (0); 864116173Sobrien} 865116173Sobrien 866116173Sobrien/* 867116173Sobrien * Filler function for proc/pid/maps 868116173Sobrien */ 869116173Sobrienstatic int 870116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 871116173Sobrien{ 872121265Scognet char mebuffer[512]; 873121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 874169156Salc vm_map_entry_t entry, tmp_entry; 875121265Scognet vm_object_t obj, tobj, lobj; 876169156Salc vm_offset_t saved_end; 877121265Scognet vm_ooffset_t off = 0; 878121265Scognet char *name = "", *freename = NULL; 879121265Scognet size_t len; 880121265Scognet ino_t ino; 881169156Salc unsigned int last_timestamp; 882121265Scognet int ref_count, shadow_count, flags; 883121265Scognet int error; 884137507Sphk struct vnode *vp; 885137507Sphk struct vattr vat; 886161094Skib int locked; 887168762Sdes 888121246Scognet PROC_LOCK(p); 889121246Scognet error = p_candebug(td, p); 890121246Scognet PROC_UNLOCK(p); 891121246Scognet if (error) 892121246Scognet return (error); 893168762Sdes 894121246Scognet if (uio->uio_rw != UIO_READ) 895121246Scognet return (EOPNOTSUPP); 896168762Sdes 897121246Scognet if (uio->uio_offset != 0) 898121246Scognet return (0); 899168762Sdes 900121246Scognet error = 0; 901169156Salc vm_map_lock_read(map); 902168762Sdes for (entry = map->header.next; 903121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 904121246Scognet entry = entry->next) { 905121265Scognet name = ""; 906121265Scognet freename = NULL; 907121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 908121246Scognet continue; 909169156Salc saved_end = entry->end; 910121246Scognet obj = entry->object.vm_object; 911169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 912169156Salc VM_OBJECT_LOCK(tobj); 913169156Salc if (lobj != obj) 914169156Salc VM_OBJECT_UNLOCK(lobj); 915121246Scognet lobj = tobj; 916169156Salc } 917121246Scognet ino = 0; 918121246Scognet if (lobj) { 919121246Scognet off = IDX_TO_OFF(lobj->size); 920161094Skib if (lobj->type == OBJT_VNODE) { 921161094Skib vp = lobj->handle; 922161094Skib if (vp) 923161094Skib vref(vp); 924121246Scognet } 925161094Skib else 926161094Skib vp = NULL; 927169156Salc if (lobj != obj) 928169156Salc VM_OBJECT_UNLOCK(lobj); 929121246Scognet flags = obj->flags; 930121246Scognet ref_count = obj->ref_count; 931121246Scognet shadow_count = obj->shadow_count; 932169156Salc VM_OBJECT_UNLOCK(obj); 933161094Skib if (vp) { 934161094Skib vn_fullpath(td, vp, &name, &freename); 935161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 936161094Skib vn_lock(vp, LK_SHARED | LK_RETRY, td); 937161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 938161094Skib ino = vat.va_fileid; 939161094Skib vput(vp); 940161094Skib VFS_UNLOCK_GIANT(locked); 941161094Skib } 942121246Scognet } else { 943121246Scognet flags = 0; 944121246Scognet ref_count = 0; 945121246Scognet shadow_count = 0; 946121246Scognet } 947168762Sdes 948121246Scognet /* 949168762Sdes * format: 950121246Scognet * start, end, access, offset, major, minor, inode, name. 951121246Scognet */ 952121246Scognet snprintf(mebuffer, sizeof mebuffer, 953121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 954121246Scognet (u_long)entry->start, (u_long)entry->end, 955121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 956121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 957121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 958121246Scognet "p", 959121265Scognet (u_long)off, 960121246Scognet 0, 961121246Scognet 0, 962121265Scognet (u_long)ino, 963121246Scognet *name ? " " : "", 964121246Scognet name 965121246Scognet ); 966121246Scognet if (freename) 967121246Scognet free(freename, M_TEMP); 968121246Scognet len = strlen(mebuffer); 969121246Scognet if (len > uio->uio_resid) 970121246Scognet len = uio->uio_resid; /* 971121246Scognet * XXX We should probably return 972121246Scognet * EFBIG here, as in procfs. 973121246Scognet */ 974169156Salc last_timestamp = map->timestamp; 975169156Salc vm_map_unlock_read(map); 976121246Scognet error = uiomove(mebuffer, len, uio); 977169156Salc vm_map_lock_read(map); 978121246Scognet if (error) 979121246Scognet break; 980169156Salc if (last_timestamp + 1 != map->timestamp) { 981169156Salc /* 982169156Salc * Look again for the entry because the map was 983169156Salc * modified while it was unlocked. Specifically, 984169156Salc * the entry may have been clipped, merged, or deleted. 985169156Salc */ 986169156Salc vm_map_lookup_entry(map, saved_end - 1, &tmp_entry); 987169156Salc entry = tmp_entry; 988169156Salc } 989121246Scognet } 990169156Salc vm_map_unlock_read(map); 991168762Sdes 992121246Scognet return (error); 993168762Sdes} 994168762Sdes 995116173Sobrien/* 99678113Sdes * Filler function for proc/net/dev 99778113Sdes */ 99878025Sdesstatic int 99978025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 100074135Sjlemon{ 100185129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 100274135Sjlemon struct ifnet *ifp; 100374135Sjlemon 100485129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 100583926Sdes "Inter-", " Receive", " Transmit", " face", 100685129Sdes "bytes packets errs drop fifo frame compressed", 100783926Sdes "bytes packets errs drop fifo frame compressed"); 100874135Sjlemon 1009108172Shsu IFNET_RLOCK(); 101074135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 101185129Sdes linux_ifname(ifp, ifname, sizeof ifname); 101285129Sdes sbuf_printf(sb, "%6.6s:", ifname); 101383926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 101483926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101583926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 101683926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101774135Sjlemon } 1018108172Shsu IFNET_RUNLOCK(); 1019119068Sdes 102078025Sdes return (0); 102174135Sjlemon} 102274135Sjlemon 1023158311Sambrisko/* 1024167159Sjkim * Filler function for proc/sys/kernel/osrelease 1025167159Sjkim */ 1026167159Sjkimstatic int 1027167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1028167159Sjkim{ 1029167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1030167159Sjkim 1031167159Sjkim linux_get_osrelease(td, osrelease); 1032167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1033167159Sjkim 1034167159Sjkim return (0); 1035167159Sjkim} 1036167159Sjkim 1037167159Sjkim/* 1038167159Sjkim * Filler function for proc/sys/kernel/ostype 1039167159Sjkim */ 1040167159Sjkimstatic int 1041167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1042167159Sjkim{ 1043167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1044167159Sjkim 1045167159Sjkim linux_get_osname(td, osname); 1046167159Sjkim sbuf_printf(sb, "%s\n", osname); 1047167159Sjkim 1048167159Sjkim return (0); 1049167159Sjkim} 1050167159Sjkim 1051167159Sjkim/* 1052167159Sjkim * Filler function for proc/sys/kernel/version 1053167159Sjkim */ 1054167159Sjkimstatic int 1055167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1056167159Sjkim{ 1057168762Sdes 1058167159Sjkim linprocfs_osbuild(td, sb); 1059167159Sjkim sbuf_cat(sb, "\n"); 1060167159Sjkim return (0); 1061167159Sjkim} 1062167159Sjkim 1063167159Sjkim/* 1064164692Sjkim * Filler function for proc/sys/kernel/msgmni 1065164692Sjkim */ 1066164692Sjkimstatic int 1067164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1068164692Sjkim{ 1069164692Sjkim 1070168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1071164692Sjkim return (0); 1072164692Sjkim} 1073164692Sjkim 1074164692Sjkim/* 1075163251Skeramida * Filler function for proc/sys/kernel/pid_max 1076163129Snetchild */ 1077163129Snetchildstatic int 1078163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1079163129Snetchild{ 1080163757Snetchild 1081163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1082163129Snetchild return (0); 1083163129Snetchild} 1084163129Snetchild 1085163129Snetchild/* 1086164692Sjkim * Filler function for proc/sys/kernel/sem 1087164692Sjkim */ 1088164692Sjkimstatic int 1089164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1090164692Sjkim{ 1091164692Sjkim 1092168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1093168067Sjkim seminfo.semopm, seminfo.semmni); 1094164692Sjkim return (0); 1095164692Sjkim} 1096164692Sjkim 1097164692Sjkim/* 1098158311Sambrisko * Filler function for proc/scsi/device_info 1099158311Sambrisko */ 1100158311Sambriskostatic int 1101158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1102158311Sambrisko{ 1103168762Sdes 1104158311Sambrisko return (0); 1105158311Sambrisko} 1106158311Sambrisko 1107158311Sambrisko/* 1108158311Sambrisko * Filler function for proc/scsi/scsi 1109158311Sambrisko */ 1110158311Sambriskostatic int 1111158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1112158311Sambrisko{ 1113168762Sdes 1114158311Sambrisko return (0); 1115158311Sambrisko} 1116158311Sambrisko 111785538Sphkextern struct cdevsw *cdevsw[]; 111885538Sphk 111978113Sdes/* 112078113Sdes * Filler function for proc/devices 112178113Sdes */ 112278025Sdesstatic int 112378025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112474135Sjlemon{ 1125158311Sambrisko char *char_devices; 112678025Sdes sbuf_printf(sb, "Character devices:\n"); 112774135Sjlemon 1128158311Sambrisko char_devices = linux_get_char_devices(); 1129158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1130158311Sambrisko linux_free_get_char_devices(char_devices); 113174135Sjlemon 113278025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1133119068Sdes 113478025Sdes return (0); 113574135Sjlemon} 113674135Sjlemon 113778113Sdes/* 113878113Sdes * Filler function for proc/cmdline 113978113Sdes */ 114078025Sdesstatic int 114178025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 114274135Sjlemon{ 1143168762Sdes 114478025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 114578025Sdes sbuf_printf(sb, " ro root=302\n"); 114678025Sdes return (0); 114778025Sdes} 114874135Sjlemon 114983926Sdes#if 0 115078025Sdes/* 115183926Sdes * Filler function for proc/modules 115283926Sdes */ 115383926Sdesstatic int 115483926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 115583926Sdes{ 115683926Sdes struct linker_file *lf; 1157119068Sdes 115883926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 115983926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 116083926Sdes (unsigned long)lf->size, lf->refs); 116183926Sdes } 116283926Sdes return (0); 116383926Sdes} 116483926Sdes#endif 116583926Sdes 116683926Sdes/* 116785129Sdes * Constructor 116878025Sdes */ 116985129Sdesstatic int 117085129Sdeslinprocfs_init(PFS_INIT_ARGS) 117185129Sdes{ 117285129Sdes struct pfs_node *root; 117385129Sdes struct pfs_node *dir; 117474135Sjlemon 117585129Sdes root = pi->pi_root; 117678025Sdes 1177119923Sdes /* /proc/... */ 1178119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1179167482Sdes NULL, NULL, NULL, PFS_RD); 1180119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1181167482Sdes NULL, NULL, NULL, PFS_RD); 1182119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1183167482Sdes NULL, NULL, NULL, PFS_RD); 1184119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1185167482Sdes NULL, NULL, NULL, PFS_RD); 1186119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1187167482Sdes NULL, NULL, NULL, PFS_RD); 118883926Sdes#if 0 1189119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1190167482Sdes NULL, NULL, NULL, PFS_RD); 119183926Sdes#endif 1192158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1193167482Sdes NULL, NULL, NULL, PFS_RD); 1194119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1195167482Sdes NULL, NULL, NULL, PFS_RD); 119687543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1197167482Sdes NULL, NULL, NULL, 0); 1198119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1199167482Sdes NULL, NULL, NULL, PFS_RD); 1200119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1201167482Sdes NULL, NULL, NULL, PFS_RD); 1202119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1203167482Sdes NULL, NULL, NULL, PFS_RD); 120478025Sdes 1205119923Sdes /* /proc/net/... */ 1206167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 120785129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1208167482Sdes NULL, NULL, NULL, PFS_RD); 120978025Sdes 1210119923Sdes /* /proc/<pid>/... */ 1211167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 121285129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1213167482Sdes NULL, NULL, NULL, PFS_RD); 1214119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1215167482Sdes NULL, NULL, NULL, 0); 1216116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1217167482Sdes NULL, NULL, NULL, PFS_RD); 121887543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1219167482Sdes NULL, &procfs_notsystem, NULL, 0); 1220116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1221167482Sdes NULL, NULL, NULL, PFS_RD); 122285129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1223167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1224119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1225167482Sdes NULL, NULL, NULL, 0); 122685129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1227167482Sdes NULL, NULL, NULL, PFS_RD); 1228119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1229167482Sdes NULL, NULL, NULL, PFS_RD); 123085129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1231167482Sdes NULL, NULL, NULL, PFS_RD); 123285129Sdes 1233158311Sambrisko /* /proc/scsi/... */ 1234167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1235158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1236167482Sdes NULL, NULL, NULL, PFS_RD); 1237158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1238167482Sdes NULL, NULL, NULL, PFS_RD); 1239163129Snetchild 1240163129Snetchild /* /proc/sys/... */ 1241167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1242163129Snetchild /* /proc/sys/kernel/... */ 1243167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1244167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1245167482Sdes NULL, NULL, NULL, PFS_RD); 1246167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1247167482Sdes NULL, NULL, NULL, PFS_RD); 1248167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1249167482Sdes NULL, NULL, NULL, PFS_RD); 1250164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1251167482Sdes NULL, NULL, NULL, PFS_RD); 1252163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1253167482Sdes NULL, NULL, NULL, PFS_RD); 1254164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1255167482Sdes NULL, NULL, NULL, PFS_RD); 1256163129Snetchild 125785129Sdes return (0); 125885129Sdes} 125985129Sdes 126085129Sdes/* 126185129Sdes * Destructor 126285129Sdes */ 126385129Sdesstatic int 126485129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 126585129Sdes{ 126685129Sdes 126785129Sdes /* nothing to do, pseudofs will GC */ 126885129Sdes return (0); 126985129Sdes} 127085129Sdes 127185129SdesPSEUDOFS(linprocfs, 1); 127278025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 127378025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1274168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1275168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1276