linprocfs.c revision 182141
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 42182141Sjulian#include "opt_compat.h" 43182141Sjulian 44116173Sobrien#include <sys/cdefs.h> 45116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 182141 2008-08-25 04:55:29Z julian $"); 46116173Sobrien 4759412Smsmith#include <sys/param.h> 4883926Sdes#include <sys/queue.h> 4976166Smarkm#include <sys/blist.h> 5074135Sjlemon#include <sys/conf.h> 5183926Sdes#include <sys/exec.h> 52177785Skib#include <sys/fcntl.h> 53119911Sdes#include <sys/filedesc.h> 5476166Smarkm#include <sys/jail.h> 5565633Sdes#include <sys/kernel.h> 5683926Sdes#include <sys/linker.h> 5776166Smarkm#include <sys/lock.h> 5874135Sjlemon#include <sys/malloc.h> 5978025Sdes#include <sys/mount.h> 60168067Sjkim#include <sys/msg.h> 6176827Salfred#include <sys/mutex.h> 6285289Sdes#include <sys/namei.h> 6365633Sdes#include <sys/proc.h> 6465633Sdes#include <sys/resourcevar.h> 6569995Sdes#include <sys/sbuf.h> 66168067Sjkim#include <sys/sem.h> 67123246Sdes#include <sys/smp.h> 6883926Sdes#include <sys/socket.h> 6976839Sjlemon#include <sys/sysctl.h> 7083926Sdes#include <sys/systm.h> 71159995Snetchild#include <sys/time.h> 7265633Sdes#include <sys/tty.h> 7383926Sdes#include <sys/user.h> 7483926Sdes#include <sys/vmmeter.h> 7559412Smsmith#include <sys/vnode.h> 76181803Sbz#include <sys/vimage.h> 7759412Smsmith 7883926Sdes#include <net/if.h> 7983926Sdes 8059412Smsmith#include <vm/vm.h> 8159412Smsmith#include <vm/pmap.h> 8267588Sdes#include <vm/vm_map.h> 8359412Smsmith#include <vm/vm_param.h> 8460860Sdes#include <vm/vm_object.h> 8559412Smsmith#include <vm/swap_pager.h> 8669799Sdes 8767589Sdes#include <machine/clock.h> 8878113Sdes 89133822Stjr#if defined(__i386__) || defined(__amd64__) 9067589Sdes#include <machine/cputypes.h> 9159412Smsmith#include <machine/md_var.h> 92133822Stjr#endif /* __i386__ || __amd64__ */ 9359412Smsmith 94140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 95140214Sobrien#include <machine/../linux32/linux.h> 96140214Sobrien#else 9787275Srwatson#include <machine/../linux/linux.h> 98133822Stjr#endif 9985129Sdes#include <compat/linux/linux_ioctl.h> 10069995Sdes#include <compat/linux/linux_mib.h> 10185289Sdes#include <compat/linux/linux_util.h> 10278025Sdes#include <fs/pseudofs/pseudofs.h> 10384248Sdes#include <fs/procfs/procfs.h> 10459412Smsmith 10567588Sdes/* 10667588Sdes * Various conversion macros 10767588Sdes */ 10876405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10967588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 11067588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 11169799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 11267588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11367588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11474135Sjlemon 115159995Snetchild/** 116159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 117159995Snetchild * 118159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 119159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 120172568Skevlo * uninterruptible disk sleep, a zombie process, process is being traced 121159995Snetchild * or stopped, or process is paging respectively. 122159995Snetchild * 123159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 124159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 125159995Snetchild * 126159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 127159995Snetchild * map our states to suitable linux states. 128159995Snetchild */ 129166140Snetchildstatic char linux_state[] = "RRSTZDD"; 130159995Snetchild 13178113Sdes/* 13278113Sdes * Filler function for proc/meminfo 13378113Sdes */ 13478025Sdesstatic int 13578025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13659412Smsmith{ 13759412Smsmith unsigned long memtotal; /* total memory in bytes */ 13859412Smsmith unsigned long memused; /* used memory in bytes */ 13959412Smsmith unsigned long memfree; /* free memory in bytes */ 14059412Smsmith unsigned long memshared; /* shared memory ??? */ 14159412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 142113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 143113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 144113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14560860Sdes vm_object_t object; 146117723Sphk int i, j; 14759412Smsmith 14859412Smsmith memtotal = physmem * PAGE_SIZE; 14959412Smsmith /* 15059412Smsmith * The correct thing here would be: 15159412Smsmith * 152170170Sattilio memfree = cnt.v_free_count * PAGE_SIZE; 15359412Smsmith memused = memtotal - memfree; 15459412Smsmith * 15559412Smsmith * but it might mislead linux binaries into thinking there 15659412Smsmith * is very little memory left, so we cheat and tell them that 15759412Smsmith * all memory that isn't wired down is free. 15859412Smsmith */ 159170170Sattilio memused = cnt.v_wire_count * PAGE_SIZE; 16059412Smsmith memfree = memtotal - memused; 161117723Sphk swap_pager_status(&i, &j); 162153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 163153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 164117723Sphk swapfree = swaptotal - swapused; 16560860Sdes memshared = 0; 166124082Salc mtx_lock(&vm_object_list_mtx); 16771471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16860860Sdes if (object->shadow_count > 1) 16960860Sdes memshared += object->resident_page_count; 170124082Salc mtx_unlock(&vm_object_list_mtx); 17160860Sdes memshared *= PAGE_SIZE; 17259412Smsmith /* 17359412Smsmith * We'd love to be able to write: 17459412Smsmith * 17559412Smsmith buffers = bufspace; 17659412Smsmith * 17759412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17859412Smsmith * like unstaticizing it just for linprocfs's sake. 17959412Smsmith */ 18059412Smsmith buffers = 0; 181170170Sattilio cached = cnt.v_cache_count * PAGE_SIZE; 18259412Smsmith 18378025Sdes sbuf_printf(sb, 18478031Sdes " total: used: free: shared: buffers: cached:\n" 18569799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18676839Sjlemon "Swap: %llu %llu %llu\n" 18769799Sdes "MemTotal: %9lu kB\n" 18869799Sdes "MemFree: %9lu kB\n" 18969799Sdes "MemShared:%9lu kB\n" 19069799Sdes "Buffers: %9lu kB\n" 19169799Sdes "Cached: %9lu kB\n" 19276839Sjlemon "SwapTotal:%9llu kB\n" 19376839Sjlemon "SwapFree: %9llu kB\n", 19469799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19569799Sdes swaptotal, swapused, swapfree, 19669799Sdes B2K(memtotal), B2K(memfree), 19769799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19869799Sdes B2K(swaptotal), B2K(swapfree)); 19959412Smsmith 20078025Sdes return (0); 20159412Smsmith} 20259412Smsmith 203133822Stjr#if defined(__i386__) || defined(__amd64__) 20478113Sdes/* 205133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20678113Sdes */ 20778113Sdesstatic int 20878113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 20978113Sdes{ 210159544Sdes int hw_model[2]; 211159544Sdes char model[128]; 212159544Sdes size_t size; 213123246Sdes int class, fqmhz, fqkhz; 214118421Sdes int i; 21559412Smsmith 21669799Sdes /* 21778031Sdes * We default the flags to include all non-conflicting flags, 21878031Sdes * and the Intel versions of conflicting flags. 21969799Sdes */ 22078031Sdes static char *flags[] = { 22178031Sdes "fpu", "vme", "de", "pse", "tsc", 22278031Sdes "msr", "pae", "mce", "cx8", "apic", 22378031Sdes "sep", "sep", "mtrr", "pge", "mca", 22478031Sdes "cmov", "pat", "pse36", "pn", "b19", 22578031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 22678031Sdes "xmm", "b26", "b27", "b28", "b29", 22767589Sdes "3dnowext", "3dnow" 22867589Sdes }; 22967589Sdes 23059412Smsmith switch (cpu_class) { 231133822Stjr#ifdef __i386__ 23259412Smsmith case CPUCLASS_286: 23367589Sdes class = 2; 23459412Smsmith break; 23559412Smsmith case CPUCLASS_386: 23667589Sdes class = 3; 23759412Smsmith break; 23859412Smsmith case CPUCLASS_486: 23967589Sdes class = 4; 24059412Smsmith break; 24159412Smsmith case CPUCLASS_586: 24267589Sdes class = 5; 24359412Smsmith break; 24459412Smsmith case CPUCLASS_686: 24567589Sdes class = 6; 24659412Smsmith break; 24759412Smsmith default: 24878031Sdes class = 0; 24959412Smsmith break; 250159170Sdes#else /* __amd64__ */ 251133822Stjr default: 252159170Sdes class = 15; 253133822Stjr break; 254133822Stjr#endif 25559412Smsmith } 25659412Smsmith 257159544Sdes hw_model[0] = CTL_HW; 258159544Sdes hw_model[1] = HW_MODEL; 259159544Sdes model[0] = '\0'; 260159544Sdes size = sizeof(model); 261159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 262159544Sdes strcpy(model, "unknown"); 263123246Sdes for (i = 0; i < mp_ncpus; ++i) { 264118421Sdes sbuf_printf(sb, 265118421Sdes "processor\t: %d\n" 266118421Sdes "vendor_id\t: %.20s\n" 267118421Sdes "cpu family\t: %d\n" 268118421Sdes "model\t\t: %d\n" 269159544Sdes "model name\t: %s\n" 270118421Sdes "stepping\t: %d\n", 271159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 272159544Sdes /* XXX per-cpu vendor / class / model / id? */ 273118421Sdes } 27459412Smsmith 27578031Sdes sbuf_cat(sb, 27678031Sdes "flags\t\t:"); 27767589Sdes 27878031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27967589Sdes flags[16] = "fcmov"; 28078031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 28167589Sdes flags[24] = "cxmmx"; 28278031Sdes } 283119068Sdes 28478031Sdes for (i = 0; i < 32; i++) 28567589Sdes if (cpu_feature & (1 << i)) 28678025Sdes sbuf_printf(sb, " %s", flags[i]); 28778025Sdes sbuf_cat(sb, "\n"); 28878031Sdes if (class >= 5) { 28969799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 29069799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 29178025Sdes sbuf_printf(sb, 29269799Sdes "cpu MHz\t\t: %d.%02d\n" 29369799Sdes "bogomips\t: %d.%02d\n", 29469799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29578031Sdes } 29669995Sdes 29778025Sdes return (0); 29859412Smsmith} 299133822Stjr#endif /* __i386__ || __amd64__ */ 30065633Sdes 30178113Sdes/* 30285289Sdes * Filler function for proc/mtab 30385289Sdes * 30485289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30585289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30685289Sdes */ 30785289Sdesstatic int 30885289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 30985289Sdes{ 31085289Sdes struct nameidata nd; 31185289Sdes struct mount *mp; 31291334Sjulian const char *lep; 31391334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 31485289Sdes size_t lep_len; 31585289Sdes int error; 31685289Sdes 31785289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 318168942Sdes NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 31985289Sdes flep = NULL; 320168942Sdes error = namei(&nd); 321168942Sdes VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 322168942Sdes if (error != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 32385289Sdes lep = linux_emul_path; 32491334Sjulian else 32591334Sjulian lep = dlep; 32685289Sdes lep_len = strlen(lep); 327119068Sdes 32885289Sdes mtx_lock(&mountlist_mtx); 32985289Sdes error = 0; 33085289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 33185289Sdes /* determine device name */ 33285289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 333119068Sdes 33485289Sdes /* determine mount point */ 33585289Sdes mntto = mp->mnt_stat.f_mntonname; 33685289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 33785289Sdes mntto[lep_len] == '/') 33885289Sdes mntto += lep_len; 33985289Sdes 34085289Sdes /* determine fs type */ 34185289Sdes fstype = mp->mnt_stat.f_fstypename; 34285289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 34385289Sdes mntfrom = fstype = "proc"; 34485289Sdes else if (strcmp(fstype, "procfs") == 0) 34585289Sdes continue; 346119068Sdes 347158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 348158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 349158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 350158311Sambrisko } else { 351158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 352158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 353158311Sambrisko } 35485289Sdes#define ADD_OPTION(opt, name) \ 35585289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 35685289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35785289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 35885289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 35985289Sdes ADD_OPTION(MNT_UNION, "union"); 36085289Sdes ADD_OPTION(MNT_ASYNC, "async"); 36185289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 36285289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 36385289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 36485289Sdes#undef ADD_OPTION 36585289Sdes /* a real Linux mtab will also show NFS options */ 36685289Sdes sbuf_printf(sb, " 0 0\n"); 36785289Sdes } 36885289Sdes mtx_unlock(&mountlist_mtx); 36985289Sdes if (flep != NULL) 37085289Sdes free(flep, M_TEMP); 37185289Sdes return (error); 37285289Sdes} 37385289Sdes 37485289Sdes/* 37578113Sdes * Filler function for proc/stat 37678113Sdes */ 37778025Sdesstatic int 37878025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 37965633Sdes{ 380174070Speter struct pcpu *pcpu; 381174070Speter long cp_time[CPUSTATES]; 382174070Speter long *cp; 383123246Sdes int i; 384120339Sdes 385174070Speter read_cpu_time(cp_time); 386120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 387120339Sdes T2J(cp_time[CP_USER]), 388120339Sdes T2J(cp_time[CP_NICE]), 389120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 390120339Sdes T2J(cp_time[CP_IDLE])); 391174070Speter for (i = 0; i <= mp_maxid; ++i) { 392174070Speter if (CPU_ABSENT(i)) 393174070Speter continue; 394174070Speter pcpu = pcpu_find(i); 395174070Speter cp = pcpu->pc_cp_time; 396143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 397174070Speter T2J(cp[CP_USER]), 398174070Speter T2J(cp[CP_NICE]), 399174070Speter T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 400174070Speter T2J(cp[CP_IDLE])); 401174070Speter } 40278025Sdes sbuf_printf(sb, 40369799Sdes "disk 0 0 0 0\n" 40469799Sdes "page %u %u\n" 40569799Sdes "swap %u %u\n" 40669799Sdes "intr %u\n" 40769799Sdes "ctxt %u\n" 40885657Sdillon "btime %lld\n", 409170170Sattilio cnt.v_vnodepgsin, 410170170Sattilio cnt.v_vnodepgsout, 411170170Sattilio cnt.v_swappgsin, 412170170Sattilio cnt.v_swappgsout, 413170170Sattilio cnt.v_intr, 414170170Sattilio cnt.v_swtch, 415113574Sjhb (long long)boottime.tv_sec); 41678025Sdes return (0); 41765633Sdes} 41865633Sdes 41978113Sdes/* 42078113Sdes * Filler function for proc/uptime 42178113Sdes */ 42278025Sdesstatic int 42378025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 42465633Sdes{ 425174070Speter long cp_time[CPUSTATES]; 42665633Sdes struct timeval tv; 42765633Sdes 42865633Sdes getmicrouptime(&tv); 429174070Speter read_cpu_time(cp_time); 43085657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 431113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 43269799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 43378025Sdes return (0); 43465633Sdes} 43565633Sdes 43678113Sdes/* 437167159Sjkim * Get OS build date 438167159Sjkim */ 439167159Sjkimstatic void 440167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 441167159Sjkim{ 442167159Sjkim#if 0 443167159Sjkim char osbuild[256]; 444167159Sjkim char *cp1, *cp2; 445167159Sjkim 446167159Sjkim strncpy(osbuild, version, 256); 447167159Sjkim osbuild[255] = '\0'; 448167159Sjkim cp1 = strstr(osbuild, "\n"); 449167159Sjkim cp2 = strstr(osbuild, ":"); 450167159Sjkim if (cp1 && cp2) { 451167159Sjkim *cp1 = *cp2 = '\0'; 452167159Sjkim cp1 = strstr(osbuild, "#"); 453167159Sjkim } else 454167159Sjkim cp1 = NULL; 455167159Sjkim if (cp1) 456167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 457167159Sjkim else 458167159Sjkim#endif 459167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 460167159Sjkim} 461167159Sjkim 462167159Sjkim/* 463167159Sjkim * Get OS builder 464167159Sjkim */ 465167159Sjkimstatic void 466167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 467167159Sjkim{ 468168762Sdes#if 0 469167159Sjkim char builder[256]; 470167159Sjkim char *cp; 471167159Sjkim 472167159Sjkim cp = strstr(version, "\n "); 473167159Sjkim if (cp) { 474167159Sjkim strncpy(builder, cp + 5, 256); 475167159Sjkim builder[255] = '\0'; 476167159Sjkim cp = strstr(builder, ":"); 477167159Sjkim if (cp) 478167159Sjkim *cp = '\0'; 479167159Sjkim } 480167159Sjkim if (cp) 481167159Sjkim sbuf_cat(sb, builder); 482167159Sjkim else 483168762Sdes#endif 484167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 485167159Sjkim} 486167159Sjkim 487167159Sjkim/* 48878113Sdes * Filler function for proc/version 48978113Sdes */ 49078025Sdesstatic int 49178025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 49265633Sdes{ 49387275Srwatson char osname[LINUX_MAX_UTSNAME]; 49487275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 49587275Srwatson 496112206Sjhb linux_get_osname(td, osname); 497112206Sjhb linux_get_osrelease(td, osrelease); 498167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 499167159Sjkim linprocfs_osbuilder(td, sb); 500167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 501167159Sjkim linprocfs_osbuild(td, sb); 502167159Sjkim sbuf_cat(sb, "\n"); 50387275Srwatson 50478025Sdes return (0); 50565633Sdes} 50665633Sdes 50778113Sdes/* 50878113Sdes * Filler function for proc/loadavg 50978113Sdes */ 51078025Sdesstatic int 51178025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 51276839Sjlemon{ 513168762Sdes 51478025Sdes sbuf_printf(sb, 51576839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 51676839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 51776839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 51876839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 51976839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 52076839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 52176839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 52276839Sjlemon 1, /* number of running tasks */ 52376839Sjlemon nprocs, /* number of tasks */ 52478116Sdes lastpid /* the last pid */ 52576839Sjlemon ); 52678025Sdes return (0); 52776839Sjlemon} 52876839Sjlemon 52978113Sdes/* 53078113Sdes * Filler function for proc/pid/stat 53178113Sdes */ 53278025Sdesstatic int 53378025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 53467588Sdes{ 53569995Sdes struct kinfo_proc kp; 536166140Snetchild char state; 537166140Snetchild static int ratelimit = 0; 53867588Sdes 53994307Sjhb PROC_LOCK(p); 54069995Sdes fill_kinfo_proc(p, &kp); 54178025Sdes sbuf_printf(sb, "%d", p->p_pid); 54278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 54367588Sdes PS_ADD("comm", "(%s)", p->p_comm); 544166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 545166140Snetchild state = 'R'; 546166140Snetchild 547166141Snetchild if (ratelimit == 0) { 548166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 549166162Snetchild kp.ki_stat, sizeof(linux_state)); 550166141Snetchild ++ratelimit; 551166141Snetchild } 552166140Snetchild } else 553166140Snetchild state = linux_state[kp.ki_stat - 1]; 554166140Snetchild PS_ADD("state", "%c", state); 55573923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 55667588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 55767588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 55891140Stanimura PROC_UNLOCK(p); 55967588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 560159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 56167588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 562159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 563159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 564159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 565159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 566159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 567159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 568159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 569159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 570159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 571159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 572159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 573159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 574159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 575159995Snetchild It should be the number of jiffies between system boot and process 576159995Snetchild start. */ 577159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 578159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 579159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 580159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 58169995Sdes PS_ADD("startcode", "%u", (unsigned)0); 58267588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 58367588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 584159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 585159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 586159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 587159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 588159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 589159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 59067588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 591159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 592159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 59369799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 594159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 595159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 596159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 59767588Sdes#undef PS_ADD 59878025Sdes sbuf_putc(sb, '\n'); 599119068Sdes 60078025Sdes return (0); 60167588Sdes} 60267588Sdes 60367588Sdes/* 604119911Sdes * Filler function for proc/pid/statm 605119911Sdes */ 606119911Sdesstatic int 607119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 608119911Sdes{ 609119911Sdes struct kinfo_proc kp; 610119911Sdes segsz_t lsize; 611120340Sdes 612119911Sdes PROC_LOCK(p); 613119911Sdes fill_kinfo_proc(p, &kp); 614119911Sdes PROC_UNLOCK(p); 615119911Sdes 616119911Sdes /* 617119911Sdes * See comments in linprocfs_doprocstatus() regarding the 618119911Sdes * computation of lsize. 619119911Sdes */ 620119911Sdes /* size resident share trs drs lrs dt */ 621119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 622119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 623119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 624119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 625119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 626119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 627119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 628119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 629119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 630119911Sdes 631119911Sdes return (0); 632119911Sdes} 633119911Sdes 634119911Sdes/* 63578113Sdes * Filler function for proc/pid/status 63678113Sdes */ 63778025Sdesstatic int 63878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 63967588Sdes{ 64069995Sdes struct kinfo_proc kp; 64167588Sdes char *state; 64269799Sdes segsz_t lsize; 64399072Sjulian struct thread *td2; 644114983Sjhb struct sigacts *ps; 64574135Sjlemon int i; 64667588Sdes 647113611Sjhb PROC_LOCK(p); 64899072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 64999072Sjulian 65099072Sjulian if (P_SHOULDSTOP(p)) { 65199072Sjulian state = "T (stopped)"; 65299072Sjulian } else { 653170307Sjeff PROC_SLOCK(p); 65499072Sjulian switch(p->p_state) { 65599072Sjulian case PRS_NEW: 65699072Sjulian state = "I (idle)"; 65799072Sjulian break; 65899072Sjulian case PRS_NORMAL: 65999072Sjulian if (p->p_flag & P_WEXIT) { 66099072Sjulian state = "X (exiting)"; 66199072Sjulian break; 66299072Sjulian } 66399072Sjulian switch(td2->td_state) { 664103216Sjulian case TDS_INHIBITED: 66599072Sjulian state = "S (sleeping)"; 66699072Sjulian break; 66799072Sjulian case TDS_RUNQ: 66899072Sjulian case TDS_RUNNING: 66999072Sjulian state = "R (running)"; 67099072Sjulian break; 67199072Sjulian default: 67299072Sjulian state = "? (unknown)"; 67399072Sjulian break; 67499072Sjulian } 67599072Sjulian break; 67699072Sjulian case PRS_ZOMBIE: 67799072Sjulian state = "Z (zombie)"; 67899072Sjulian break; 67999072Sjulian default: 68099072Sjulian state = "? (unknown)"; 68199072Sjulian break; 68299072Sjulian } 683170307Sjeff PROC_SUNLOCK(p); 68499072Sjulian } 68567588Sdes 68669995Sdes fill_kinfo_proc(p, &kp); 68778025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 68878031Sdes sbuf_printf(sb, "State:\t%s\n", state); 68967588Sdes 69067588Sdes /* 69167588Sdes * Credentials 69267588Sdes */ 69378025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 69478025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 69573923Sjhb p->p_pptr->p_pid : 0); 69678031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 69778031Sdes p->p_ucred->cr_uid, 69878031Sdes p->p_ucred->cr_svuid, 69978031Sdes /* FreeBSD doesn't have fsuid */ 70078031Sdes p->p_ucred->cr_uid); 70178031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 70278031Sdes p->p_ucred->cr_gid, 70378031Sdes p->p_ucred->cr_svgid, 70478031Sdes /* FreeBSD doesn't have fsgid */ 70578031Sdes p->p_ucred->cr_gid); 70678025Sdes sbuf_cat(sb, "Groups:\t"); 70767588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 70878031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 70971471Sjhb PROC_UNLOCK(p); 71078025Sdes sbuf_putc(sb, '\n'); 711119068Sdes 71267588Sdes /* 71367588Sdes * Memory 71469799Sdes * 71569799Sdes * While our approximation of VmLib may not be accurate (I 71669799Sdes * don't know of a simple way to verify it, and I'm not sure 71769799Sdes * it has much meaning anyway), I believe it's good enough. 71869799Sdes * 71969799Sdes * The same code that could (I think) accurately compute VmLib 72069799Sdes * could also compute VmLck, but I don't really care enough to 72169799Sdes * implement it. Submissions are welcome. 72267588Sdes */ 723113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 72478025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 725113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 726113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 727113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 728113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 72969995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 73069995Sdes kp.ki_ssize - kp.ki_tsize - 1; 731113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 73267588Sdes 73367588Sdes /* 73467588Sdes * Signal masks 73567588Sdes * 73667588Sdes * We support up to 128 signals, while Linux supports 32, 73767588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 73867588Sdes * just show the lower 32 bits of each mask. XXX hack. 73967588Sdes * 74067588Sdes * NB: on certain platforms (Sparc at least) Linux actually 74167588Sdes * supports 64 signals, but this code is a long way from 74267588Sdes * running on anything but i386, so ignore that for now. 74367588Sdes */ 74471471Sjhb PROC_LOCK(p); 745104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 74669799Sdes /* 74769799Sdes * I can't seem to find out where the signal mask is in 74869799Sdes * relation to struct proc, so SigBlk is left unimplemented. 74969799Sdes */ 75078025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 751114983Sjhb ps = p->p_sigacts; 752114983Sjhb mtx_lock(&ps->ps_mtx); 753114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 754114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 755114983Sjhb mtx_unlock(&ps->ps_mtx); 75671471Sjhb PROC_UNLOCK(p); 757119068Sdes 75867588Sdes /* 75967588Sdes * Linux also prints the capability masks, but we don't have 76067588Sdes * capabilities yet, and when we do get them they're likely to 76167588Sdes * be meaningless to Linux programs, so we lie. XXX 76267588Sdes */ 76378025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 76478025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 76578025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 766119068Sdes 76778025Sdes return (0); 76867588Sdes} 76974135Sjlemon 770119911Sdes 77178113Sdes/* 772119911Sdes * Filler function for proc/pid/cwd 773119911Sdes */ 774119911Sdesstatic int 775119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 776119911Sdes{ 777119911Sdes char *fullpath = "unknown"; 778119911Sdes char *freepath = NULL; 779119911Sdes 780119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 781119911Sdes sbuf_printf(sb, "%s", fullpath); 782119911Sdes if (freepath) 783119911Sdes free(freepath, M_TEMP); 784119911Sdes return (0); 785119911Sdes} 786119911Sdes 787119911Sdes/* 788119911Sdes * Filler function for proc/pid/root 789119911Sdes */ 790119911Sdesstatic int 791119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 792119911Sdes{ 793119911Sdes struct vnode *rvp; 794119911Sdes char *fullpath = "unknown"; 795119911Sdes char *freepath = NULL; 796119911Sdes 797119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 798119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 799119911Sdes sbuf_printf(sb, "%s", fullpath); 800119911Sdes if (freepath) 801119911Sdes free(freepath, M_TEMP); 802119911Sdes return (0); 803119911Sdes} 804119911Sdes 805119911Sdes/* 80678113Sdes * Filler function for proc/pid/cmdline 80778113Sdes */ 80878025Sdesstatic int 80978113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 81078113Sdes{ 81178113Sdes struct ps_strings pstr; 812138281Scperciva char **ps_argvstr; 81378113Sdes int error, i; 81478113Sdes 81578113Sdes /* 81678113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 81778113Sdes * revert back to the old way which only implements full cmdline 81878113Sdes * for the currept process and just p->p_comm for all other 81978113Sdes * processes. 82078113Sdes * Note that if the argv is no longer available, we deliberately 82178113Sdes * don't fall back on p->p_comm or return an error: the authentic 82278113Sdes * Linux behaviour is to return zero-length in this case. 82378113Sdes */ 82478113Sdes 82594620Sjhb PROC_LOCK(p); 826127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 82794620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 82894620Sjhb PROC_UNLOCK(p); 82994620Sjhb } else if (p != td->td_proc) { 83094620Sjhb PROC_UNLOCK(p); 83194620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 83294620Sjhb } else { 83394620Sjhb PROC_UNLOCK(p); 834103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 835103767Sjake sizeof(pstr)); 83694620Sjhb if (error) 83794620Sjhb return (error); 838138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 839138281Scperciva return (E2BIG); 840138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 841138281Scperciva M_TEMP, M_WAITOK); 842138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 843138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 844138281Scperciva if (error) { 845138281Scperciva free(ps_argvstr, M_TEMP); 846138281Scperciva return (error); 847138281Scperciva } 84894620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 849138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 85094620Sjhb sbuf_printf(sb, "%c", '\0'); 85178113Sdes } 852138281Scperciva free(ps_argvstr, M_TEMP); 85378113Sdes } 85478113Sdes 85578113Sdes return (0); 85678113Sdes} 85778113Sdes 85878113Sdes/* 859116173Sobrien * Filler function for proc/pid/environ 860116173Sobrien */ 861116173Sobrienstatic int 862116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 863116173Sobrien{ 864168762Sdes 865116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 866116173Sobrien return (0); 867116173Sobrien} 868116173Sobrien 869116173Sobrien/* 870116173Sobrien * Filler function for proc/pid/maps 871116173Sobrien */ 872116173Sobrienstatic int 873116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 874116173Sobrien{ 875121265Scognet char mebuffer[512]; 876121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 877169156Salc vm_map_entry_t entry, tmp_entry; 878121265Scognet vm_object_t obj, tobj, lobj; 879169156Salc vm_offset_t saved_end; 880121265Scognet vm_ooffset_t off = 0; 881121265Scognet char *name = "", *freename = NULL; 882121265Scognet size_t len; 883121265Scognet ino_t ino; 884169156Salc unsigned int last_timestamp; 885121265Scognet int ref_count, shadow_count, flags; 886121265Scognet int error; 887137507Sphk struct vnode *vp; 888137507Sphk struct vattr vat; 889161094Skib int locked; 890168762Sdes 891121246Scognet PROC_LOCK(p); 892121246Scognet error = p_candebug(td, p); 893121246Scognet PROC_UNLOCK(p); 894121246Scognet if (error) 895121246Scognet return (error); 896168762Sdes 897121246Scognet if (uio->uio_rw != UIO_READ) 898121246Scognet return (EOPNOTSUPP); 899168762Sdes 900121246Scognet if (uio->uio_offset != 0) 901121246Scognet return (0); 902168762Sdes 903121246Scognet error = 0; 904169156Salc vm_map_lock_read(map); 905168762Sdes for (entry = map->header.next; 906121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 907121246Scognet entry = entry->next) { 908121265Scognet name = ""; 909121265Scognet freename = NULL; 910121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 911121246Scognet continue; 912169156Salc saved_end = entry->end; 913121246Scognet obj = entry->object.vm_object; 914169156Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 915169156Salc VM_OBJECT_LOCK(tobj); 916169156Salc if (lobj != obj) 917169156Salc VM_OBJECT_UNLOCK(lobj); 918121246Scognet lobj = tobj; 919169156Salc } 920121246Scognet ino = 0; 921121246Scognet if (lobj) { 922121246Scognet off = IDX_TO_OFF(lobj->size); 923161094Skib if (lobj->type == OBJT_VNODE) { 924161094Skib vp = lobj->handle; 925161094Skib if (vp) 926161094Skib vref(vp); 927121246Scognet } 928161094Skib else 929161094Skib vp = NULL; 930169156Salc if (lobj != obj) 931169156Salc VM_OBJECT_UNLOCK(lobj); 932121246Scognet flags = obj->flags; 933121246Scognet ref_count = obj->ref_count; 934121246Scognet shadow_count = obj->shadow_count; 935169156Salc VM_OBJECT_UNLOCK(obj); 936161094Skib if (vp) { 937161094Skib vn_fullpath(td, vp, &name, &freename); 938161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 939175202Sattilio vn_lock(vp, LK_SHARED | LK_RETRY); 940161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 941161094Skib ino = vat.va_fileid; 942161094Skib vput(vp); 943161094Skib VFS_UNLOCK_GIANT(locked); 944161094Skib } 945121246Scognet } else { 946121246Scognet flags = 0; 947121246Scognet ref_count = 0; 948121246Scognet shadow_count = 0; 949121246Scognet } 950168762Sdes 951121246Scognet /* 952168762Sdes * format: 953121246Scognet * start, end, access, offset, major, minor, inode, name. 954121246Scognet */ 955121246Scognet snprintf(mebuffer, sizeof mebuffer, 956121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 957121246Scognet (u_long)entry->start, (u_long)entry->end, 958121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 959121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 960121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 961121246Scognet "p", 962121265Scognet (u_long)off, 963121246Scognet 0, 964121246Scognet 0, 965121265Scognet (u_long)ino, 966121246Scognet *name ? " " : "", 967121246Scognet name 968121246Scognet ); 969121246Scognet if (freename) 970121246Scognet free(freename, M_TEMP); 971121246Scognet len = strlen(mebuffer); 972121246Scognet if (len > uio->uio_resid) 973121246Scognet len = uio->uio_resid; /* 974121246Scognet * XXX We should probably return 975121246Scognet * EFBIG here, as in procfs. 976121246Scognet */ 977169156Salc last_timestamp = map->timestamp; 978169156Salc vm_map_unlock_read(map); 979121246Scognet error = uiomove(mebuffer, len, uio); 980169156Salc vm_map_lock_read(map); 981121246Scognet if (error) 982121246Scognet break; 983169156Salc if (last_timestamp + 1 != map->timestamp) { 984169156Salc /* 985169156Salc * Look again for the entry because the map was 986169156Salc * modified while it was unlocked. Specifically, 987169156Salc * the entry may have been clipped, merged, or deleted. 988169156Salc */ 989169156Salc vm_map_lookup_entry(map, saved_end - 1, &tmp_entry); 990169156Salc entry = tmp_entry; 991169156Salc } 992121246Scognet } 993169156Salc vm_map_unlock_read(map); 994168762Sdes 995121246Scognet return (error); 996168762Sdes} 997168762Sdes 998116173Sobrien/* 99978113Sdes * Filler function for proc/net/dev 100078113Sdes */ 100178025Sdesstatic int 100278025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 100374135Sjlemon{ 100485129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 100574135Sjlemon struct ifnet *ifp; 100674135Sjlemon 100785129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 100883926Sdes "Inter-", " Receive", " Transmit", " face", 100985129Sdes "bytes packets errs drop fifo frame compressed", 101083926Sdes "bytes packets errs drop fifo frame compressed"); 101174135Sjlemon 1012108172Shsu IFNET_RLOCK(); 1013181803Sbz TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 101485129Sdes linux_ifname(ifp, ifname, sizeof ifname); 101585129Sdes sbuf_printf(sb, "%6.6s:", ifname); 101683926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 101783926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 101883926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 101983926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 102074135Sjlemon } 1021108172Shsu IFNET_RUNLOCK(); 1022119068Sdes 102378025Sdes return (0); 102474135Sjlemon} 102574135Sjlemon 1026158311Sambrisko/* 1027167159Sjkim * Filler function for proc/sys/kernel/osrelease 1028167159Sjkim */ 1029167159Sjkimstatic int 1030167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 1031167159Sjkim{ 1032167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 1033167159Sjkim 1034167159Sjkim linux_get_osrelease(td, osrelease); 1035167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1036167159Sjkim 1037167159Sjkim return (0); 1038167159Sjkim} 1039167159Sjkim 1040167159Sjkim/* 1041167159Sjkim * Filler function for proc/sys/kernel/ostype 1042167159Sjkim */ 1043167159Sjkimstatic int 1044167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1045167159Sjkim{ 1046167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1047167159Sjkim 1048167159Sjkim linux_get_osname(td, osname); 1049167159Sjkim sbuf_printf(sb, "%s\n", osname); 1050167159Sjkim 1051167159Sjkim return (0); 1052167159Sjkim} 1053167159Sjkim 1054167159Sjkim/* 1055167159Sjkim * Filler function for proc/sys/kernel/version 1056167159Sjkim */ 1057167159Sjkimstatic int 1058167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1059167159Sjkim{ 1060168762Sdes 1061167159Sjkim linprocfs_osbuild(td, sb); 1062167159Sjkim sbuf_cat(sb, "\n"); 1063167159Sjkim return (0); 1064167159Sjkim} 1065167159Sjkim 1066167159Sjkim/* 1067164692Sjkim * Filler function for proc/sys/kernel/msgmni 1068164692Sjkim */ 1069164692Sjkimstatic int 1070164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1071164692Sjkim{ 1072164692Sjkim 1073168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1074164692Sjkim return (0); 1075164692Sjkim} 1076164692Sjkim 1077164692Sjkim/* 1078163251Skeramida * Filler function for proc/sys/kernel/pid_max 1079163129Snetchild */ 1080163129Snetchildstatic int 1081163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1082163129Snetchild{ 1083163757Snetchild 1084163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1085163129Snetchild return (0); 1086163129Snetchild} 1087163129Snetchild 1088163129Snetchild/* 1089164692Sjkim * Filler function for proc/sys/kernel/sem 1090164692Sjkim */ 1091164692Sjkimstatic int 1092164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1093164692Sjkim{ 1094164692Sjkim 1095168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1096168067Sjkim seminfo.semopm, seminfo.semmni); 1097164692Sjkim return (0); 1098164692Sjkim} 1099164692Sjkim 1100164692Sjkim/* 1101158311Sambrisko * Filler function for proc/scsi/device_info 1102158311Sambrisko */ 1103158311Sambriskostatic int 1104158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1105158311Sambrisko{ 1106168762Sdes 1107158311Sambrisko return (0); 1108158311Sambrisko} 1109158311Sambrisko 1110158311Sambrisko/* 1111158311Sambrisko * Filler function for proc/scsi/scsi 1112158311Sambrisko */ 1113158311Sambriskostatic int 1114158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1115158311Sambrisko{ 1116168762Sdes 1117158311Sambrisko return (0); 1118158311Sambrisko} 1119158311Sambrisko 112085538Sphkextern struct cdevsw *cdevsw[]; 112185538Sphk 112278113Sdes/* 112378113Sdes * Filler function for proc/devices 112478113Sdes */ 112578025Sdesstatic int 112678025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112774135Sjlemon{ 1128158311Sambrisko char *char_devices; 112978025Sdes sbuf_printf(sb, "Character devices:\n"); 113074135Sjlemon 1131158311Sambrisko char_devices = linux_get_char_devices(); 1132158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1133158311Sambrisko linux_free_get_char_devices(char_devices); 113474135Sjlemon 113578025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1136119068Sdes 113778025Sdes return (0); 113874135Sjlemon} 113974135Sjlemon 114078113Sdes/* 114178113Sdes * Filler function for proc/cmdline 114278113Sdes */ 114378025Sdesstatic int 114478025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 114574135Sjlemon{ 1146168762Sdes 114778025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 114878025Sdes sbuf_printf(sb, " ro root=302\n"); 114978025Sdes return (0); 115078025Sdes} 115174135Sjlemon 115283926Sdes#if 0 115378025Sdes/* 115483926Sdes * Filler function for proc/modules 115583926Sdes */ 115683926Sdesstatic int 115783926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 115883926Sdes{ 115983926Sdes struct linker_file *lf; 1160119068Sdes 116183926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 116283926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 116383926Sdes (unsigned long)lf->size, lf->refs); 116483926Sdes } 116583926Sdes return (0); 116683926Sdes} 116783926Sdes#endif 116883926Sdes 116983926Sdes/* 117085129Sdes * Constructor 117178025Sdes */ 117285129Sdesstatic int 117385129Sdeslinprocfs_init(PFS_INIT_ARGS) 117485129Sdes{ 117585129Sdes struct pfs_node *root; 117685129Sdes struct pfs_node *dir; 117774135Sjlemon 117885129Sdes root = pi->pi_root; 117978025Sdes 1180119923Sdes /* /proc/... */ 1181119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1182167482Sdes NULL, NULL, NULL, PFS_RD); 1183119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1184167482Sdes NULL, NULL, NULL, PFS_RD); 1185119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1186167482Sdes NULL, NULL, NULL, PFS_RD); 1187119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1188167482Sdes NULL, NULL, NULL, PFS_RD); 1189119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1190167482Sdes NULL, NULL, NULL, PFS_RD); 119183926Sdes#if 0 1192119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1193167482Sdes NULL, NULL, NULL, PFS_RD); 119483926Sdes#endif 1195158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1196167482Sdes NULL, NULL, NULL, PFS_RD); 1197119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1198167482Sdes NULL, NULL, NULL, PFS_RD); 119987543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1200167482Sdes NULL, NULL, NULL, 0); 1201119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1202167482Sdes NULL, NULL, NULL, PFS_RD); 1203119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1204167482Sdes NULL, NULL, NULL, PFS_RD); 1205119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1206167482Sdes NULL, NULL, NULL, PFS_RD); 120778025Sdes 1208119923Sdes /* /proc/net/... */ 1209167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 121085129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1211167482Sdes NULL, NULL, NULL, PFS_RD); 121278025Sdes 1213119923Sdes /* /proc/<pid>/... */ 1214167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 121585129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1216167482Sdes NULL, NULL, NULL, PFS_RD); 1217119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1218167482Sdes NULL, NULL, NULL, 0); 1219116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1220167482Sdes NULL, NULL, NULL, PFS_RD); 122187543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1222167482Sdes NULL, &procfs_notsystem, NULL, 0); 1223116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1224167482Sdes NULL, NULL, NULL, PFS_RD); 122585129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1226167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1227119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1228167482Sdes NULL, NULL, NULL, 0); 122985129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1230167482Sdes NULL, NULL, NULL, PFS_RD); 1231119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1232167482Sdes NULL, NULL, NULL, PFS_RD); 123385129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1234167482Sdes NULL, NULL, NULL, PFS_RD); 123585129Sdes 1236158311Sambrisko /* /proc/scsi/... */ 1237167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1238158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1239167482Sdes NULL, NULL, NULL, PFS_RD); 1240158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1241167482Sdes NULL, NULL, NULL, PFS_RD); 1242163129Snetchild 1243163129Snetchild /* /proc/sys/... */ 1244167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1245163129Snetchild /* /proc/sys/kernel/... */ 1246167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1247167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1248167482Sdes NULL, NULL, NULL, PFS_RD); 1249167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1250167482Sdes NULL, NULL, NULL, PFS_RD); 1251167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1252167482Sdes NULL, NULL, NULL, PFS_RD); 1253164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1254167482Sdes NULL, NULL, NULL, PFS_RD); 1255163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1256167482Sdes NULL, NULL, NULL, PFS_RD); 1257164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1258167482Sdes NULL, NULL, NULL, PFS_RD); 1259163129Snetchild 126085129Sdes return (0); 126185129Sdes} 126285129Sdes 126385129Sdes/* 126485129Sdes * Destructor 126585129Sdes */ 126685129Sdesstatic int 126785129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 126885129Sdes{ 126985129Sdes 127085129Sdes /* nothing to do, pseudofs will GC */ 127185129Sdes return (0); 127285129Sdes} 127385129Sdes 127485129SdesPSEUDOFS(linprocfs, 1); 127578025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 127678025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1277168440SjkimMODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1278168440SjkimMODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1279