linprocfs.c revision 181803
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 181803 2008-08-17 23:27:27Z bz $"); 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> 50177785Skib#include <sys/fcntl.h> 51119911Sdes#include <sys/filedesc.h> 5276166Smarkm#include <sys/jail.h> 5365633Sdes#include <sys/kernel.h> 5483926Sdes#include <sys/linker.h> 5576166Smarkm#include <sys/lock.h> 5674135Sjlemon#include <sys/malloc.h> 5778025Sdes#include <sys/mount.h> 58168067Sjkim#include <sys/msg.h> 5976827Salfred#include <sys/mutex.h> 6085289Sdes#include <sys/namei.h> 6165633Sdes#include <sys/proc.h> 6265633Sdes#include <sys/resourcevar.h> 6369995Sdes#include <sys/sbuf.h> 64168067Sjkim#include <sys/sem.h> 65123246Sdes#include <sys/smp.h> 6683926Sdes#include <sys/socket.h> 6776839Sjlemon#include <sys/sysctl.h> 6883926Sdes#include <sys/systm.h> 69159995Snetchild#include <sys/time.h> 7065633Sdes#include <sys/tty.h> 7183926Sdes#include <sys/user.h> 7283926Sdes#include <sys/vmmeter.h> 7359412Smsmith#include <sys/vnode.h> 74181803Sbz#include <sys/vimage.h> 7559412Smsmith 7683926Sdes#include <net/if.h> 7783926Sdes 7859412Smsmith#include <vm/vm.h> 7959412Smsmith#include <vm/pmap.h> 8067588Sdes#include <vm/vm_map.h> 8159412Smsmith#include <vm/vm_param.h> 8260860Sdes#include <vm/vm_object.h> 8359412Smsmith#include <vm/swap_pager.h> 8469799Sdes 8567589Sdes#include <machine/clock.h> 8678113Sdes 87133822Stjr#if defined(__i386__) || defined(__amd64__) 8867589Sdes#include <machine/cputypes.h> 8959412Smsmith#include <machine/md_var.h> 90133822Stjr#endif /* __i386__ || __amd64__ */ 9159412Smsmith 92133822Stjr#include "opt_compat.h" 93140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 94140214Sobrien#include <machine/../linux32/linux.h> 95140214Sobrien#else 9687275Srwatson#include <machine/../linux/linux.h> 97133822Stjr#endif 9885129Sdes#include <compat/linux/linux_ioctl.h> 9969995Sdes#include <compat/linux/linux_mib.h> 10085289Sdes#include <compat/linux/linux_util.h> 10178025Sdes#include <fs/pseudofs/pseudofs.h> 10284248Sdes#include <fs/procfs/procfs.h> 10359412Smsmith 10467588Sdes/* 10567588Sdes * Various conversion macros 10667588Sdes */ 10776405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10867588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10967588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 11069799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 11167588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11267588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11374135Sjlemon 114159995Snetchild/** 115159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 116159995Snetchild * 117159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 118159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 119172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 120159995Snetchild * or stopped, or process is paging respectively. 121159995Snetchild * 122159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 123159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 124159995Snetchild * 125159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 126159995Snetchild * map our states to suitable linux states. 127159995Snetchild */ 128166140Snetchildstatic char linux_state[] = "RRSTZDD"; 129159995Snetchild 13078113Sdes/* 13178113Sdes * Filler function for proc/meminfo 13278113Sdes */ 13378025Sdesstatic int 13478025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13559412Smsmith{ 13659412Smsmith unsigned long memtotal; /* total memory in bytes */ 13759412Smsmith unsigned long memused; /* used memory in bytes */ 13859412Smsmith unsigned long memfree; /* free memory in bytes */ 13959412Smsmith unsigned long memshared; /* shared memory ??? */ 14059412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 141113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 142113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 143113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14460860Sdes vm_object_t object; 145117723Sphk int i, j; 14659412Smsmith 14759412Smsmith memtotal = physmem * PAGE_SIZE; 14859412Smsmith /* 14959412Smsmith * The correct thing here would be: 15059412Smsmith * 151170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15259412Smsmith memused = memtotal - memfree; 15359412Smsmith * 15459412Smsmith * but it might mislead linux binaries into thinking there 15559412Smsmith * is very little memory left, so we cheat and tell them that 15659412Smsmith * all memory that isn't wired down is free. 15759412Smsmith */ 158170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 15959412Smsmith memfree = memtotal - memused; 160117723Sphk swap_pager_status(&i, &j); 161153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 162153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 163117723Sphk swapfree = swaptotal - swapused; 16460860Sdes memshared = 0; 165124082Salc mtx_lock(&vm_object_list_mtx); 16671471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16760860Sdes if (object->shadow_count > 1) 16860860Sdes memshared += object->resident_page_count; 169124082Salc mtx_unlock(&vm_object_list_mtx); 17060860Sdes memshared *= PAGE_SIZE; 17159412Smsmith /* 17259412Smsmith * We'd love to be able to write: 17359412Smsmith * 17459412Smsmith buffers = bufspace; 17559412Smsmith * 17659412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17759412Smsmith * like unstaticizing it just for linprocfs's sake. 17859412Smsmith */ 17959412Smsmith buffers = 0; 180170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 18159412Smsmith 18278025Sdes sbuf_printf(sb, 18378031Sdes " total: used: free: shared: buffers: cached:\n" 18469799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18576839Sjlemon "Swap: %llu %llu %llu\n" 18669799Sdes "MemTotal: %9lu kB\n" 18769799Sdes "MemFree: %9lu kB\n" 18869799Sdes "MemShared:%9lu kB\n" 18969799Sdes "Buffers: %9lu kB\n" 19069799Sdes "Cached: %9lu kB\n" 19176839Sjlemon "SwapTotal:%9llu kB\n" 19276839Sjlemon "SwapFree: %9llu kB\n", 19369799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19469799Sdes swaptotal, swapused, swapfree, 19569799Sdes B2K(memtotal), B2K(memfree), 19669799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19769799Sdes B2K(swaptotal), B2K(swapfree)); 19859412Smsmith 19978025Sdes return (0); 20059412Smsmith} 20159412Smsmith 202133822Stjr#if defined(__i386__) || defined(__amd64__) 20378113Sdes/* 204133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20578113Sdes */ 20678113Sdesstatic int 20778113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 20878113Sdes{ 209159544Sdes int hw_model[2]; 210159544Sdes char model[128]; 211159544Sdes size_t size; 212123246Sdes int class, fqmhz, fqkhz; 213118421Sdes int i; 21459412Smsmith 21569799Sdes /* 21678031Sdes * We default the flags to include all non-conflicting flags, 21778031Sdes * and the Intel versions of conflicting flags. 21869799Sdes */ 21978031Sdes static char *flags[] = { 22078031Sdes "fpu", "vme", "de", "pse", "tsc", 22178031Sdes "msr", "pae", "mce", "cx8", "apic", 22278031Sdes "sep", "sep", "mtrr", "pge", "mca", 22378031Sdes "cmov", "pat", "pse36", "pn", "b19", 22478031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 22578031Sdes "xmm", "b26", "b27", "b28", "b29", 22667589Sdes "3dnowext", "3dnow" 22767589Sdes }; 22867589Sdes 22959412Smsmith switch (cpu_class) { 230133822Stjr#ifdef __i386__ 23159412Smsmith case CPUCLASS_286: 23267589Sdes class = 2; 23359412Smsmith break; 23459412Smsmith case CPUCLASS_386: 23567589Sdes class = 3; 23659412Smsmith break; 23759412Smsmith case CPUCLASS_486: 23867589Sdes class = 4; 23959412Smsmith break; 24059412Smsmith case CPUCLASS_586: 24167589Sdes class = 5; 24259412Smsmith break; 24359412Smsmith case CPUCLASS_686: 24467589Sdes class = 6; 24559412Smsmith break; 24659412Smsmith default: 24778031Sdes class = 0; 24859412Smsmith break; 249159170Sdes#else /* __amd64__ */ 250133822Stjr default: 251159170Sdes class = 15; 252133822Stjr break; 253133822Stjr#endif 25459412Smsmith } 25559412Smsmith 256159544Sdes hw_model[0] = CTL_HW; 257159544Sdes hw_model[1] = HW_MODEL; 258159544Sdes model[0] = '\0'; 259159544Sdes size = sizeof(model); 260159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 261159544Sdes strcpy(model, "unknown"); 262123246Sdes for (i = 0; i < mp_ncpus; ++i) { 263118421Sdes sbuf_printf(sb, 264118421Sdes "processor\t: %d\n" 265118421Sdes "vendor_id\t: %.20s\n" 266118421Sdes "cpu family\t: %d\n" 267118421Sdes "model\t\t: %d\n" 268159544Sdes "model name\t: %s\n" 269118421Sdes "stepping\t: %d\n", 270159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 271159544Sdes /* XXX per-cpu vendor / class / model / id? */ 272118421Sdes } 27359412Smsmith 27478031Sdes sbuf_cat(sb, 27578031Sdes "flags\t\t:"); 27667589Sdes 27778031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27867589Sdes flags[16] = "fcmov"; 27978031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 28067589Sdes flags[24] = "cxmmx"; 28178031Sdes } 282119068Sdes 28378031Sdes for (i = 0; i < 32; i++) 28467589Sdes if (cpu_feature & (1 << i)) 28578025Sdes sbuf_printf(sb, " %s", flags[i]); 28678025Sdes sbuf_cat(sb, "\n"); 28778031Sdes if (class >= 5) { 28869799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 28969799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 29078025Sdes sbuf_printf(sb, 29169799Sdes "cpu MHz\t\t: %d.%02d\n" 29269799Sdes "bogomips\t: %d.%02d\n", 29369799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29478031Sdes } 29569995Sdes 29678025Sdes return (0); 29759412Smsmith} 298133822Stjr#endif /* __i386__ || __amd64__ */ 29965633Sdes 30078113Sdes/* 30185289Sdes * Filler function for proc/mtab 30285289Sdes * 30385289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30485289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30585289Sdes */ 30685289Sdesstatic int 30785289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 30885289Sdes{ 30985289Sdes struct nameidata nd; 31085289Sdes struct mount *mp; 31191334Sjulian const char *lep; 31291334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 31385289Sdes size_t lep_len; 31485289Sdes int error; 31585289Sdes 31685289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 317168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 31885289Sdes flep = NULL; 319168942Sdes error = namei(&nd); 320168942Sdes VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 321168942Sdes if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 32285289Sdes lep = linux_emul_path; 32391334Sjulian else 32491334Sjulian lep = dlep; 32585289Sdes lep_len = strlen(lep); 326119068Sdes 32785289Sdes mtx_lock(&mountlist_mtx); 32885289Sdes error = 0; 32985289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 33085289Sdes /* determine device name */ 33185289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 332119068Sdes 33385289Sdes /* determine mount point */ 33485289Sdes mntto = mp->mnt_stat.f_mntonname; 33585289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 33685289Sdes mntto[lep_len] == '/') 33785289Sdes mntto += lep_len; 33885289Sdes 33985289Sdes /* determine fs type */ 34085289Sdes fstype = mp->mnt_stat.f_fstypename; 34185289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 34285289Sdes mntfrom = fstype = "proc"; 34385289Sdes else if (strcmp(fstype, "procfs") == 0) 34485289Sdes continue; 345119068Sdes 346158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 347158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 348158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 349158311Sambrisko } else { 350158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 351158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 352158311Sambrisko } 35385289Sdes#define ADD_OPTION(opt, name) \ 35485289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 35585289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35685289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 35785289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 35885289Sdes ADD_OPTION(MNT_UNION, "union"); 35985289Sdes ADD_OPTION(MNT_ASYNC, "async"); 36085289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 36185289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 36285289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 36385289Sdes#undef ADD_OPTION 36485289Sdes /* a real Linux mtab will also show NFS options */ 36585289Sdes sbuf_printf(sb, " 0 0\n"); 36685289Sdes } 36785289Sdes mtx_unlock(&mountlist_mtx); 36885289Sdes if (flep != NULL) 36985289Sdes free(flep, M_TEMP); 37085289Sdes return (error); 37185289Sdes} 37285289Sdes 37385289Sdes/* 37478113Sdes * Filler function for proc/stat 37578113Sdes */ 37678025Sdesstatic int 37778025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 37865633Sdes{ 379174070Speter struct pcpu *pcpu; 380174070Speter long cp_time[CPUSTATES]; 381174070Speter long *cp; 382123246Sdes int i; 383120339Sdes 384174070Speter read_cpu_time(cp_time); 385120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 386120339Sdes T2J(cp_time[CP_USER]), 387120339Sdes T2J(cp_time[CP_NICE]), 388120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 389120339Sdes T2J(cp_time[CP_IDLE])); 390174070Speter for (i = 0; i <= mp_maxid; ++i) { 391174070Speter if (CPU_ABSENT(i)) 392174070Speter continue; 393174070Speter pcpu = pcpu_find(i); 394174070Speter cp = pcpu->pc_cp_time; 395143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 396174070Speter T2J(cp[CP_USER]), 397174070Speter T2J(cp[CP_NICE]), 398174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 399174070Speter T2J(cp[CP_IDLE])); 400174070Speter } 40178025Sdes sbuf_printf(sb, 40269799Sdes "disk 0 0 0 0\n" 40369799Sdes "page %u %u\n" 40469799Sdes "swap %u %u\n" 40569799Sdes "intr %u\n" 40669799Sdes "ctxt %u\n" 40785657Sdillon "btime %lld\n", 408170170Sattilio cnt.v_vnodepgsin, 409170170Sattilio cnt.v_vnodepgsout, 410170170Sattilio cnt.v_swappgsin, 411170170Sattilio cnt.v_swappgsout, 412170170Sattilio cnt.v_intr, 413170170Sattilio cnt.v_swtch, 414113574Sjhb (long long)boottime.tv_sec); 41578025Sdes return (0); 41665633Sdes} 41765633Sdes 41878113Sdes/* 41978113Sdes * Filler function for proc/uptime 42078113Sdes */ 42178025Sdesstatic int 42278025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 42365633Sdes{ 424174070Speter long cp_time[CPUSTATES]; 42565633Sdes struct timeval tv; 42665633Sdes 42765633Sdes getmicrouptime(&tv); 428174070Speter read_cpu_time(cp_time); 42985657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 430113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 43169799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43278025Sdes return (0); 43365633Sdes} 43465633Sdes 43578113Sdes/* 436167159Sjkim * Get OS build date 437167159Sjkim */ 438167159Sjkimstatic void 439167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 440167159Sjkim{ 441167159Sjkim#if 0 442167159Sjkim char osbuild[256]; 443167159Sjkim char *cp1, *cp2; 444167159Sjkim 445167159Sjkim strncpy(osbuild, version, 256); 446167159Sjkim osbuild[255] = '\0'; 447167159Sjkim cp1 = strstr(osbuild, "\n"); 448167159Sjkim cp2 = strstr(osbuild, ":"); 449167159Sjkim if (cp1 && cp2) { 450167159Sjkim *cp1 = *cp2 = '\0'; 451167159Sjkim cp1 = strstr(osbuild, "#"); 452167159Sjkim } else 453167159Sjkim cp1 = NULL; 454167159Sjkim if (cp1) 455167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 456167159Sjkim else 457167159Sjkim#endif 458167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 459167159Sjkim} 460167159Sjkim 461167159Sjkim/* 462167159Sjkim * Get OS builder 463167159Sjkim */ 464167159Sjkimstatic void 465167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 466167159Sjkim{ 467168762Sdes#if 0 468167159Sjkim char builder[256]; 469167159Sjkim char *cp; 470167159Sjkim 471167159Sjkim cp = strstr(version, "\n "); 472167159Sjkim if (cp) { 473167159Sjkim strncpy(builder, cp + 5, 256); 474167159Sjkim builder[255] = '\0'; 475167159Sjkim cp = strstr(builder, ":"); 476167159Sjkim if (cp) 477167159Sjkim *cp = '\0'; 478167159Sjkim } 479167159Sjkim if (cp) 480167159Sjkim sbuf_cat(sb, builder); 481167159Sjkim else 482168762Sdes#endif 483167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 484167159Sjkim} 485167159Sjkim 486167159Sjkim/* 48778113Sdes * Filler function for proc/version 48878113Sdes */ 48978025Sdesstatic int 49078025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 49165633Sdes{ 49287275Srwatson char osname[LINUX_MAX_UTSNAME]; 49387275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 49487275Srwatson 495112206Sjhb linux_get_osname(td, osname); 496112206Sjhb linux_get_osrelease(td, osrelease); 497167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 498167159Sjkim linprocfs_osbuilder(td, sb); 499167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 500167159Sjkim linprocfs_osbuild(td, sb); 501167159Sjkim sbuf_cat(sb, "\n"); 50287275Srwatson 50378025Sdes return (0); 50465633Sdes} 50565633Sdes 50678113Sdes/* 50778113Sdes * Filler function for proc/loadavg 50878113Sdes */ 50978025Sdesstatic int 51078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 51176839Sjlemon{ 512168762Sdes 51378025Sdes sbuf_printf(sb, 51476839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 51576839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 51676839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 51776839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 51876839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 51976839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 52076839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 52176839Sjlemon 1, /* number of running tasks */ 52276839Sjlemon nprocs, /* number of tasks */ 52378116Sdes lastpid /* the last pid */ 52476839Sjlemon ); 52578025Sdes return (0); 52676839Sjlemon} 52776839Sjlemon 52878113Sdes/* 52978113Sdes * Filler function for proc/pid/stat 53078113Sdes */ 53178025Sdesstatic int 53278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 53367588Sdes{ 53469995Sdes struct kinfo_proc kp; 535166140Snetchild char state; 536166140Snetchild static int ratelimit = 0; 53767588Sdes 53894307Sjhb PROC_LOCK(p); 53969995Sdes fill_kinfo_proc(p, &kp); 54078025Sdes sbuf_printf(sb, "%d", p->p_pid); 54178025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 54267588Sdes PS_ADD("comm", "(%s)", p->p_comm); 543166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 544166140Snetchild state = 'R'; 545166140Snetchild 546166141Snetchild if (ratelimit == 0) { 547166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 548166162Snetchild kp.ki_stat, sizeof(linux_state)); 549166141Snetchild ++ratelimit; 550166141Snetchild } 551166140Snetchild } else 552166140Snetchild state = linux_state[kp.ki_stat - 1]; 553166140Snetchild PS_ADD("state", "%c", state); 55473923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 55567588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 55667588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 55791140Stanimura PROC_UNLOCK(p); 55867588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 559159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 56067588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 561159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 562159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 563159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 564159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 565159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 566159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 567159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 568159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 569159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 570159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 571159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 572159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 573159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 574159995Snetchild It should be the number of jiffies between system boot and process 575159995Snetchild start. */ 576159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 577159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 578159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 579159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 58069995Sdes PS_ADD("startcode", "%u", (unsigned)0); 58167588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 58267588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 583159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 584159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 585159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 586159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 587159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 588159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 58967588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 590159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 591159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 59269799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 593159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 594159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 595159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 59667588Sdes#undef PS_ADD 59778025Sdes sbuf_putc(sb, '\n'); 598119068Sdes 59978025Sdes return (0); 60067588Sdes} 60167588Sdes 60267588Sdes/* 603119911Sdes * Filler function for proc/pid/statm 604119911Sdes */ 605119911Sdesstatic int 606119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 607119911Sdes{ 608119911Sdes struct kinfo_proc kp; 609119911Sdes segsz_t lsize; 610120340Sdes 611119911Sdes PROC_LOCK(p); 612119911Sdes fill_kinfo_proc(p, &kp); 613119911Sdes PROC_UNLOCK(p); 614119911Sdes 615119911Sdes /* 616119911Sdes * See comments in linprocfs_doprocstatus() regarding the 617119911Sdes * computation of lsize. 618119911Sdes */ 619119911Sdes /* size resident share trs drs lrs dt */ 620119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 621119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 622119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 623119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 624119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 625119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 626119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 627119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 628119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 629119911Sdes 630119911Sdes return (0); 631119911Sdes} 632119911Sdes 633119911Sdes/* 63478113Sdes * Filler function for proc/pid/status 63578113Sdes */ 63678025Sdesstatic int 63778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 63867588Sdes{ 63969995Sdes struct kinfo_proc kp; 64067588Sdes char *state; 64169799Sdes segsz_t lsize; 64299072Sjulian struct thread *td2; 643114983Sjhb struct sigacts *ps; 64474135Sjlemon int i; 64567588Sdes 646113611Sjhb PROC_LOCK(p); 64799072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 64899072Sjulian 64999072Sjulian if (P_SHOULDSTOP(p)) { 65099072Sjulian state = "T (stopped)"; 65199072Sjulian } else { 652170307Sjeff PROC_SLOCK(p); 65399072Sjulian switch(p->p_state) { 65499072Sjulian case PRS_NEW: 65599072Sjulian state = "I (idle)"; 65699072Sjulian break; 65799072Sjulian case PRS_NORMAL: 65899072Sjulian if (p->p_flag & P_WEXIT) { 65999072Sjulian state = "X (exiting)"; 66099072Sjulian break; 66199072Sjulian } 66299072Sjulian switch(td2->td_state) { 663103216Sjulian case TDS_INHIBITED: 66499072Sjulian state = "S (sleeping)"; 66599072Sjulian break; 66699072Sjulian case TDS_RUNQ: 66799072Sjulian case TDS_RUNNING: 66899072Sjulian state = "R (running)"; 66999072Sjulian break; 67099072Sjulian default: 67199072Sjulian state = "? (unknown)"; 67299072Sjulian break; 67399072Sjulian } 67499072Sjulian break; 67599072Sjulian case PRS_ZOMBIE: 67699072Sjulian state = "Z (zombie)"; 67799072Sjulian break; 67899072Sjulian default: 67999072Sjulian state = "? (unknown)"; 68099072Sjulian break; 68199072Sjulian } 682170307Sjeff PROC_SUNLOCK(p); 68399072Sjulian } 68467588Sdes 68569995Sdes fill_kinfo_proc(p, &kp); 68678025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 68778031Sdes sbuf_printf(sb, "State:\t%s\n", state); 68867588Sdes 68967588Sdes /* 69067588Sdes * Credentials 69167588Sdes */ 69278025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 69378025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 69473923Sjhb p->p_pptr->p_pid : 0); 69578031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 69678031Sdes p->p_ucred->cr_uid, 69778031Sdes p->p_ucred->cr_svuid, 69878031Sdes /* FreeBSD doesn't have fsuid */ 69978031Sdes p->p_ucred->cr_uid); 70078031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 70178031Sdes p->p_ucred->cr_gid, 70278031Sdes p->p_ucred->cr_svgid, 70378031Sdes /* FreeBSD doesn't have fsgid */ 70478031Sdes p->p_ucred->cr_gid); 70578025Sdes sbuf_cat(sb, "Groups:\t"); 70667588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 70778031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 70871471Sjhb PROC_UNLOCK(p); 70978025Sdes sbuf_putc(sb, '\n'); 710119068Sdes 71167588Sdes /* 71267588Sdes * Memory 71369799Sdes * 71469799Sdes * While our approximation of VmLib may not be accurate (I 71569799Sdes * don't know of a simple way to verify it, and I'm not sure 71669799Sdes * it has much meaning anyway), I believe it's good enough. 71769799Sdes * 71869799Sdes * The same code that could (I think) accurately compute VmLib 71969799Sdes * could also compute VmLck, but I don't really care enough to 72069799Sdes * implement it. Submissions are welcome. 72167588Sdes */ 722113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 72378025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 724113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 725113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 726113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 727113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 72869995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 72969995Sdes kp.ki_ssize - kp.ki_tsize - 1; 730113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 73167588Sdes 73267588Sdes /* 73367588Sdes * Signal masks 73467588Sdes * 73567588Sdes * We support up to 128 signals, while Linux supports 32, 73667588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 73767588Sdes * just show the lower 32 bits of each mask. XXX hack. 73867588Sdes * 73967588Sdes * NB: on certain platforms (Sparc at least) Linux actually 74067588Sdes * supports 64 signals, but this code is a long way from 74167588Sdes * running on anything but i386, so ignore that for now. 74267588Sdes */ 74371471Sjhb PROC_LOCK(p); 744104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 74569799Sdes /* 74669799Sdes * I can't seem to find out where the signal mask is in 74769799Sdes * relation to struct proc, so SigBlk is left unimplemented. 74869799Sdes */ 74978025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 750114983Sjhb ps = p->p_sigacts; 751114983Sjhb mtx_lock(&ps->ps_mtx); 752114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 753114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 754114983Sjhb mtx_unlock(&ps->ps_mtx); 75571471Sjhb PROC_UNLOCK(p); 756119068Sdes 75767588Sdes /* 75867588Sdes * Linux also prints the capability masks, but we don't have 75967588Sdes * capabilities yet, and when we do get them they're likely to 76067588Sdes * be meaningless to Linux programs, so we lie. XXX 76167588Sdes */ 76278025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 76378025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 76478025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 765119068Sdes 76678025Sdes return (0); 76767588Sdes} 76874135Sjlemon 769119911Sdes 77078113Sdes/* 771119911Sdes * Filler function for proc/pid/cwd 772119911Sdes */ 773119911Sdesstatic int 774119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 775119911Sdes{ 776119911Sdes char *fullpath = "unknown"; 777119911Sdes char *freepath = NULL; 778119911Sdes 779119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 780119911Sdes sbuf_printf(sb, "%s", fullpath); 781119911Sdes if (freepath) 782119911Sdes free(freepath, M_TEMP); 783119911Sdes return (0); 784119911Sdes} 785119911Sdes 786119911Sdes/* 787119911Sdes * Filler function for proc/pid/root 788119911Sdes */ 789119911Sdesstatic int 790119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 791119911Sdes{ 792119911Sdes struct vnode *rvp; 793119911Sdes char *fullpath = "unknown"; 794119911Sdes char *freepath = NULL; 795119911Sdes 796119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 797119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 798119911Sdes sbuf_printf(sb, "%s", fullpath); 799119911Sdes if (freepath) 800119911Sdes free(freepath, M_TEMP); 801119911Sdes return (0); 802119911Sdes} 803119911Sdes 804119911Sdes/* 80578113Sdes * Filler function for proc/pid/cmdline 80678113Sdes */ 80778025Sdesstatic int 80878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 80978113Sdes{ 81078113Sdes struct ps_strings pstr; 811138281Scperciva char **ps_argvstr; 81278113Sdes int error, i; 81378113Sdes 81478113Sdes /* 81578113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 81678113Sdes * revert back to the old way which only implements full cmdline 81778113Sdes * for the currept process and just p->p_comm for all other 81878113Sdes * processes. 81978113Sdes * Note that if the argv is no longer available, we deliberately 82078113Sdes * don't fall back on p->p_comm or return an error: the authentic 82178113Sdes * Linux behaviour is to return zero-length in this case. 82278113Sdes */ 82378113Sdes 82494620Sjhb PROC_LOCK(p); 825127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 82694620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 82794620Sjhb PROC_UNLOCK(p); 82894620Sjhb } else if (p != td->td_proc) { 82994620Sjhb PROC_UNLOCK(p); 83094620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 83194620Sjhb } else { 83294620Sjhb PROC_UNLOCK(p); 833103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 834103767Sjake sizeof(pstr)); 83594620Sjhb if (error) 83694620Sjhb return (error); 837138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 838138281Scperciva return (E2BIG); 839138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 840138281Scperciva M_TEMP, M_WAITOK); 841138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 842138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 843138281Scperciva if (error) { 844138281Scperciva free(ps_argvstr, M_TEMP); 845138281Scperciva return (error); 846138281Scperciva } 84794620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 848138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 84994620Sjhb sbuf_printf(sb, "%c", '\0'); 85078113Sdes } 851138281Scperciva free(ps_argvstr, M_TEMP); 85278113Sdes } 85378113Sdes 85478113Sdes return (0); 85578113Sdes} 85678113Sdes 85778113Sdes/* 858116173Sobrien * Filler function for proc/pid/environ 859116173Sobrien */ 860116173Sobrienstatic int 861116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 862116173Sobrien{ 863168762Sdes 864116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 865116173Sobrien return (0); 866116173Sobrien} 867116173Sobrien 868116173Sobrien/* 869116173Sobrien * Filler function for proc/pid/maps 870116173Sobrien */ 871116173Sobrienstatic int 872116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 873116173Sobrien{ 874121265Scognet char mebuffer[512]; 875121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 876169156Salc vm_map_entry_t entry, tmp_entry; 877121265Scognet vm_object_t obj, tobj, lobj; 878169156Salc vm_offset_t saved_end; 879121265Scognet vm_ooffset_t off = 0; 880121265Scognet char *name = "", *freename = NULL; 881121265Scognet size_t len; 882121265Scognet ino_t ino; 883169156Salc unsigned int last_timestamp; 884121265Scognet int ref_count, shadow_count, flags; 885121265Scognet int error; 886137507Sphk struct vnode *vp; 887137507Sphk struct vattr vat; 888161094Skib int locked; 889168762Sdes 890121246Scognet PROC_LOCK(p); 891121246Scognet error = p_candebug(td, p); 892121246Scognet PROC_UNLOCK(p); 893121246Scognet if (error) 894121246Scognet return (error); 895168762Sdes 896121246Scognet if (uio->uio_rw != UIO_READ) 897121246Scognet return (EOPNOTSUPP); 898168762Sdes 899121246Scognet if (uio->uio_offset != 0) 900121246Scognet return (0); 901168762Sdes 902121246Scognet error = 0; 903169156Salc vm_map_lock_read(map); 904168762Sdes for (entry = map->header.next; 905121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 906121246Scognet entry = entry->next) { 907121265Scognet name = ""; 908121265Scognet freename = NULL; 909121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 910121246Scognet continue; 911169156Salc saved_end = entry->end; 912121246Scognet obj = entry->object.vm_object; 913169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 914169156Salc VM_OBJECT_LOCK(tobj); 915169156Salc if (lobj != obj) 916169156Salc VM_OBJECT_UNLOCK(lobj); 917121246Scognet lobj = tobj; 918169156Salc } 919121246Scognet ino = 0; 920121246Scognet if (lobj) { 921121246Scognet off = IDX_TO_OFF(lobj->size); 922161094Skib if (lobj->type == OBJT_VNODE) { 923161094Skib vp = lobj->handle; 924161094Skib if (vp) 925161094Skib vref(vp); 926121246Scognet } 927161094Skib else 928161094Skib vp = NULL; 929169156Salc if (lobj != obj) 930169156Salc VM_OBJECT_UNLOCK(lobj); 931121246Scognet flags = obj->flags; 932121246Scognet ref_count = obj->ref_count; 933121246Scognet shadow_count = obj->shadow_count; 934169156Salc VM_OBJECT_UNLOCK(obj); 935161094Skib if (vp) { 936161094Skib vn_fullpath(td, vp, &name, &freename); 937161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 938175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 939161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 940161094Skib ino = vat.va_fileid; 941161094Skib vput(vp); 942161094Skib VFS_UNLOCK_GIANT(locked); 943161094Skib } 944121246Scognet } else { 945121246Scognet flags = 0; 946121246Scognet ref_count = 0; 947121246Scognet shadow_count = 0; 948121246Scognet } 949168762Sdes 950121246Scognet /* 951168762Sdes * format: 952121246Scognet * start, end, access, offset, major, minor, inode, name. 953121246Scognet */ 954121246Scognet snprintf(mebuffer, sizeof mebuffer, 955121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 956121246Scognet (u_long)entry->start, (u_long)entry->end, 957121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 958121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 959121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 960121246Scognet "p", 961121265Scognet (u_long)off, 962121246Scognet 0, 963121246Scognet 0, 964121265Scognet (u_long)ino, 965121246Scognet *name ? " " : "", 966121246Scognet name 967121246Scognet ); 968121246Scognet if (freename) 969121246Scognet free(freename, M_TEMP); 970121246Scognet len = strlen(mebuffer); 971121246Scognet if (len > uio->uio_resid) 972121246Scognet len = uio->uio_resid; /* 973121246Scognet * XXX We should probably return 974121246Scognet * EFBIG here, as in procfs. 975121246Scognet */ 976169156Salc last_timestamp = map->timestamp; 977169156Salc vm_map_unlock_read(map); 978121246Scognet error = uiomove(mebuffer, len, uio); 979169156Salc vm_map_lock_read(map); 980121246Scognet if (error) 981121246Scognet break; 982169156Salc if (last_timestamp + 1 != map->timestamp) { 983169156Salc /* 984169156Salc * Look again for the entry because the map was 985169156Salc * modified while it was unlocked. Specifically, 986169156Salc * the entry may have been clipped, merged, or deleted. 987169156Salc */ 988169156Salc vm_map_lookup_entry(map, saved_end - 1, &tmp_entry); 989169156Salc entry = tmp_entry; 990169156Salc } 991121246Scognet } 992169156Salc vm_map_unlock_read(map); 993168762Sdes 994121246Scognet return (error); 995168762Sdes} 996168762Sdes 997116173Sobrien/* 99878113Sdes * Filler function for proc/net/dev 99978113Sdes */ 100078025Sdesstatic int 100178025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 100274135Sjlemon{ 100385129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 100474135Sjlemon struct ifnet *ifp; 100574135Sjlemon 100685129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 100783926Sdes "Inter-", " Receive", " Transmit", " face", 100885129Sdes "bytes packets errs drop fifo frame compressed", 100983926Sdes "bytes packets errs drop fifo frame compressed"); 101074135Sjlemon 1011108172Shsu IFNET_RLOCK(); 1012181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 101385129Sdes linux_ifname(ifp, ifname, sizeof ifname); 101485129Sdes sbuf_printf(sb, "%6.6s:", ifname); 101583926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 101683926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101783926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 101883926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101974135Sjlemon } 1020108172Shsu IFNET_RUNLOCK(); 1021119068Sdes 102278025Sdes return (0); 102374135Sjlemon} 102474135Sjlemon 1025158311Sambrisko/* 1026167159Sjkim * Filler function for proc/sys/kernel/osrelease 1027167159Sjkim */ 1028167159Sjkimstatic int 1029167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1030167159Sjkim{ 1031167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1032167159Sjkim 1033167159Sjkim linux_get_osrelease(td, osrelease); 1034167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1035167159Sjkim 1036167159Sjkim return (0); 1037167159Sjkim} 1038167159Sjkim 1039167159Sjkim/* 1040167159Sjkim * Filler function for proc/sys/kernel/ostype 1041167159Sjkim */ 1042167159Sjkimstatic int 1043167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1044167159Sjkim{ 1045167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1046167159Sjkim 1047167159Sjkim linux_get_osname(td, osname); 1048167159Sjkim sbuf_printf(sb, "%s\n", osname); 1049167159Sjkim 1050167159Sjkim return (0); 1051167159Sjkim} 1052167159Sjkim 1053167159Sjkim/* 1054167159Sjkim * Filler function for proc/sys/kernel/version 1055167159Sjkim */ 1056167159Sjkimstatic int 1057167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1058167159Sjkim{ 1059168762Sdes 1060167159Sjkim linprocfs_osbuild(td, sb); 1061167159Sjkim sbuf_cat(sb, "\n"); 1062167159Sjkim return (0); 1063167159Sjkim} 1064167159Sjkim 1065167159Sjkim/* 1066164692Sjkim * Filler function for proc/sys/kernel/msgmni 1067164692Sjkim */ 1068164692Sjkimstatic int 1069164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1070164692Sjkim{ 1071164692Sjkim 1072168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1073164692Sjkim return (0); 1074164692Sjkim} 1075164692Sjkim 1076164692Sjkim/* 1077163251Skeramida * Filler function for proc/sys/kernel/pid_max 1078163129Snetchild */ 1079163129Snetchildstatic int 1080163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1081163129Snetchild{ 1082163757Snetchild 1083163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1084163129Snetchild return (0); 1085163129Snetchild} 1086163129Snetchild 1087163129Snetchild/* 1088164692Sjkim * Filler function for proc/sys/kernel/sem 1089164692Sjkim */ 1090164692Sjkimstatic int 1091164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1092164692Sjkim{ 1093164692Sjkim 1094168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1095168067Sjkim seminfo.semopm, seminfo.semmni); 1096164692Sjkim return (0); 1097164692Sjkim} 1098164692Sjkim 1099164692Sjkim/* 1100158311Sambrisko * Filler function for proc/scsi/device_info 1101158311Sambrisko */ 1102158311Sambriskostatic int 1103158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1104158311Sambrisko{ 1105168762Sdes 1106158311Sambrisko return (0); 1107158311Sambrisko} 1108158311Sambrisko 1109158311Sambrisko/* 1110158311Sambrisko * Filler function for proc/scsi/scsi 1111158311Sambrisko */ 1112158311Sambriskostatic int 1113158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1114158311Sambrisko{ 1115168762Sdes 1116158311Sambrisko return (0); 1117158311Sambrisko} 1118158311Sambrisko 111985538Sphkextern struct cdevsw *cdevsw[]; 112085538Sphk 112178113Sdes/* 112278113Sdes * Filler function for proc/devices 112378113Sdes */ 112478025Sdesstatic int 112578025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112674135Sjlemon{ 1127158311Sambrisko char *char_devices; 112878025Sdes sbuf_printf(sb, "Character devices:\n"); 112974135Sjlemon 1130158311Sambrisko char_devices = linux_get_char_devices(); 1131158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1132158311Sambrisko linux_free_get_char_devices(char_devices); 113374135Sjlemon 113478025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1135119068Sdes 113678025Sdes return (0); 113774135Sjlemon} 113874135Sjlemon 113978113Sdes/* 114078113Sdes * Filler function for proc/cmdline 114178113Sdes */ 114278025Sdesstatic int 114378025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 114474135Sjlemon{ 1145168762Sdes 114678025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 114778025Sdes sbuf_printf(sb, " ro root=302\n"); 114878025Sdes return (0); 114978025Sdes} 115074135Sjlemon 115183926Sdes#if 0 115278025Sdes/* 115383926Sdes * Filler function for proc/modules 115483926Sdes */ 115583926Sdesstatic int 115683926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 115783926Sdes{ 115883926Sdes struct linker_file *lf; 1159119068Sdes 116083926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 116183926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 116283926Sdes (unsigned long)lf->size, lf->refs); 116383926Sdes } 116483926Sdes return (0); 116583926Sdes} 116683926Sdes#endif 116783926Sdes 116883926Sdes/* 116985129Sdes * Constructor 117078025Sdes */ 117185129Sdesstatic int 117285129Sdeslinprocfs_init(PFS_INIT_ARGS) 117385129Sdes{ 117485129Sdes struct pfs_node *root; 117585129Sdes struct pfs_node *dir; 117674135Sjlemon 117785129Sdes root = pi->pi_root; 117878025Sdes 1179119923Sdes /* /proc/... */ 1180119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1181167482Sdes NULL, NULL, NULL, PFS_RD); 1182119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1183167482Sdes NULL, NULL, NULL, PFS_RD); 1184119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1185167482Sdes NULL, NULL, NULL, PFS_RD); 1186119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1187167482Sdes NULL, NULL, NULL, PFS_RD); 1188119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1189167482Sdes NULL, NULL, NULL, PFS_RD); 119083926Sdes#if 0 1191119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1192167482Sdes NULL, NULL, NULL, PFS_RD); 119383926Sdes#endif 1194158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1195167482Sdes NULL, NULL, NULL, PFS_RD); 1196119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1197167482Sdes NULL, NULL, NULL, PFS_RD); 119887543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1199167482Sdes NULL, NULL, NULL, 0); 1200119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1201167482Sdes NULL, NULL, NULL, PFS_RD); 1202119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1203167482Sdes NULL, NULL, NULL, PFS_RD); 1204119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1205167482Sdes NULL, NULL, NULL, PFS_RD); 120678025Sdes 1207119923Sdes /* /proc/net/... */ 1208167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 120985129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1210167482Sdes NULL, NULL, NULL, PFS_RD); 121178025Sdes 1212119923Sdes /* /proc/<pid>/... */ 1213167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 121485129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1215167482Sdes NULL, NULL, NULL, PFS_RD); 1216119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1217167482Sdes NULL, NULL, NULL, 0); 1218116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1219167482Sdes NULL, NULL, NULL, PFS_RD); 122087543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1221167482Sdes NULL, &procfs_notsystem, NULL, 0); 1222116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1223167482Sdes NULL, NULL, NULL, PFS_RD); 122485129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1225167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1226119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1227167482Sdes NULL, NULL, NULL, 0); 122885129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1229167482Sdes NULL, NULL, NULL, PFS_RD); 1230119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1231167482Sdes NULL, NULL, NULL, PFS_RD); 123285129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1233167482Sdes NULL, NULL, NULL, PFS_RD); 123485129Sdes 1235158311Sambrisko /* /proc/scsi/... */ 1236167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1237158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1238167482Sdes NULL, NULL, NULL, PFS_RD); 1239158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1240167482Sdes NULL, NULL, NULL, PFS_RD); 1241163129Snetchild 1242163129Snetchild /* /proc/sys/... */ 1243167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1244163129Snetchild /* /proc/sys/kernel/... */ 1245167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1246167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1247167482Sdes NULL, NULL, NULL, PFS_RD); 1248167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1249167482Sdes NULL, NULL, NULL, PFS_RD); 1250167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1251167482Sdes NULL, NULL, NULL, PFS_RD); 1252164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1253167482Sdes NULL, NULL, NULL, PFS_RD); 1254163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1255167482Sdes NULL, NULL, NULL, PFS_RD); 1256164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1257167482Sdes NULL, NULL, NULL, PFS_RD); 1258163129Snetchild 125985129Sdes return (0); 126085129Sdes} 126185129Sdes 126285129Sdes/* 126385129Sdes * Destructor 126485129Sdes */ 126585129Sdesstatic int 126685129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 126785129Sdes{ 126885129Sdes 126985129Sdes /* nothing to do, pseudofs will GC */ 127085129Sdes return (0); 127185129Sdes} 127285129Sdes 127385129SdesPSEUDOFS(linprocfs, 1); 127478025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 127578025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1276168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1277168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1278