linprocfs.c revision 167159
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 167159 2007-03-02 01:10:26Z jkim $"); 44116173Sobrien 4559412Smsmith#include <sys/param.h> 4683926Sdes#include <sys/queue.h> 4776166Smarkm#include <sys/blist.h> 4874135Sjlemon#include <sys/conf.h> 4983926Sdes#include <sys/exec.h> 50119911Sdes#include <sys/filedesc.h> 5176166Smarkm#include <sys/jail.h> 5265633Sdes#include <sys/kernel.h> 5383926Sdes#include <sys/linker.h> 5476166Smarkm#include <sys/lock.h> 5574135Sjlemon#include <sys/malloc.h> 5678025Sdes#include <sys/mount.h> 5776827Salfred#include <sys/mutex.h> 5885289Sdes#include <sys/namei.h> 5965633Sdes#include <sys/proc.h> 6065633Sdes#include <sys/resourcevar.h> 6169995Sdes#include <sys/sbuf.h> 62123246Sdes#include <sys/smp.h> 6383926Sdes#include <sys/socket.h> 6476839Sjlemon#include <sys/sysctl.h> 6583926Sdes#include <sys/systm.h> 66159995Snetchild#include <sys/time.h> 6765633Sdes#include <sys/tty.h> 6883926Sdes#include <sys/user.h> 6983926Sdes#include <sys/vmmeter.h> 7059412Smsmith#include <sys/vnode.h> 7159412Smsmith 7283926Sdes#include <net/if.h> 7383926Sdes 7459412Smsmith#include <vm/vm.h> 7559412Smsmith#include <vm/pmap.h> 7667588Sdes#include <vm/vm_map.h> 7759412Smsmith#include <vm/vm_param.h> 7860860Sdes#include <vm/vm_object.h> 7959412Smsmith#include <vm/swap_pager.h> 8069799Sdes 8167589Sdes#include <machine/clock.h> 8278113Sdes 83133822Stjr#if defined(__i386__) || defined(__amd64__) 8467589Sdes#include <machine/cputypes.h> 8559412Smsmith#include <machine/md_var.h> 86133822Stjr#endif /* __i386__ || __amd64__ */ 8759412Smsmith 88133822Stjr#include "opt_compat.h" 89140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 90140214Sobrien#include <machine/../linux32/linux.h> 91140214Sobrien#else 9287275Srwatson#include <machine/../linux/linux.h> 93133822Stjr#endif 9485129Sdes#include <compat/linux/linux_ioctl.h> 9569995Sdes#include <compat/linux/linux_mib.h> 9685289Sdes#include <compat/linux/linux_util.h> 9778025Sdes#include <fs/pseudofs/pseudofs.h> 9884248Sdes#include <fs/procfs/procfs.h> 9959412Smsmith 10067588Sdes/* 10167588Sdes * Various conversion macros 10267588Sdes */ 10376405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10467588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10567588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10669799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10767588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10867588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10974135Sjlemon 110159995Snetchild/** 111159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 112159995Snetchild * 113159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 114159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 115159995Snetchild * uninteruptible disk sleep, a zombie process, process is being traced 116159995Snetchild * or stopped, or process is paging respectively. 117159995Snetchild * 118159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 119159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 120159995Snetchild * 121159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 122159995Snetchild * map our states to suitable linux states. 123159995Snetchild */ 124166140Snetchildstatic char linux_state[] = "RRSTZDD"; 125159995Snetchild 12678113Sdes/* 12778113Sdes * Filler function for proc/meminfo 12878113Sdes */ 12978025Sdesstatic int 13078025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13159412Smsmith{ 13259412Smsmith unsigned long memtotal; /* total memory in bytes */ 13359412Smsmith unsigned long memused; /* used memory in bytes */ 13459412Smsmith unsigned long memfree; /* free memory in bytes */ 13559412Smsmith unsigned long memshared; /* shared memory ??? */ 13659412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 137113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 138113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 139113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14060860Sdes vm_object_t object; 141117723Sphk int i, j; 14259412Smsmith 14359412Smsmith memtotal = physmem * PAGE_SIZE; 14459412Smsmith /* 14559412Smsmith * The correct thing here would be: 14659412Smsmith * 14759412Smsmith memfree = cnt.v_free_count * PAGE_SIZE; 14859412Smsmith memused = memtotal - memfree; 14959412Smsmith * 15059412Smsmith * but it might mislead linux binaries into thinking there 15159412Smsmith * is very little memory left, so we cheat and tell them that 15259412Smsmith * all memory that isn't wired down is free. 15359412Smsmith */ 15459412Smsmith memused = cnt.v_wire_count * PAGE_SIZE; 15559412Smsmith memfree = memtotal - memused; 156117723Sphk swap_pager_status(&i, &j); 157153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 158153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 159117723Sphk swapfree = swaptotal - swapused; 16060860Sdes memshared = 0; 161124082Salc mtx_lock(&vm_object_list_mtx); 16271471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16360860Sdes if (object->shadow_count > 1) 16460860Sdes memshared += object->resident_page_count; 165124082Salc mtx_unlock(&vm_object_list_mtx); 16660860Sdes memshared *= PAGE_SIZE; 16759412Smsmith /* 16859412Smsmith * We'd love to be able to write: 16959412Smsmith * 17059412Smsmith buffers = bufspace; 17159412Smsmith * 17259412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17359412Smsmith * like unstaticizing it just for linprocfs's sake. 17459412Smsmith */ 17559412Smsmith buffers = 0; 17659412Smsmith cached = cnt.v_cache_count * PAGE_SIZE; 17759412Smsmith 17878025Sdes sbuf_printf(sb, 17978031Sdes " total: used: free: shared: buffers: cached:\n" 18069799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18176839Sjlemon "Swap: %llu %llu %llu\n" 18269799Sdes "MemTotal: %9lu kB\n" 18369799Sdes "MemFree: %9lu kB\n" 18469799Sdes "MemShared:%9lu kB\n" 18569799Sdes "Buffers: %9lu kB\n" 18669799Sdes "Cached: %9lu kB\n" 18776839Sjlemon "SwapTotal:%9llu kB\n" 18876839Sjlemon "SwapFree: %9llu kB\n", 18969799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19069799Sdes swaptotal, swapused, swapfree, 19169799Sdes B2K(memtotal), B2K(memfree), 19269799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19369799Sdes B2K(swaptotal), B2K(swapfree)); 19459412Smsmith 19578025Sdes return (0); 19659412Smsmith} 19759412Smsmith 198133822Stjr#if defined(__i386__) || defined(__amd64__) 19978113Sdes/* 200133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20178113Sdes */ 20278113Sdesstatic int 20378113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 20478113Sdes{ 205159544Sdes int hw_model[2]; 206159544Sdes char model[128]; 207159544Sdes size_t size; 208123246Sdes int class, fqmhz, fqkhz; 209118421Sdes int i; 21059412Smsmith 21169799Sdes /* 21278031Sdes * We default the flags to include all non-conflicting flags, 21378031Sdes * and the Intel versions of conflicting flags. 21469799Sdes */ 21578031Sdes static char *flags[] = { 21678031Sdes "fpu", "vme", "de", "pse", "tsc", 21778031Sdes "msr", "pae", "mce", "cx8", "apic", 21878031Sdes "sep", "sep", "mtrr", "pge", "mca", 21978031Sdes "cmov", "pat", "pse36", "pn", "b19", 22078031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 22178031Sdes "xmm", "b26", "b27", "b28", "b29", 22267589Sdes "3dnowext", "3dnow" 22367589Sdes }; 22467589Sdes 22559412Smsmith switch (cpu_class) { 226133822Stjr#ifdef __i386__ 22759412Smsmith case CPUCLASS_286: 22867589Sdes class = 2; 22959412Smsmith break; 23059412Smsmith case CPUCLASS_386: 23167589Sdes class = 3; 23259412Smsmith break; 23359412Smsmith case CPUCLASS_486: 23467589Sdes class = 4; 23559412Smsmith break; 23659412Smsmith case CPUCLASS_586: 23767589Sdes class = 5; 23859412Smsmith break; 23959412Smsmith case CPUCLASS_686: 24067589Sdes class = 6; 24159412Smsmith break; 24259412Smsmith default: 24378031Sdes class = 0; 24459412Smsmith break; 245159170Sdes#else /* __amd64__ */ 246133822Stjr default: 247159170Sdes class = 15; 248133822Stjr break; 249133822Stjr#endif 25059412Smsmith } 25159412Smsmith 252159544Sdes hw_model[0] = CTL_HW; 253159544Sdes hw_model[1] = HW_MODEL; 254159544Sdes model[0] = '\0'; 255159544Sdes size = sizeof(model); 256159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 257159544Sdes strcpy(model, "unknown"); 258123246Sdes for (i = 0; i < mp_ncpus; ++i) { 259118421Sdes sbuf_printf(sb, 260118421Sdes "processor\t: %d\n" 261118421Sdes "vendor_id\t: %.20s\n" 262118421Sdes "cpu family\t: %d\n" 263118421Sdes "model\t\t: %d\n" 264159544Sdes "model name\t: %s\n" 265118421Sdes "stepping\t: %d\n", 266159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 267159544Sdes /* XXX per-cpu vendor / class / model / id? */ 268118421Sdes } 26959412Smsmith 27078031Sdes sbuf_cat(sb, 27178031Sdes "flags\t\t:"); 27267589Sdes 27378031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27467589Sdes flags[16] = "fcmov"; 27578031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 27667589Sdes flags[24] = "cxmmx"; 27778031Sdes } 278119068Sdes 27978031Sdes for (i = 0; i < 32; i++) 28067589Sdes if (cpu_feature & (1 << i)) 28178025Sdes sbuf_printf(sb, " %s", flags[i]); 28278025Sdes sbuf_cat(sb, "\n"); 28378031Sdes if (class >= 5) { 28469799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 28569799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 28678025Sdes sbuf_printf(sb, 28769799Sdes "cpu MHz\t\t: %d.%02d\n" 28869799Sdes "bogomips\t: %d.%02d\n", 28969799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29078031Sdes } 29169995Sdes 29278025Sdes return (0); 29359412Smsmith} 294133822Stjr#endif /* __i386__ || __amd64__ */ 29565633Sdes 29678113Sdes/* 29785289Sdes * Filler function for proc/mtab 29885289Sdes * 29985289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30085289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30185289Sdes */ 30285289Sdesstatic int 30385289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 30485289Sdes{ 30585289Sdes struct nameidata nd; 30685289Sdes struct mount *mp; 30791334Sjulian const char *lep; 30891334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 30985289Sdes size_t lep_len; 31085289Sdes int error; 31185289Sdes 31285289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 31385289Sdes NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 31485289Sdes flep = NULL; 315124407Srwatson if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 31685289Sdes lep = linux_emul_path; 31791334Sjulian else 31891334Sjulian lep = dlep; 31985289Sdes lep_len = strlen(lep); 320119068Sdes 32185289Sdes mtx_lock(&mountlist_mtx); 32285289Sdes error = 0; 32385289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 32485289Sdes /* determine device name */ 32585289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 326119068Sdes 32785289Sdes /* determine mount point */ 32885289Sdes mntto = mp->mnt_stat.f_mntonname; 32985289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 33085289Sdes mntto[lep_len] == '/') 33185289Sdes mntto += lep_len; 33285289Sdes 33385289Sdes /* determine fs type */ 33485289Sdes fstype = mp->mnt_stat.f_fstypename; 33585289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 33685289Sdes mntfrom = fstype = "proc"; 33785289Sdes else if (strcmp(fstype, "procfs") == 0) 33885289Sdes continue; 339119068Sdes 340158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 341158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 342158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 343158311Sambrisko } else { 344158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 345158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 346158311Sambrisko } 34785289Sdes#define ADD_OPTION(opt, name) \ 34885289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 34985289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35085289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 35185289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 35285289Sdes ADD_OPTION(MNT_UNION, "union"); 35385289Sdes ADD_OPTION(MNT_ASYNC, "async"); 35485289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 35585289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 35685289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 35785289Sdes#undef ADD_OPTION 35885289Sdes /* a real Linux mtab will also show NFS options */ 35985289Sdes sbuf_printf(sb, " 0 0\n"); 36085289Sdes } 36185289Sdes mtx_unlock(&mountlist_mtx); 36285289Sdes if (flep != NULL) 36385289Sdes free(flep, M_TEMP); 36485289Sdes return (error); 36585289Sdes} 36685289Sdes 36785289Sdes/* 36878113Sdes * Filler function for proc/stat 36978113Sdes */ 37078025Sdesstatic int 37178025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 37265633Sdes{ 373123246Sdes int i; 374120339Sdes 375120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 376120339Sdes T2J(cp_time[CP_USER]), 377120339Sdes T2J(cp_time[CP_NICE]), 378120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 379120339Sdes T2J(cp_time[CP_IDLE])); 380143194Ssobomax for (i = 0; i < mp_ncpus; ++i) 381143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 382143194Ssobomax T2J(cp_time[CP_USER]) / mp_ncpus, 383143194Ssobomax T2J(cp_time[CP_NICE]) / mp_ncpus, 384143194Ssobomax T2J(cp_time[CP_SYS]) / mp_ncpus, 385143194Ssobomax T2J(cp_time[CP_IDLE]) / mp_ncpus); 38678025Sdes sbuf_printf(sb, 38769799Sdes "disk 0 0 0 0\n" 38869799Sdes "page %u %u\n" 38969799Sdes "swap %u %u\n" 39069799Sdes "intr %u\n" 39169799Sdes "ctxt %u\n" 39285657Sdillon "btime %lld\n", 39369799Sdes cnt.v_vnodepgsin, 39469799Sdes cnt.v_vnodepgsout, 39569799Sdes cnt.v_swappgsin, 39669799Sdes cnt.v_swappgsout, 39769799Sdes cnt.v_intr, 39869799Sdes cnt.v_swtch, 399113574Sjhb (long long)boottime.tv_sec); 40078025Sdes return (0); 40165633Sdes} 40265633Sdes 40378113Sdes/* 40478113Sdes * Filler function for proc/uptime 40578113Sdes */ 40678025Sdesstatic int 40778025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 40865633Sdes{ 40965633Sdes struct timeval tv; 41065633Sdes 41165633Sdes getmicrouptime(&tv); 41285657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 413113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 41469799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 41578025Sdes return (0); 41665633Sdes} 41765633Sdes 41878113Sdes/* 419167159Sjkim * Get OS build date 420167159Sjkim */ 421167159Sjkimstatic void 422167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 423167159Sjkim{ 424167159Sjkim#if 0 425167159Sjkim char osbuild[256]; 426167159Sjkim char *cp1, *cp2; 427167159Sjkim 428167159Sjkim strncpy(osbuild, version, 256); 429167159Sjkim osbuild[255] = '\0'; 430167159Sjkim cp1 = strstr(osbuild, "\n"); 431167159Sjkim cp2 = strstr(osbuild, ":"); 432167159Sjkim if (cp1 && cp2) { 433167159Sjkim *cp1 = *cp2 = '\0'; 434167159Sjkim cp1 = strstr(osbuild, "#"); 435167159Sjkim } else 436167159Sjkim cp1 = NULL; 437167159Sjkim if (cp1) 438167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 439167159Sjkim else 440167159Sjkim#endif 441167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 442167159Sjkim} 443167159Sjkim 444167159Sjkim/* 445167159Sjkim * Get OS builder 446167159Sjkim */ 447167159Sjkimstatic void 448167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 449167159Sjkim{ 450167159Sjkim char builder[256]; 451167159Sjkim char *cp; 452167159Sjkim 453167159Sjkim cp = strstr(version, "\n "); 454167159Sjkim if (cp) { 455167159Sjkim strncpy(builder, cp + 5, 256); 456167159Sjkim builder[255] = '\0'; 457167159Sjkim cp = strstr(builder, ":"); 458167159Sjkim if (cp) 459167159Sjkim *cp = '\0'; 460167159Sjkim } 461167159Sjkim if (cp) 462167159Sjkim sbuf_cat(sb, builder); 463167159Sjkim else 464167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 465167159Sjkim} 466167159Sjkim 467167159Sjkim/* 46878113Sdes * Filler function for proc/version 46978113Sdes */ 47078025Sdesstatic int 47178025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 47265633Sdes{ 47387275Srwatson char osname[LINUX_MAX_UTSNAME]; 47487275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 47587275Srwatson 476112206Sjhb linux_get_osname(td, osname); 477112206Sjhb linux_get_osrelease(td, osrelease); 478167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 479167159Sjkim linprocfs_osbuilder(td, sb); 480167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 481167159Sjkim linprocfs_osbuild(td, sb); 482167159Sjkim sbuf_cat(sb, "\n"); 48387275Srwatson 48478025Sdes return (0); 48565633Sdes} 48665633Sdes 48778113Sdes/* 48878113Sdes * Filler function for proc/loadavg 48978113Sdes */ 49078025Sdesstatic int 49178025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 49276839Sjlemon{ 49378025Sdes sbuf_printf(sb, 49476839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 49576839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 49676839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 49776839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 49876839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 49976839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 50076839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 50176839Sjlemon 1, /* number of running tasks */ 50276839Sjlemon nprocs, /* number of tasks */ 50378116Sdes lastpid /* the last pid */ 50476839Sjlemon ); 505119068Sdes 50678025Sdes return (0); 50776839Sjlemon} 50876839Sjlemon 50978113Sdes/* 51078113Sdes * Filler function for proc/pid/stat 51178113Sdes */ 51278025Sdesstatic int 51378025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 51467588Sdes{ 51569995Sdes struct kinfo_proc kp; 516166140Snetchild char state; 517166140Snetchild static int ratelimit = 0; 51867588Sdes 51994307Sjhb PROC_LOCK(p); 52069995Sdes fill_kinfo_proc(p, &kp); 52178025Sdes sbuf_printf(sb, "%d", p->p_pid); 52278025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 52367588Sdes PS_ADD("comm", "(%s)", p->p_comm); 524166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 525166140Snetchild state = 'R'; 526166140Snetchild 527166141Snetchild if (ratelimit == 0) { 528166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 529166162Snetchild kp.ki_stat, sizeof(linux_state)); 530166141Snetchild ++ratelimit; 531166141Snetchild } 532166140Snetchild } else 533166140Snetchild state = linux_state[kp.ki_stat - 1]; 534166140Snetchild PS_ADD("state", "%c", state); 53573923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 53667588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 53767588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 53891140Stanimura PROC_UNLOCK(p); 53967588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 540159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 54167588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 542159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 543159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 544159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 545159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 546159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 547159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 548159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 549159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 550159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 551159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 552159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 553159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 554159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 555159995Snetchild It should be the number of jiffies between system boot and process 556159995Snetchild start. */ 557159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 558159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 559159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 560159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 56169995Sdes PS_ADD("startcode", "%u", (unsigned)0); 56267588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 56367588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 564159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 565159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 566159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 567159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 568159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 569159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 57067588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 571159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 572159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 57369799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 574159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 575159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 576159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 57767588Sdes#undef PS_ADD 57878025Sdes sbuf_putc(sb, '\n'); 579119068Sdes 58078025Sdes return (0); 58167588Sdes} 58267588Sdes 58367588Sdes/* 584119911Sdes * Filler function for proc/pid/statm 585119911Sdes */ 586119911Sdesstatic int 587119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 588119911Sdes{ 589119911Sdes struct kinfo_proc kp; 590119911Sdes segsz_t lsize; 591120340Sdes 592119911Sdes PROC_LOCK(p); 593119911Sdes fill_kinfo_proc(p, &kp); 594119911Sdes PROC_UNLOCK(p); 595119911Sdes 596119911Sdes /* 597119911Sdes * See comments in linprocfs_doprocstatus() regarding the 598119911Sdes * computation of lsize. 599119911Sdes */ 600119911Sdes /* size resident share trs drs lrs dt */ 601119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 602119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 603119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 604119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 605119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 606119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 607119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 608119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 609119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 610119911Sdes 611119911Sdes return (0); 612119911Sdes} 613119911Sdes 614119911Sdes/* 61578113Sdes * Filler function for proc/pid/status 61678113Sdes */ 61778025Sdesstatic int 61878025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 61967588Sdes{ 62069995Sdes struct kinfo_proc kp; 62167588Sdes char *state; 62269799Sdes segsz_t lsize; 62399072Sjulian struct thread *td2; 624114983Sjhb struct sigacts *ps; 62574135Sjlemon int i; 62667588Sdes 627113611Sjhb PROC_LOCK(p); 62899072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 62999072Sjulian 63099072Sjulian if (P_SHOULDSTOP(p)) { 63199072Sjulian state = "T (stopped)"; 63299072Sjulian } else { 633113611Sjhb mtx_lock_spin(&sched_lock); 63499072Sjulian switch(p->p_state) { 63599072Sjulian case PRS_NEW: 63699072Sjulian state = "I (idle)"; 63799072Sjulian break; 63899072Sjulian case PRS_NORMAL: 63999072Sjulian if (p->p_flag & P_WEXIT) { 64099072Sjulian state = "X (exiting)"; 64199072Sjulian break; 64299072Sjulian } 64399072Sjulian switch(td2->td_state) { 644103216Sjulian case TDS_INHIBITED: 64599072Sjulian state = "S (sleeping)"; 64699072Sjulian break; 64799072Sjulian case TDS_RUNQ: 64899072Sjulian case TDS_RUNNING: 64999072Sjulian state = "R (running)"; 65099072Sjulian break; 65199072Sjulian default: 65299072Sjulian state = "? (unknown)"; 65399072Sjulian break; 65499072Sjulian } 65599072Sjulian break; 65699072Sjulian case PRS_ZOMBIE: 65799072Sjulian state = "Z (zombie)"; 65899072Sjulian break; 65999072Sjulian default: 66099072Sjulian state = "? (unknown)"; 66199072Sjulian break; 66299072Sjulian } 663113611Sjhb mtx_unlock_spin(&sched_lock); 66499072Sjulian } 66567588Sdes 66669995Sdes fill_kinfo_proc(p, &kp); 66778025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 66878031Sdes sbuf_printf(sb, "State:\t%s\n", state); 66967588Sdes 67067588Sdes /* 67167588Sdes * Credentials 67267588Sdes */ 67378025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 67478025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 67573923Sjhb p->p_pptr->p_pid : 0); 67678031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 67778031Sdes p->p_ucred->cr_uid, 67878031Sdes p->p_ucred->cr_svuid, 67978031Sdes /* FreeBSD doesn't have fsuid */ 68078031Sdes p->p_ucred->cr_uid); 68178031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 68278031Sdes p->p_ucred->cr_gid, 68378031Sdes p->p_ucred->cr_svgid, 68478031Sdes /* FreeBSD doesn't have fsgid */ 68578031Sdes p->p_ucred->cr_gid); 68678025Sdes sbuf_cat(sb, "Groups:\t"); 68767588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 68878031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 68971471Sjhb PROC_UNLOCK(p); 69078025Sdes sbuf_putc(sb, '\n'); 691119068Sdes 69267588Sdes /* 69367588Sdes * Memory 69469799Sdes * 69569799Sdes * While our approximation of VmLib may not be accurate (I 69669799Sdes * don't know of a simple way to verify it, and I'm not sure 69769799Sdes * it has much meaning anyway), I believe it's good enough. 69869799Sdes * 69969799Sdes * The same code that could (I think) accurately compute VmLib 70069799Sdes * could also compute VmLck, but I don't really care enough to 70169799Sdes * implement it. Submissions are welcome. 70267588Sdes */ 703113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 70478025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 705113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 706113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 707113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 708113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 70969995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 71069995Sdes kp.ki_ssize - kp.ki_tsize - 1; 711113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 71267588Sdes 71367588Sdes /* 71467588Sdes * Signal masks 71567588Sdes * 71667588Sdes * We support up to 128 signals, while Linux supports 32, 71767588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 71867588Sdes * just show the lower 32 bits of each mask. XXX hack. 71967588Sdes * 72067588Sdes * NB: on certain platforms (Sparc at least) Linux actually 72167588Sdes * supports 64 signals, but this code is a long way from 72267588Sdes * running on anything but i386, so ignore that for now. 72367588Sdes */ 72471471Sjhb PROC_LOCK(p); 725104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 72669799Sdes /* 72769799Sdes * I can't seem to find out where the signal mask is in 72869799Sdes * relation to struct proc, so SigBlk is left unimplemented. 72969799Sdes */ 73078025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 731114983Sjhb ps = p->p_sigacts; 732114983Sjhb mtx_lock(&ps->ps_mtx); 733114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 734114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 735114983Sjhb mtx_unlock(&ps->ps_mtx); 73671471Sjhb PROC_UNLOCK(p); 737119068Sdes 73867588Sdes /* 73967588Sdes * Linux also prints the capability masks, but we don't have 74067588Sdes * capabilities yet, and when we do get them they're likely to 74167588Sdes * be meaningless to Linux programs, so we lie. XXX 74267588Sdes */ 74378025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 74478025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 74578025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 746119068Sdes 74778025Sdes return (0); 74867588Sdes} 74974135Sjlemon 750119911Sdes 75178113Sdes/* 752119911Sdes * Filler function for proc/pid/cwd 753119911Sdes */ 754119911Sdesstatic int 755119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 756119911Sdes{ 757119911Sdes char *fullpath = "unknown"; 758119911Sdes char *freepath = NULL; 759119911Sdes 760119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 761119911Sdes sbuf_printf(sb, "%s", fullpath); 762119911Sdes if (freepath) 763119911Sdes free(freepath, M_TEMP); 764119911Sdes return (0); 765119911Sdes} 766119911Sdes 767119911Sdes/* 768119911Sdes * Filler function for proc/pid/root 769119911Sdes */ 770119911Sdesstatic int 771119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 772119911Sdes{ 773119911Sdes struct vnode *rvp; 774119911Sdes char *fullpath = "unknown"; 775119911Sdes char *freepath = NULL; 776119911Sdes 777119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 778119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 779119911Sdes sbuf_printf(sb, "%s", fullpath); 780119911Sdes if (freepath) 781119911Sdes free(freepath, M_TEMP); 782119911Sdes return (0); 783119911Sdes} 784119911Sdes 785119911Sdes/* 78678113Sdes * Filler function for proc/pid/cmdline 78778113Sdes */ 78878025Sdesstatic int 78978113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 79078113Sdes{ 79178113Sdes struct ps_strings pstr; 792138281Scperciva char **ps_argvstr; 79378113Sdes int error, i; 79478113Sdes 79578113Sdes /* 79678113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 79778113Sdes * revert back to the old way which only implements full cmdline 79878113Sdes * for the currept process and just p->p_comm for all other 79978113Sdes * processes. 80078113Sdes * Note that if the argv is no longer available, we deliberately 80178113Sdes * don't fall back on p->p_comm or return an error: the authentic 80278113Sdes * Linux behaviour is to return zero-length in this case. 80378113Sdes */ 80478113Sdes 80594620Sjhb PROC_LOCK(p); 806127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 80794620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 80894620Sjhb PROC_UNLOCK(p); 80994620Sjhb } else if (p != td->td_proc) { 81094620Sjhb PROC_UNLOCK(p); 81194620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 81294620Sjhb } else { 81394620Sjhb PROC_UNLOCK(p); 814103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 815103767Sjake sizeof(pstr)); 81694620Sjhb if (error) 81794620Sjhb return (error); 818138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 819138281Scperciva return (E2BIG); 820138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 821138281Scperciva M_TEMP, M_WAITOK); 822138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 823138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 824138281Scperciva if (error) { 825138281Scperciva free(ps_argvstr, M_TEMP); 826138281Scperciva return (error); 827138281Scperciva } 82894620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 829138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 83094620Sjhb sbuf_printf(sb, "%c", '\0'); 83178113Sdes } 832138281Scperciva free(ps_argvstr, M_TEMP); 83378113Sdes } 83478113Sdes 83578113Sdes return (0); 83678113Sdes} 83778113Sdes 83878113Sdes/* 839116173Sobrien * Filler function for proc/pid/environ 840116173Sobrien */ 841116173Sobrienstatic int 842116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 843116173Sobrien{ 844116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 845116173Sobrien 846116173Sobrien return (0); 847116173Sobrien} 848116173Sobrien 849116173Sobrien/* 850116173Sobrien * Filler function for proc/pid/maps 851116173Sobrien */ 852116173Sobrienstatic int 853116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 854116173Sobrien{ 855121265Scognet char mebuffer[512]; 856121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 857121246Scognet vm_map_entry_t entry; 858121265Scognet vm_object_t obj, tobj, lobj; 859121265Scognet vm_ooffset_t off = 0; 860121265Scognet char *name = "", *freename = NULL; 861121265Scognet size_t len; 862121265Scognet ino_t ino; 863121265Scognet int ref_count, shadow_count, flags; 864121265Scognet int error; 865137507Sphk struct vnode *vp; 866137507Sphk struct vattr vat; 867161094Skib int locked; 868121246Scognet 869121246Scognet PROC_LOCK(p); 870121246Scognet error = p_candebug(td, p); 871121246Scognet PROC_UNLOCK(p); 872121246Scognet if (error) 873121246Scognet return (error); 874121246Scognet 875121246Scognet if (uio->uio_rw != UIO_READ) 876121246Scognet return (EOPNOTSUPP); 877121246Scognet 878121246Scognet if (uio->uio_offset != 0) 879121246Scognet return (0); 880121246Scognet 881121246Scognet error = 0; 882121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 883121246Scognet vm_map_lock_read(map); 884121246Scognet for (entry = map->header.next; 885121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 886121246Scognet entry = entry->next) { 887121265Scognet name = ""; 888121265Scognet freename = NULL; 889121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 890121246Scognet continue; 891121246Scognet obj = entry->object.vm_object; 892121246Scognet for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 893121246Scognet lobj = tobj; 894121246Scognet ino = 0; 895121246Scognet if (lobj) { 896121246Scognet VM_OBJECT_LOCK(lobj); 897121246Scognet off = IDX_TO_OFF(lobj->size); 898161094Skib if (lobj->type == OBJT_VNODE) { 899161094Skib vp = lobj->handle; 900161094Skib if (vp) 901161094Skib vref(vp); 902121246Scognet } 903161094Skib else 904161094Skib vp = NULL; 905121246Scognet flags = obj->flags; 906121246Scognet ref_count = obj->ref_count; 907121246Scognet shadow_count = obj->shadow_count; 908121246Scognet VM_OBJECT_UNLOCK(lobj); 909161094Skib if (vp) { 910161094Skib vn_fullpath(td, vp, &name, &freename); 911161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 912161094Skib vn_lock(vp, LK_SHARED | LK_RETRY, td); 913161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 914161094Skib ino = vat.va_fileid; 915161094Skib vput(vp); 916161094Skib VFS_UNLOCK_GIANT(locked); 917161094Skib } 918121246Scognet } else { 919121246Scognet flags = 0; 920121246Scognet ref_count = 0; 921121246Scognet shadow_count = 0; 922121246Scognet } 923121246Scognet 924121246Scognet /* 925121246Scognet * format: 926121246Scognet * start, end, access, offset, major, minor, inode, name. 927121246Scognet */ 928121246Scognet snprintf(mebuffer, sizeof mebuffer, 929121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 930121246Scognet (u_long)entry->start, (u_long)entry->end, 931121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 932121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 933121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 934121246Scognet "p", 935121265Scognet (u_long)off, 936121246Scognet 0, 937121246Scognet 0, 938121265Scognet (u_long)ino, 939121246Scognet *name ? " " : "", 940121246Scognet name 941121246Scognet ); 942121246Scognet if (freename) 943121246Scognet free(freename, M_TEMP); 944121246Scognet len = strlen(mebuffer); 945121246Scognet if (len > uio->uio_resid) 946121246Scognet len = uio->uio_resid; /* 947121246Scognet * XXX We should probably return 948121246Scognet * EFBIG here, as in procfs. 949121246Scognet */ 950121246Scognet error = uiomove(mebuffer, len, uio); 951121246Scognet if (error) 952121246Scognet break; 953121246Scognet } 954121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 955121246Scognet vm_map_unlock_read(map); 956121246Scognet 957121246Scognet return (error); 958121246Scognet} 959121246Scognet 960116173Sobrien/* 96178113Sdes * Filler function for proc/net/dev 96278113Sdes */ 96378025Sdesstatic int 96478025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 96574135Sjlemon{ 96685129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 96774135Sjlemon struct ifnet *ifp; 96874135Sjlemon 96985129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 97083926Sdes "Inter-", " Receive", " Transmit", " face", 97185129Sdes "bytes packets errs drop fifo frame compressed", 97283926Sdes "bytes packets errs drop fifo frame compressed"); 97374135Sjlemon 974108172Shsu IFNET_RLOCK(); 97574135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 97685129Sdes linux_ifname(ifp, ifname, sizeof ifname); 97785129Sdes sbuf_printf(sb, "%6.6s:", ifname); 97883926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 97983926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 98083926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 98183926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 98274135Sjlemon } 983108172Shsu IFNET_RUNLOCK(); 984119068Sdes 98578025Sdes return (0); 98674135Sjlemon} 98774135Sjlemon 988158311Sambrisko/* 989167159Sjkim * Filler function for proc/sys/kernel/osrelease 990167159Sjkim */ 991167159Sjkimstatic int 992167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 993167159Sjkim{ 994167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 995167159Sjkim 996167159Sjkim linux_get_osrelease(td, osrelease); 997167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 998167159Sjkim 999167159Sjkim return (0); 1000167159Sjkim} 1001167159Sjkim 1002167159Sjkim/* 1003167159Sjkim * Filler function for proc/sys/kernel/ostype 1004167159Sjkim */ 1005167159Sjkimstatic int 1006167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1007167159Sjkim{ 1008167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1009167159Sjkim 1010167159Sjkim linux_get_osname(td, osname); 1011167159Sjkim sbuf_printf(sb, "%s\n", osname); 1012167159Sjkim 1013167159Sjkim return (0); 1014167159Sjkim} 1015167159Sjkim 1016167159Sjkim/* 1017167159Sjkim * Filler function for proc/sys/kernel/version 1018167159Sjkim */ 1019167159Sjkimstatic int 1020167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1021167159Sjkim{ 1022167159Sjkim linprocfs_osbuild(td, sb); 1023167159Sjkim sbuf_cat(sb, "\n"); 1024167159Sjkim 1025167159Sjkim return (0); 1026167159Sjkim} 1027167159Sjkim 1028167159Sjkim/* 1029164692Sjkim * Filler function for proc/sys/kernel/msgmni 1030164692Sjkim */ 1031164692Sjkimstatic int 1032164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1033164692Sjkim{ 1034164692Sjkim int msgmni; 1035164692Sjkim size_t size; 1036164692Sjkim 1037164692Sjkim size = sizeof(msgmni); 1038164692Sjkim if (kernel_sysctlbyname(td, "kern.ipc.msgmni", &msgmni, &size, 1039164692Sjkim 0, 0, 0, 0) != 0) 1040164692Sjkim msgmni = 0; 1041164692Sjkim sbuf_printf(sb, "%i\n", msgmni); 1042164692Sjkim 1043164692Sjkim return (0); 1044164692Sjkim} 1045164692Sjkim 1046164692Sjkim/* 1047163251Skeramida * Filler function for proc/sys/kernel/pid_max 1048163129Snetchild */ 1049163129Snetchildstatic int 1050163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1051163129Snetchild{ 1052163757Snetchild 1053163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1054163129Snetchild 1055163129Snetchild return (0); 1056163129Snetchild} 1057163129Snetchild 1058163129Snetchild/* 1059164692Sjkim * Filler function for proc/sys/kernel/sem 1060164692Sjkim */ 1061164692Sjkimstatic int 1062164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1063164692Sjkim{ 1064164692Sjkim int semmsl, semmns, semopm, semmni; 1065164692Sjkim size_t size; 1066164692Sjkim 1067164692Sjkim /* Field 1: SEMMSL */ 1068164692Sjkim size = sizeof(semmsl); 1069164692Sjkim if (kernel_sysctlbyname(td, "kern.ipc.semmsl", &semmsl, &size, 1070164692Sjkim 0, 0, 0, 0) != 0) 1071164692Sjkim semmsl = 0; 1072164692Sjkim 1073164692Sjkim /* Field 2: SEMMNS */ 1074164692Sjkim size = sizeof(semmns); 1075164692Sjkim if (kernel_sysctlbyname(td, "kern.ipc.semmns", &semmns, &size, 1076164692Sjkim 0, 0, 0, 0) != 0) 1077164692Sjkim semmns = 0; 1078164692Sjkim 1079164692Sjkim /* Field 3: SEMOPM */ 1080164692Sjkim size = sizeof(semopm); 1081164692Sjkim if (kernel_sysctlbyname(td, "kern.ipc.semopm", &semopm, &size, 1082164692Sjkim 0, 0, 0, 0) != 0) 1083164692Sjkim semopm = 0; 1084164692Sjkim 1085164692Sjkim /* Field 4: SEMMNI */ 1086164692Sjkim size = sizeof(semmni); 1087164692Sjkim if (kernel_sysctlbyname(td, "kern.ipc.semmni", &semmni, &size, 1088164692Sjkim 0, 0, 0, 0) != 0) 1089164692Sjkim semmni = 0; 1090164692Sjkim 1091164692Sjkim sbuf_printf(sb, "%i %i %i %i\n", semmsl, semmns, semopm, semmni); 1092164692Sjkim 1093164692Sjkim return (0); 1094164692Sjkim} 1095164692Sjkim 1096164692Sjkim/* 1097158311Sambrisko * Filler function for proc/scsi/device_info 1098158311Sambrisko */ 1099158311Sambriskostatic int 1100158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1101158311Sambrisko{ 1102158311Sambrisko return (0); 1103158311Sambrisko} 1104158311Sambrisko 1105158311Sambrisko/* 1106158311Sambrisko * Filler function for proc/scsi/scsi 1107158311Sambrisko */ 1108158311Sambriskostatic int 1109158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1110158311Sambrisko{ 1111158311Sambrisko return (0); 1112158311Sambrisko} 1113158311Sambrisko 111485538Sphkextern struct cdevsw *cdevsw[]; 111585538Sphk 111678113Sdes/* 111778113Sdes * Filler function for proc/devices 111878113Sdes */ 111978025Sdesstatic int 112078025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 112174135Sjlemon{ 1122158311Sambrisko char *char_devices; 112378025Sdes sbuf_printf(sb, "Character devices:\n"); 112474135Sjlemon 1125158311Sambrisko char_devices = linux_get_char_devices(); 1126158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1127158311Sambrisko linux_free_get_char_devices(char_devices); 112874135Sjlemon 112978025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1130119068Sdes 113178025Sdes return (0); 113274135Sjlemon} 113374135Sjlemon 113478113Sdes/* 113578113Sdes * Filler function for proc/cmdline 113678113Sdes */ 113778025Sdesstatic int 113878025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 113974135Sjlemon{ 114078025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 114178025Sdes sbuf_printf(sb, " ro root=302\n"); 114278025Sdes return (0); 114378025Sdes} 114474135Sjlemon 114583926Sdes#if 0 114678025Sdes/* 114783926Sdes * Filler function for proc/modules 114883926Sdes */ 114983926Sdesstatic int 115083926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 115183926Sdes{ 115283926Sdes struct linker_file *lf; 1153119068Sdes 115483926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 115583926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 115683926Sdes (unsigned long)lf->size, lf->refs); 115783926Sdes } 115883926Sdes return (0); 115983926Sdes} 116083926Sdes#endif 116183926Sdes 116283926Sdes/* 116385129Sdes * Constructor 116478025Sdes */ 116585129Sdesstatic int 116685129Sdeslinprocfs_init(PFS_INIT_ARGS) 116785129Sdes{ 116885129Sdes struct pfs_node *root; 116985129Sdes struct pfs_node *dir; 117074135Sjlemon 117185129Sdes root = pi->pi_root; 117278025Sdes 1173119923Sdes /* /proc/... */ 1174119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1175119911Sdes NULL, NULL, PFS_RD); 1176119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1177119911Sdes NULL, NULL, PFS_RD); 1178119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1179119911Sdes NULL, NULL, PFS_RD); 1180119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1181119911Sdes NULL, NULL, PFS_RD); 1182119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1183119911Sdes NULL, NULL, PFS_RD); 118483926Sdes#if 0 1185119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1186119911Sdes NULL, NULL, PFS_RD); 118783926Sdes#endif 1188158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1189158311Sambrisko NULL, NULL, PFS_RD); 1190119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1191119911Sdes NULL, NULL, PFS_RD); 119287543Sdes pfs_create_link(root, "self", &procfs_docurproc, 119385129Sdes NULL, NULL, 0); 1194119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1195119911Sdes NULL, NULL, PFS_RD); 1196119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1197119911Sdes NULL, NULL, PFS_RD); 1198119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1199119911Sdes NULL, NULL, PFS_RD); 120078025Sdes 1201119923Sdes /* /proc/net/... */ 120285129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 120385129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 120485129Sdes NULL, NULL, PFS_RD); 120578025Sdes 1206119923Sdes /* /proc/<pid>/... */ 120785129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 120885129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 120985129Sdes NULL, NULL, PFS_RD); 1210119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1211119911Sdes NULL, NULL, 0); 1212116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1213116173Sobrien NULL, NULL, PFS_RD); 121487543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 121587543Sdes NULL, &procfs_notsystem, 0); 1216116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1217116173Sobrien NULL, NULL, PFS_RD); 121885129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 121985129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1220119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1221119911Sdes NULL, NULL, 0); 122285129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 122385129Sdes NULL, NULL, PFS_RD); 1224119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1225119911Sdes NULL, NULL, PFS_RD); 122685129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 122785129Sdes NULL, NULL, PFS_RD); 122885129Sdes 1229158311Sambrisko /* /proc/scsi/... */ 1230158311Sambrisko dir = pfs_create_dir(root, "scsi", NULL, NULL, 0); 1231158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1232158311Sambrisko NULL, NULL, PFS_RD); 1233158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1234158311Sambrisko NULL, NULL, PFS_RD); 1235163129Snetchild 1236163129Snetchild /* /proc/sys/... */ 1237163129Snetchild dir = pfs_create_dir(root, "sys", NULL, NULL, 0); 1238163129Snetchild /* /proc/sys/kernel/... */ 1239163129Snetchild dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0); 1240167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1241167159Sjkim NULL, NULL, PFS_RD); 1242167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1243167159Sjkim NULL, NULL, PFS_RD); 1244167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1245167159Sjkim NULL, NULL, PFS_RD); 1246164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1247164692Sjkim NULL, NULL, PFS_RD); 1248163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1249163129Snetchild NULL, NULL, PFS_RD); 1250164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1251164692Sjkim NULL, NULL, PFS_RD); 1252163129Snetchild 125385129Sdes return (0); 125485129Sdes} 125585129Sdes 125685129Sdes/* 125785129Sdes * Destructor 125885129Sdes */ 125985129Sdesstatic int 126085129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 126185129Sdes{ 126285129Sdes 126385129Sdes /* nothing to do, pseudofs will GC */ 126485129Sdes return (0); 126585129Sdes} 126685129Sdes 126785129SdesPSEUDOFS(linprocfs, 1); 126878025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 126978025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1270