linprocfs.c revision 168067
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 168067 2007-03-30 17:56:44Z 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> 57168067Sjkim#include <sys/msg.h> 5876827Salfred#include <sys/mutex.h> 5985289Sdes#include <sys/namei.h> 6065633Sdes#include <sys/proc.h> 6165633Sdes#include <sys/resourcevar.h> 6269995Sdes#include <sys/sbuf.h> 63168067Sjkim#include <sys/sem.h> 64123246Sdes#include <sys/smp.h> 6583926Sdes#include <sys/socket.h> 6676839Sjlemon#include <sys/sysctl.h> 6783926Sdes#include <sys/systm.h> 68159995Snetchild#include <sys/time.h> 6965633Sdes#include <sys/tty.h> 7083926Sdes#include <sys/user.h> 7183926Sdes#include <sys/vmmeter.h> 7259412Smsmith#include <sys/vnode.h> 7359412Smsmith 7483926Sdes#include <net/if.h> 7583926Sdes 7659412Smsmith#include <vm/vm.h> 7759412Smsmith#include <vm/pmap.h> 7867588Sdes#include <vm/vm_map.h> 7959412Smsmith#include <vm/vm_param.h> 8060860Sdes#include <vm/vm_object.h> 8159412Smsmith#include <vm/swap_pager.h> 8269799Sdes 8367589Sdes#include <machine/clock.h> 8478113Sdes 85133822Stjr#if defined(__i386__) || defined(__amd64__) 8667589Sdes#include <machine/cputypes.h> 8759412Smsmith#include <machine/md_var.h> 88133822Stjr#endif /* __i386__ || __amd64__ */ 8959412Smsmith 90133822Stjr#include "opt_compat.h" 91140214Sobrien#ifdef COMPAT_LINUX32 /* XXX */ 92140214Sobrien#include <machine/../linux32/linux.h> 93140214Sobrien#else 9487275Srwatson#include <machine/../linux/linux.h> 95133822Stjr#endif 9685129Sdes#include <compat/linux/linux_ioctl.h> 9769995Sdes#include <compat/linux/linux_mib.h> 9885289Sdes#include <compat/linux/linux_util.h> 9978025Sdes#include <fs/pseudofs/pseudofs.h> 10084248Sdes#include <fs/procfs/procfs.h> 10159412Smsmith 10267588Sdes/* 10367588Sdes * Various conversion macros 10467588Sdes */ 10576405Sdes#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10667588Sdes#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10767588Sdes#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10869799Sdes#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10967588Sdes#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 11067588Sdes#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 11174135Sjlemon 112159995Snetchild/** 113159995Snetchild * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 114159995Snetchild * 115159995Snetchild * The linux procfs state field displays one of the characters RSDZTW to 116159995Snetchild * denote running, sleeping in an interruptible wait, waiting in an 117159995Snetchild * uninteruptible disk sleep, a zombie process, process is being traced 118159995Snetchild * or stopped, or process is paging respectively. 119159995Snetchild * 120159995Snetchild * Our struct kinfo_proc contains the variable ki_stat which contains a 121159995Snetchild * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 122159995Snetchild * 123159995Snetchild * This character array is used with ki_stati-1 as an index and tries to 124159995Snetchild * map our states to suitable linux states. 125159995Snetchild */ 126166140Snetchildstatic char linux_state[] = "RRSTZDD"; 127159995Snetchild 12878113Sdes/* 12978113Sdes * Filler function for proc/meminfo 13078113Sdes */ 13178025Sdesstatic int 13278025Sdeslinprocfs_domeminfo(PFS_FILL_ARGS) 13359412Smsmith{ 13459412Smsmith unsigned long memtotal; /* total memory in bytes */ 13559412Smsmith unsigned long memused; /* used memory in bytes */ 13659412Smsmith unsigned long memfree; /* free memory in bytes */ 13759412Smsmith unsigned long memshared; /* shared memory ??? */ 13859412Smsmith unsigned long buffers, cached; /* buffer / cache memory ??? */ 139113574Sjhb unsigned long long swaptotal; /* total swap space in bytes */ 140113574Sjhb unsigned long long swapused; /* used swap space in bytes */ 141113574Sjhb unsigned long long swapfree; /* free swap space in bytes */ 14260860Sdes vm_object_t object; 143117723Sphk int i, j; 14459412Smsmith 14559412Smsmith memtotal = physmem * PAGE_SIZE; 14659412Smsmith /* 14759412Smsmith * The correct thing here would be: 14859412Smsmith * 14959412Smsmith memfree = cnt.v_free_count * PAGE_SIZE; 15059412Smsmith memused = memtotal - memfree; 15159412Smsmith * 15259412Smsmith * but it might mislead linux binaries into thinking there 15359412Smsmith * is very little memory left, so we cheat and tell them that 15459412Smsmith * all memory that isn't wired down is free. 15559412Smsmith */ 15659412Smsmith memused = cnt.v_wire_count * PAGE_SIZE; 15759412Smsmith memfree = memtotal - memused; 158117723Sphk swap_pager_status(&i, &j); 159153310Smlaier swaptotal = (unsigned long long)i * PAGE_SIZE; 160153310Smlaier swapused = (unsigned long long)j * PAGE_SIZE; 161117723Sphk swapfree = swaptotal - swapused; 16260860Sdes memshared = 0; 163124082Salc mtx_lock(&vm_object_list_mtx); 16471471Sjhb TAILQ_FOREACH(object, &vm_object_list, object_list) 16560860Sdes if (object->shadow_count > 1) 16660860Sdes memshared += object->resident_page_count; 167124082Salc mtx_unlock(&vm_object_list_mtx); 16860860Sdes memshared *= PAGE_SIZE; 16959412Smsmith /* 17059412Smsmith * We'd love to be able to write: 17159412Smsmith * 17259412Smsmith buffers = bufspace; 17359412Smsmith * 17459412Smsmith * but bufspace is internal to vfs_bio.c and we don't feel 17559412Smsmith * like unstaticizing it just for linprocfs's sake. 17659412Smsmith */ 17759412Smsmith buffers = 0; 17859412Smsmith cached = cnt.v_cache_count * PAGE_SIZE; 17959412Smsmith 18078025Sdes sbuf_printf(sb, 18178031Sdes " total: used: free: shared: buffers: cached:\n" 18269799Sdes "Mem: %lu %lu %lu %lu %lu %lu\n" 18376839Sjlemon "Swap: %llu %llu %llu\n" 18469799Sdes "MemTotal: %9lu kB\n" 18569799Sdes "MemFree: %9lu kB\n" 18669799Sdes "MemShared:%9lu kB\n" 18769799Sdes "Buffers: %9lu kB\n" 18869799Sdes "Cached: %9lu kB\n" 18976839Sjlemon "SwapTotal:%9llu kB\n" 19076839Sjlemon "SwapFree: %9llu kB\n", 19169799Sdes memtotal, memused, memfree, memshared, buffers, cached, 19269799Sdes swaptotal, swapused, swapfree, 19369799Sdes B2K(memtotal), B2K(memfree), 19469799Sdes B2K(memshared), B2K(buffers), B2K(cached), 19569799Sdes B2K(swaptotal), B2K(swapfree)); 19659412Smsmith 19778025Sdes return (0); 19859412Smsmith} 19959412Smsmith 200133822Stjr#if defined(__i386__) || defined(__amd64__) 20178113Sdes/* 202133822Stjr * Filler function for proc/cpuinfo (i386 & amd64 version) 20378113Sdes */ 20478113Sdesstatic int 20578113Sdeslinprocfs_docpuinfo(PFS_FILL_ARGS) 20678113Sdes{ 207159544Sdes int hw_model[2]; 208159544Sdes char model[128]; 209159544Sdes size_t size; 210123246Sdes int class, fqmhz, fqkhz; 211118421Sdes int i; 21259412Smsmith 21369799Sdes /* 21478031Sdes * We default the flags to include all non-conflicting flags, 21578031Sdes * and the Intel versions of conflicting flags. 21669799Sdes */ 21778031Sdes static char *flags[] = { 21878031Sdes "fpu", "vme", "de", "pse", "tsc", 21978031Sdes "msr", "pae", "mce", "cx8", "apic", 22078031Sdes "sep", "sep", "mtrr", "pge", "mca", 22178031Sdes "cmov", "pat", "pse36", "pn", "b19", 22278031Sdes "b20", "b21", "mmxext", "mmx", "fxsr", 22378031Sdes "xmm", "b26", "b27", "b28", "b29", 22467589Sdes "3dnowext", "3dnow" 22567589Sdes }; 22667589Sdes 22759412Smsmith switch (cpu_class) { 228133822Stjr#ifdef __i386__ 22959412Smsmith case CPUCLASS_286: 23067589Sdes class = 2; 23159412Smsmith break; 23259412Smsmith case CPUCLASS_386: 23367589Sdes class = 3; 23459412Smsmith break; 23559412Smsmith case CPUCLASS_486: 23667589Sdes class = 4; 23759412Smsmith break; 23859412Smsmith case CPUCLASS_586: 23967589Sdes class = 5; 24059412Smsmith break; 24159412Smsmith case CPUCLASS_686: 24267589Sdes class = 6; 24359412Smsmith break; 24459412Smsmith default: 24578031Sdes class = 0; 24659412Smsmith break; 247159170Sdes#else /* __amd64__ */ 248133822Stjr default: 249159170Sdes class = 15; 250133822Stjr break; 251133822Stjr#endif 25259412Smsmith } 25359412Smsmith 254159544Sdes hw_model[0] = CTL_HW; 255159544Sdes hw_model[1] = HW_MODEL; 256159544Sdes model[0] = '\0'; 257159544Sdes size = sizeof(model); 258159544Sdes if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 259159544Sdes strcpy(model, "unknown"); 260123246Sdes for (i = 0; i < mp_ncpus; ++i) { 261118421Sdes sbuf_printf(sb, 262118421Sdes "processor\t: %d\n" 263118421Sdes "vendor_id\t: %.20s\n" 264118421Sdes "cpu family\t: %d\n" 265118421Sdes "model\t\t: %d\n" 266159544Sdes "model name\t: %s\n" 267118421Sdes "stepping\t: %d\n", 268159544Sdes i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 269159544Sdes /* XXX per-cpu vendor / class / model / id? */ 270118421Sdes } 27159412Smsmith 27278031Sdes sbuf_cat(sb, 27378031Sdes "flags\t\t:"); 27467589Sdes 27578031Sdes if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 27667589Sdes flags[16] = "fcmov"; 27778031Sdes } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 27867589Sdes flags[24] = "cxmmx"; 27978031Sdes } 280119068Sdes 28178031Sdes for (i = 0; i < 32; i++) 28267589Sdes if (cpu_feature & (1 << i)) 28378025Sdes sbuf_printf(sb, " %s", flags[i]); 28478025Sdes sbuf_cat(sb, "\n"); 28578031Sdes if (class >= 5) { 28669799Sdes fqmhz = (tsc_freq + 4999) / 1000000; 28769799Sdes fqkhz = ((tsc_freq + 4999) / 10000) % 100; 28878025Sdes sbuf_printf(sb, 28969799Sdes "cpu MHz\t\t: %d.%02d\n" 29069799Sdes "bogomips\t: %d.%02d\n", 29169799Sdes fqmhz, fqkhz, fqmhz, fqkhz); 29278031Sdes } 29369995Sdes 29478025Sdes return (0); 29559412Smsmith} 296133822Stjr#endif /* __i386__ || __amd64__ */ 29765633Sdes 29878113Sdes/* 29985289Sdes * Filler function for proc/mtab 30085289Sdes * 30185289Sdes * This file doesn't exist in Linux' procfs, but is included here so 30285289Sdes * users can symlink /compat/linux/etc/mtab to /proc/mtab 30385289Sdes */ 30485289Sdesstatic int 30585289Sdeslinprocfs_domtab(PFS_FILL_ARGS) 30685289Sdes{ 30785289Sdes struct nameidata nd; 30885289Sdes struct mount *mp; 30991334Sjulian const char *lep; 31091334Sjulian char *dlep, *flep, *mntto, *mntfrom, *fstype; 31185289Sdes size_t lep_len; 31285289Sdes int error; 31385289Sdes 31485289Sdes /* resolve symlinks etc. in the emulation tree prefix */ 31585289Sdes NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 31685289Sdes flep = NULL; 317124407Srwatson if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 31885289Sdes lep = linux_emul_path; 31991334Sjulian else 32091334Sjulian lep = dlep; 32185289Sdes lep_len = strlen(lep); 322119068Sdes 32385289Sdes mtx_lock(&mountlist_mtx); 32485289Sdes error = 0; 32585289Sdes TAILQ_FOREACH(mp, &mountlist, mnt_list) { 32685289Sdes /* determine device name */ 32785289Sdes mntfrom = mp->mnt_stat.f_mntfromname; 328119068Sdes 32985289Sdes /* determine mount point */ 33085289Sdes mntto = mp->mnt_stat.f_mntonname; 33185289Sdes if (strncmp(mntto, lep, lep_len) == 0 && 33285289Sdes mntto[lep_len] == '/') 33385289Sdes mntto += lep_len; 33485289Sdes 33585289Sdes /* determine fs type */ 33685289Sdes fstype = mp->mnt_stat.f_fstypename; 33785289Sdes if (strcmp(fstype, pn->pn_info->pi_name) == 0) 33885289Sdes mntfrom = fstype = "proc"; 33985289Sdes else if (strcmp(fstype, "procfs") == 0) 34085289Sdes continue; 341119068Sdes 342158311Sambrisko if (strcmp(fstype, "linsysfs") == 0) { 343158311Sambrisko sbuf_printf(sb, "/sys %s sysfs %s", mntto, 344158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 345158311Sambrisko } else { 346158311Sambrisko sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 347158311Sambrisko mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 348158311Sambrisko } 34985289Sdes#define ADD_OPTION(opt, name) \ 35085289Sdes if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 35185289Sdes ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 35285289Sdes ADD_OPTION(MNT_NOEXEC, "noexec"); 35385289Sdes ADD_OPTION(MNT_NOSUID, "nosuid"); 35485289Sdes ADD_OPTION(MNT_UNION, "union"); 35585289Sdes ADD_OPTION(MNT_ASYNC, "async"); 35685289Sdes ADD_OPTION(MNT_SUIDDIR, "suiddir"); 35785289Sdes ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 35885289Sdes ADD_OPTION(MNT_NOATIME, "noatime"); 35985289Sdes#undef ADD_OPTION 36085289Sdes /* a real Linux mtab will also show NFS options */ 36185289Sdes sbuf_printf(sb, " 0 0\n"); 36285289Sdes } 36385289Sdes mtx_unlock(&mountlist_mtx); 36485289Sdes if (flep != NULL) 36585289Sdes free(flep, M_TEMP); 36685289Sdes return (error); 36785289Sdes} 36885289Sdes 36985289Sdes/* 37078113Sdes * Filler function for proc/stat 37178113Sdes */ 37278025Sdesstatic int 37378025Sdeslinprocfs_dostat(PFS_FILL_ARGS) 37465633Sdes{ 375123246Sdes int i; 376120339Sdes 377120339Sdes sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 378120339Sdes T2J(cp_time[CP_USER]), 379120339Sdes T2J(cp_time[CP_NICE]), 380120339Sdes T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 381120339Sdes T2J(cp_time[CP_IDLE])); 382143194Ssobomax for (i = 0; i < mp_ncpus; ++i) 383143194Ssobomax sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 384143194Ssobomax T2J(cp_time[CP_USER]) / mp_ncpus, 385143194Ssobomax T2J(cp_time[CP_NICE]) / mp_ncpus, 386143194Ssobomax T2J(cp_time[CP_SYS]) / mp_ncpus, 387143194Ssobomax T2J(cp_time[CP_IDLE]) / mp_ncpus); 38878025Sdes sbuf_printf(sb, 38969799Sdes "disk 0 0 0 0\n" 39069799Sdes "page %u %u\n" 39169799Sdes "swap %u %u\n" 39269799Sdes "intr %u\n" 39369799Sdes "ctxt %u\n" 39485657Sdillon "btime %lld\n", 39569799Sdes cnt.v_vnodepgsin, 39669799Sdes cnt.v_vnodepgsout, 39769799Sdes cnt.v_swappgsin, 39869799Sdes cnt.v_swappgsout, 39969799Sdes cnt.v_intr, 40069799Sdes cnt.v_swtch, 401113574Sjhb (long long)boottime.tv_sec); 40278025Sdes return (0); 40365633Sdes} 40465633Sdes 40578113Sdes/* 40678113Sdes * Filler function for proc/uptime 40778113Sdes */ 40878025Sdesstatic int 40978025Sdeslinprocfs_douptime(PFS_FILL_ARGS) 41065633Sdes{ 41165633Sdes struct timeval tv; 41265633Sdes 41365633Sdes getmicrouptime(&tv); 41485657Sdillon sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 415113574Sjhb (long long)tv.tv_sec, tv.tv_usec / 10000, 41669799Sdes T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 41778025Sdes return (0); 41865633Sdes} 41965633Sdes 42078113Sdes/* 421167159Sjkim * Get OS build date 422167159Sjkim */ 423167159Sjkimstatic void 424167159Sjkimlinprocfs_osbuild(struct thread *td, struct sbuf *sb) 425167159Sjkim{ 426167159Sjkim#if 0 427167159Sjkim char osbuild[256]; 428167159Sjkim char *cp1, *cp2; 429167159Sjkim 430167159Sjkim strncpy(osbuild, version, 256); 431167159Sjkim osbuild[255] = '\0'; 432167159Sjkim cp1 = strstr(osbuild, "\n"); 433167159Sjkim cp2 = strstr(osbuild, ":"); 434167159Sjkim if (cp1 && cp2) { 435167159Sjkim *cp1 = *cp2 = '\0'; 436167159Sjkim cp1 = strstr(osbuild, "#"); 437167159Sjkim } else 438167159Sjkim cp1 = NULL; 439167159Sjkim if (cp1) 440167159Sjkim sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 441167159Sjkim else 442167159Sjkim#endif 443167159Sjkim sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 444167159Sjkim} 445167159Sjkim 446167159Sjkim/* 447167159Sjkim * Get OS builder 448167159Sjkim */ 449167159Sjkimstatic void 450167159Sjkimlinprocfs_osbuilder(struct thread *td, struct sbuf *sb) 451167159Sjkim{ 452167159Sjkim char builder[256]; 453167159Sjkim char *cp; 454167159Sjkim 455167159Sjkim cp = strstr(version, "\n "); 456167159Sjkim if (cp) { 457167159Sjkim strncpy(builder, cp + 5, 256); 458167159Sjkim builder[255] = '\0'; 459167159Sjkim cp = strstr(builder, ":"); 460167159Sjkim if (cp) 461167159Sjkim *cp = '\0'; 462167159Sjkim } 463167159Sjkim if (cp) 464167159Sjkim sbuf_cat(sb, builder); 465167159Sjkim else 466167159Sjkim sbuf_cat(sb, "des@freebsd.org"); 467167159Sjkim} 468167159Sjkim 469167159Sjkim/* 47078113Sdes * Filler function for proc/version 47178113Sdes */ 47278025Sdesstatic int 47378025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 47465633Sdes{ 47587275Srwatson char osname[LINUX_MAX_UTSNAME]; 47687275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 47787275Srwatson 478112206Sjhb linux_get_osname(td, osname); 479112206Sjhb linux_get_osrelease(td, osrelease); 480167159Sjkim sbuf_printf(sb, "%s version %s (", osname, osrelease); 481167159Sjkim linprocfs_osbuilder(td, sb); 482167159Sjkim sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 483167159Sjkim linprocfs_osbuild(td, sb); 484167159Sjkim sbuf_cat(sb, "\n"); 48587275Srwatson 48678025Sdes return (0); 48765633Sdes} 48865633Sdes 48978113Sdes/* 49078113Sdes * Filler function for proc/loadavg 49178113Sdes */ 49278025Sdesstatic int 49378025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 49476839Sjlemon{ 49578025Sdes sbuf_printf(sb, 49676839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 49776839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 49876839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 49976839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 50076839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 50176839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 50276839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 50376839Sjlemon 1, /* number of running tasks */ 50476839Sjlemon nprocs, /* number of tasks */ 50578116Sdes lastpid /* the last pid */ 50676839Sjlemon ); 507119068Sdes 50878025Sdes return (0); 50976839Sjlemon} 51076839Sjlemon 51178113Sdes/* 51278113Sdes * Filler function for proc/pid/stat 51378113Sdes */ 51478025Sdesstatic int 51578025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 51667588Sdes{ 51769995Sdes struct kinfo_proc kp; 518166140Snetchild char state; 519166140Snetchild static int ratelimit = 0; 52067588Sdes 52194307Sjhb PROC_LOCK(p); 52269995Sdes fill_kinfo_proc(p, &kp); 52378025Sdes sbuf_printf(sb, "%d", p->p_pid); 52478025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 52567588Sdes PS_ADD("comm", "(%s)", p->p_comm); 526166140Snetchild if (kp.ki_stat > sizeof(linux_state)) { 527166140Snetchild state = 'R'; 528166140Snetchild 529166141Snetchild if (ratelimit == 0) { 530166162Snetchild printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 531166162Snetchild kp.ki_stat, sizeof(linux_state)); 532166141Snetchild ++ratelimit; 533166141Snetchild } 534166140Snetchild } else 535166140Snetchild state = linux_state[kp.ki_stat - 1]; 536166140Snetchild PS_ADD("state", "%c", state); 53773923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 53867588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 53967588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 54091140Stanimura PROC_UNLOCK(p); 54167588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 542159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 54367588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 544159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 545159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 546159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 547159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 548159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 549159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 550159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 551159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 552159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 553159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 554159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 555159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 556159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 557159995Snetchild It should be the number of jiffies between system boot and process 558159995Snetchild start. */ 559159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 560159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 561159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 562159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 56369995Sdes PS_ADD("startcode", "%u", (unsigned)0); 56467588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 56567588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 566159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 567159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 568159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 569159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 570159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 571159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 57267588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 573159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 574159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 57569799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 576159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 577159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 578159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 57967588Sdes#undef PS_ADD 58078025Sdes sbuf_putc(sb, '\n'); 581119068Sdes 58278025Sdes return (0); 58367588Sdes} 58467588Sdes 58567588Sdes/* 586119911Sdes * Filler function for proc/pid/statm 587119911Sdes */ 588119911Sdesstatic int 589119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 590119911Sdes{ 591119911Sdes struct kinfo_proc kp; 592119911Sdes segsz_t lsize; 593120340Sdes 594119911Sdes PROC_LOCK(p); 595119911Sdes fill_kinfo_proc(p, &kp); 596119911Sdes PROC_UNLOCK(p); 597119911Sdes 598119911Sdes /* 599119911Sdes * See comments in linprocfs_doprocstatus() regarding the 600119911Sdes * computation of lsize. 601119911Sdes */ 602119911Sdes /* size resident share trs drs lrs dt */ 603119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 604119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 605119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 606119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 607119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 608119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 609119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 610119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 611119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 612119911Sdes 613119911Sdes return (0); 614119911Sdes} 615119911Sdes 616119911Sdes/* 61778113Sdes * Filler function for proc/pid/status 61878113Sdes */ 61978025Sdesstatic int 62078025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 62167588Sdes{ 62269995Sdes struct kinfo_proc kp; 62367588Sdes char *state; 62469799Sdes segsz_t lsize; 62599072Sjulian struct thread *td2; 626114983Sjhb struct sigacts *ps; 62774135Sjlemon int i; 62867588Sdes 629113611Sjhb PROC_LOCK(p); 63099072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 63199072Sjulian 63299072Sjulian if (P_SHOULDSTOP(p)) { 63399072Sjulian state = "T (stopped)"; 63499072Sjulian } else { 635113611Sjhb mtx_lock_spin(&sched_lock); 63699072Sjulian switch(p->p_state) { 63799072Sjulian case PRS_NEW: 63899072Sjulian state = "I (idle)"; 63999072Sjulian break; 64099072Sjulian case PRS_NORMAL: 64199072Sjulian if (p->p_flag & P_WEXIT) { 64299072Sjulian state = "X (exiting)"; 64399072Sjulian break; 64499072Sjulian } 64599072Sjulian switch(td2->td_state) { 646103216Sjulian case TDS_INHIBITED: 64799072Sjulian state = "S (sleeping)"; 64899072Sjulian break; 64999072Sjulian case TDS_RUNQ: 65099072Sjulian case TDS_RUNNING: 65199072Sjulian state = "R (running)"; 65299072Sjulian break; 65399072Sjulian default: 65499072Sjulian state = "? (unknown)"; 65599072Sjulian break; 65699072Sjulian } 65799072Sjulian break; 65899072Sjulian case PRS_ZOMBIE: 65999072Sjulian state = "Z (zombie)"; 66099072Sjulian break; 66199072Sjulian default: 66299072Sjulian state = "? (unknown)"; 66399072Sjulian break; 66499072Sjulian } 665113611Sjhb mtx_unlock_spin(&sched_lock); 66699072Sjulian } 66767588Sdes 66869995Sdes fill_kinfo_proc(p, &kp); 66978025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 67078031Sdes sbuf_printf(sb, "State:\t%s\n", state); 67167588Sdes 67267588Sdes /* 67367588Sdes * Credentials 67467588Sdes */ 67578025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 67678025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 67773923Sjhb p->p_pptr->p_pid : 0); 67878031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 67978031Sdes p->p_ucred->cr_uid, 68078031Sdes p->p_ucred->cr_svuid, 68178031Sdes /* FreeBSD doesn't have fsuid */ 68278031Sdes p->p_ucred->cr_uid); 68378031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 68478031Sdes p->p_ucred->cr_gid, 68578031Sdes p->p_ucred->cr_svgid, 68678031Sdes /* FreeBSD doesn't have fsgid */ 68778031Sdes p->p_ucred->cr_gid); 68878025Sdes sbuf_cat(sb, "Groups:\t"); 68967588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 69078031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 69171471Sjhb PROC_UNLOCK(p); 69278025Sdes sbuf_putc(sb, '\n'); 693119068Sdes 69467588Sdes /* 69567588Sdes * Memory 69669799Sdes * 69769799Sdes * While our approximation of VmLib may not be accurate (I 69869799Sdes * don't know of a simple way to verify it, and I'm not sure 69969799Sdes * it has much meaning anyway), I believe it's good enough. 70069799Sdes * 70169799Sdes * The same code that could (I think) accurately compute VmLib 70269799Sdes * could also compute VmLck, but I don't really care enough to 70369799Sdes * implement it. Submissions are welcome. 70467588Sdes */ 705113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 70678025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 707113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 708113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 709113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 710113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 71169995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 71269995Sdes kp.ki_ssize - kp.ki_tsize - 1; 713113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 71467588Sdes 71567588Sdes /* 71667588Sdes * Signal masks 71767588Sdes * 71867588Sdes * We support up to 128 signals, while Linux supports 32, 71967588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 72067588Sdes * just show the lower 32 bits of each mask. XXX hack. 72167588Sdes * 72267588Sdes * NB: on certain platforms (Sparc at least) Linux actually 72367588Sdes * supports 64 signals, but this code is a long way from 72467588Sdes * running on anything but i386, so ignore that for now. 72567588Sdes */ 72671471Sjhb PROC_LOCK(p); 727104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 72869799Sdes /* 72969799Sdes * I can't seem to find out where the signal mask is in 73069799Sdes * relation to struct proc, so SigBlk is left unimplemented. 73169799Sdes */ 73278025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 733114983Sjhb ps = p->p_sigacts; 734114983Sjhb mtx_lock(&ps->ps_mtx); 735114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 736114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 737114983Sjhb mtx_unlock(&ps->ps_mtx); 73871471Sjhb PROC_UNLOCK(p); 739119068Sdes 74067588Sdes /* 74167588Sdes * Linux also prints the capability masks, but we don't have 74267588Sdes * capabilities yet, and when we do get them they're likely to 74367588Sdes * be meaningless to Linux programs, so we lie. XXX 74467588Sdes */ 74578025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 74678025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 74778025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 748119068Sdes 74978025Sdes return (0); 75067588Sdes} 75174135Sjlemon 752119911Sdes 75378113Sdes/* 754119911Sdes * Filler function for proc/pid/cwd 755119911Sdes */ 756119911Sdesstatic int 757119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 758119911Sdes{ 759119911Sdes char *fullpath = "unknown"; 760119911Sdes char *freepath = NULL; 761119911Sdes 762119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 763119911Sdes sbuf_printf(sb, "%s", fullpath); 764119911Sdes if (freepath) 765119911Sdes free(freepath, M_TEMP); 766119911Sdes return (0); 767119911Sdes} 768119911Sdes 769119911Sdes/* 770119911Sdes * Filler function for proc/pid/root 771119911Sdes */ 772119911Sdesstatic int 773119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 774119911Sdes{ 775119911Sdes struct vnode *rvp; 776119911Sdes char *fullpath = "unknown"; 777119911Sdes char *freepath = NULL; 778119911Sdes 779119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 780119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 781119911Sdes sbuf_printf(sb, "%s", fullpath); 782119911Sdes if (freepath) 783119911Sdes free(freepath, M_TEMP); 784119911Sdes return (0); 785119911Sdes} 786119911Sdes 787119911Sdes/* 78878113Sdes * Filler function for proc/pid/cmdline 78978113Sdes */ 79078025Sdesstatic int 79178113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 79278113Sdes{ 79378113Sdes struct ps_strings pstr; 794138281Scperciva char **ps_argvstr; 79578113Sdes int error, i; 79678113Sdes 79778113Sdes /* 79878113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 79978113Sdes * revert back to the old way which only implements full cmdline 80078113Sdes * for the currept process and just p->p_comm for all other 80178113Sdes * processes. 80278113Sdes * Note that if the argv is no longer available, we deliberately 80378113Sdes * don't fall back on p->p_comm or return an error: the authentic 80478113Sdes * Linux behaviour is to return zero-length in this case. 80578113Sdes */ 80678113Sdes 80794620Sjhb PROC_LOCK(p); 808127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 80994620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 81094620Sjhb PROC_UNLOCK(p); 81194620Sjhb } else if (p != td->td_proc) { 81294620Sjhb PROC_UNLOCK(p); 81394620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 81494620Sjhb } else { 81594620Sjhb PROC_UNLOCK(p); 816103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 817103767Sjake sizeof(pstr)); 81894620Sjhb if (error) 81994620Sjhb return (error); 820138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 821138281Scperciva return (E2BIG); 822138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 823138281Scperciva M_TEMP, M_WAITOK); 824138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 825138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 826138281Scperciva if (error) { 827138281Scperciva free(ps_argvstr, M_TEMP); 828138281Scperciva return (error); 829138281Scperciva } 83094620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 831138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 83294620Sjhb sbuf_printf(sb, "%c", '\0'); 83378113Sdes } 834138281Scperciva free(ps_argvstr, M_TEMP); 83578113Sdes } 83678113Sdes 83778113Sdes return (0); 83878113Sdes} 83978113Sdes 84078113Sdes/* 841116173Sobrien * Filler function for proc/pid/environ 842116173Sobrien */ 843116173Sobrienstatic int 844116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 845116173Sobrien{ 846116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 847116173Sobrien 848116173Sobrien return (0); 849116173Sobrien} 850116173Sobrien 851116173Sobrien/* 852116173Sobrien * Filler function for proc/pid/maps 853116173Sobrien */ 854116173Sobrienstatic int 855116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 856116173Sobrien{ 857121265Scognet char mebuffer[512]; 858121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 859121246Scognet vm_map_entry_t entry; 860121265Scognet vm_object_t obj, tobj, lobj; 861121265Scognet vm_ooffset_t off = 0; 862121265Scognet char *name = "", *freename = NULL; 863121265Scognet size_t len; 864121265Scognet ino_t ino; 865121265Scognet int ref_count, shadow_count, flags; 866121265Scognet int error; 867137507Sphk struct vnode *vp; 868137507Sphk struct vattr vat; 869161094Skib int locked; 870121246Scognet 871121246Scognet PROC_LOCK(p); 872121246Scognet error = p_candebug(td, p); 873121246Scognet PROC_UNLOCK(p); 874121246Scognet if (error) 875121246Scognet return (error); 876121246Scognet 877121246Scognet if (uio->uio_rw != UIO_READ) 878121246Scognet return (EOPNOTSUPP); 879121246Scognet 880121246Scognet if (uio->uio_offset != 0) 881121246Scognet return (0); 882121246Scognet 883121246Scognet error = 0; 884121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 885121246Scognet vm_map_lock_read(map); 886121246Scognet for (entry = map->header.next; 887121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 888121246Scognet entry = entry->next) { 889121265Scognet name = ""; 890121265Scognet freename = NULL; 891121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 892121246Scognet continue; 893121246Scognet obj = entry->object.vm_object; 894121246Scognet for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 895121246Scognet lobj = tobj; 896121246Scognet ino = 0; 897121246Scognet if (lobj) { 898121246Scognet VM_OBJECT_LOCK(lobj); 899121246Scognet off = IDX_TO_OFF(lobj->size); 900161094Skib if (lobj->type == OBJT_VNODE) { 901161094Skib vp = lobj->handle; 902161094Skib if (vp) 903161094Skib vref(vp); 904121246Scognet } 905161094Skib else 906161094Skib vp = NULL; 907121246Scognet flags = obj->flags; 908121246Scognet ref_count = obj->ref_count; 909121246Scognet shadow_count = obj->shadow_count; 910121246Scognet VM_OBJECT_UNLOCK(lobj); 911161094Skib if (vp) { 912161094Skib vn_fullpath(td, vp, &name, &freename); 913161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 914161094Skib vn_lock(vp, LK_SHARED | LK_RETRY, td); 915161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 916161094Skib ino = vat.va_fileid; 917161094Skib vput(vp); 918161094Skib VFS_UNLOCK_GIANT(locked); 919161094Skib } 920121246Scognet } else { 921121246Scognet flags = 0; 922121246Scognet ref_count = 0; 923121246Scognet shadow_count = 0; 924121246Scognet } 925121246Scognet 926121246Scognet /* 927121246Scognet * format: 928121246Scognet * start, end, access, offset, major, minor, inode, name. 929121246Scognet */ 930121246Scognet snprintf(mebuffer, sizeof mebuffer, 931121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 932121246Scognet (u_long)entry->start, (u_long)entry->end, 933121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 934121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 935121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 936121246Scognet "p", 937121265Scognet (u_long)off, 938121246Scognet 0, 939121246Scognet 0, 940121265Scognet (u_long)ino, 941121246Scognet *name ? " " : "", 942121246Scognet name 943121246Scognet ); 944121246Scognet if (freename) 945121246Scognet free(freename, M_TEMP); 946121246Scognet len = strlen(mebuffer); 947121246Scognet if (len > uio->uio_resid) 948121246Scognet len = uio->uio_resid; /* 949121246Scognet * XXX We should probably return 950121246Scognet * EFBIG here, as in procfs. 951121246Scognet */ 952121246Scognet error = uiomove(mebuffer, len, uio); 953121246Scognet if (error) 954121246Scognet break; 955121246Scognet } 956121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 957121246Scognet vm_map_unlock_read(map); 958121246Scognet 959121246Scognet return (error); 960121246Scognet} 961121246Scognet 962116173Sobrien/* 96378113Sdes * Filler function for proc/net/dev 96478113Sdes */ 96578025Sdesstatic int 96678025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 96774135Sjlemon{ 96885129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 96974135Sjlemon struct ifnet *ifp; 97074135Sjlemon 97185129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 97283926Sdes "Inter-", " Receive", " Transmit", " face", 97385129Sdes "bytes packets errs drop fifo frame compressed", 97483926Sdes "bytes packets errs drop fifo frame compressed"); 97574135Sjlemon 976108172Shsu IFNET_RLOCK(); 97774135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 97885129Sdes linux_ifname(ifp, ifname, sizeof ifname); 97985129Sdes sbuf_printf(sb, "%6.6s:", ifname); 98083926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 98183926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 98283926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 98383926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 98474135Sjlemon } 985108172Shsu IFNET_RUNLOCK(); 986119068Sdes 98778025Sdes return (0); 98874135Sjlemon} 98974135Sjlemon 990158311Sambrisko/* 991167159Sjkim * Filler function for proc/sys/kernel/osrelease 992167159Sjkim */ 993167159Sjkimstatic int 994167159Sjkimlinprocfs_doosrelease(PFS_FILL_ARGS) 995167159Sjkim{ 996167159Sjkim char osrelease[LINUX_MAX_UTSNAME]; 997167159Sjkim 998167159Sjkim linux_get_osrelease(td, osrelease); 999167159Sjkim sbuf_printf(sb, "%s\n", osrelease); 1000167159Sjkim 1001167159Sjkim return (0); 1002167159Sjkim} 1003167159Sjkim 1004167159Sjkim/* 1005167159Sjkim * Filler function for proc/sys/kernel/ostype 1006167159Sjkim */ 1007167159Sjkimstatic int 1008167159Sjkimlinprocfs_doostype(PFS_FILL_ARGS) 1009167159Sjkim{ 1010167159Sjkim char osname[LINUX_MAX_UTSNAME]; 1011167159Sjkim 1012167159Sjkim linux_get_osname(td, osname); 1013167159Sjkim sbuf_printf(sb, "%s\n", osname); 1014167159Sjkim 1015167159Sjkim return (0); 1016167159Sjkim} 1017167159Sjkim 1018167159Sjkim/* 1019167159Sjkim * Filler function for proc/sys/kernel/version 1020167159Sjkim */ 1021167159Sjkimstatic int 1022167159Sjkimlinprocfs_doosbuild(PFS_FILL_ARGS) 1023167159Sjkim{ 1024167159Sjkim linprocfs_osbuild(td, sb); 1025167159Sjkim sbuf_cat(sb, "\n"); 1026167159Sjkim 1027167159Sjkim return (0); 1028167159Sjkim} 1029167159Sjkim 1030167159Sjkim/* 1031164692Sjkim * Filler function for proc/sys/kernel/msgmni 1032164692Sjkim */ 1033164692Sjkimstatic int 1034164692Sjkimlinprocfs_domsgmni(PFS_FILL_ARGS) 1035164692Sjkim{ 1036164692Sjkim 1037168067Sjkim sbuf_printf(sb, "%d\n", msginfo.msgmni); 1038164692Sjkim 1039164692Sjkim return (0); 1040164692Sjkim} 1041164692Sjkim 1042164692Sjkim/* 1043163251Skeramida * Filler function for proc/sys/kernel/pid_max 1044163129Snetchild */ 1045163129Snetchildstatic int 1046163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 1047163129Snetchild{ 1048163757Snetchild 1049163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 1050163129Snetchild 1051163129Snetchild return (0); 1052163129Snetchild} 1053163129Snetchild 1054163129Snetchild/* 1055164692Sjkim * Filler function for proc/sys/kernel/sem 1056164692Sjkim */ 1057164692Sjkimstatic int 1058164692Sjkimlinprocfs_dosem(PFS_FILL_ARGS) 1059164692Sjkim{ 1060164692Sjkim 1061168067Sjkim sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1062168067Sjkim seminfo.semopm, seminfo.semmni); 1063164692Sjkim 1064164692Sjkim return (0); 1065164692Sjkim} 1066164692Sjkim 1067164692Sjkim/* 1068158311Sambrisko * Filler function for proc/scsi/device_info 1069158311Sambrisko */ 1070158311Sambriskostatic int 1071158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 1072158311Sambrisko{ 1073158311Sambrisko return (0); 1074158311Sambrisko} 1075158311Sambrisko 1076158311Sambrisko/* 1077158311Sambrisko * Filler function for proc/scsi/scsi 1078158311Sambrisko */ 1079158311Sambriskostatic int 1080158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 1081158311Sambrisko{ 1082158311Sambrisko return (0); 1083158311Sambrisko} 1084158311Sambrisko 108585538Sphkextern struct cdevsw *cdevsw[]; 108685538Sphk 108778113Sdes/* 108878113Sdes * Filler function for proc/devices 108978113Sdes */ 109078025Sdesstatic int 109178025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 109274135Sjlemon{ 1093158311Sambrisko char *char_devices; 109478025Sdes sbuf_printf(sb, "Character devices:\n"); 109574135Sjlemon 1096158311Sambrisko char_devices = linux_get_char_devices(); 1097158311Sambrisko sbuf_printf(sb, "%s", char_devices); 1098158311Sambrisko linux_free_get_char_devices(char_devices); 109974135Sjlemon 110078025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 1101119068Sdes 110278025Sdes return (0); 110374135Sjlemon} 110474135Sjlemon 110578113Sdes/* 110678113Sdes * Filler function for proc/cmdline 110778113Sdes */ 110878025Sdesstatic int 110978025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 111074135Sjlemon{ 111178025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 111278025Sdes sbuf_printf(sb, " ro root=302\n"); 111378025Sdes return (0); 111478025Sdes} 111574135Sjlemon 111683926Sdes#if 0 111778025Sdes/* 111883926Sdes * Filler function for proc/modules 111983926Sdes */ 112083926Sdesstatic int 112183926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 112283926Sdes{ 112383926Sdes struct linker_file *lf; 1124119068Sdes 112583926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 112683926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 112783926Sdes (unsigned long)lf->size, lf->refs); 112883926Sdes } 112983926Sdes return (0); 113083926Sdes} 113183926Sdes#endif 113283926Sdes 113383926Sdes/* 113485129Sdes * Constructor 113578025Sdes */ 113685129Sdesstatic int 113785129Sdeslinprocfs_init(PFS_INIT_ARGS) 113885129Sdes{ 113985129Sdes struct pfs_node *root; 114085129Sdes struct pfs_node *dir; 114174135Sjlemon 114285129Sdes root = pi->pi_root; 114378025Sdes 1144119923Sdes /* /proc/... */ 1145119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1146167482Sdes NULL, NULL, NULL, PFS_RD); 1147119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1148167482Sdes NULL, NULL, NULL, PFS_RD); 1149119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1150167482Sdes NULL, NULL, NULL, PFS_RD); 1151119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1152167482Sdes NULL, NULL, NULL, PFS_RD); 1153119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1154167482Sdes NULL, NULL, NULL, PFS_RD); 115583926Sdes#if 0 1156119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1157167482Sdes NULL, NULL, NULL, PFS_RD); 115883926Sdes#endif 1159158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1160167482Sdes NULL, NULL, NULL, PFS_RD); 1161119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1162167482Sdes NULL, NULL, NULL, PFS_RD); 116387543Sdes pfs_create_link(root, "self", &procfs_docurproc, 1164167482Sdes NULL, NULL, NULL, 0); 1165119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1166167482Sdes NULL, NULL, NULL, PFS_RD); 1167119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1168167482Sdes NULL, NULL, NULL, PFS_RD); 1169119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1170167482Sdes NULL, NULL, NULL, PFS_RD); 117178025Sdes 1172119923Sdes /* /proc/net/... */ 1173167482Sdes dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 117485129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 1175167482Sdes NULL, NULL, NULL, PFS_RD); 117678025Sdes 1177119923Sdes /* /proc/<pid>/... */ 1178167482Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 117985129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1180167482Sdes NULL, NULL, NULL, PFS_RD); 1181119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1182167482Sdes NULL, NULL, NULL, 0); 1183116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1184167482Sdes NULL, NULL, NULL, PFS_RD); 118587543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 1186167482Sdes NULL, &procfs_notsystem, NULL, 0); 1187116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1188167482Sdes NULL, NULL, NULL, PFS_RD); 118985129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 1190167482Sdes &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1191119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1192167482Sdes NULL, NULL, NULL, 0); 119385129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1194167482Sdes NULL, NULL, NULL, PFS_RD); 1195119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1196167482Sdes NULL, NULL, NULL, PFS_RD); 119785129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1198167482Sdes NULL, NULL, NULL, PFS_RD); 119985129Sdes 1200158311Sambrisko /* /proc/scsi/... */ 1201167482Sdes dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1202158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1203167482Sdes NULL, NULL, NULL, PFS_RD); 1204158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1205167482Sdes NULL, NULL, NULL, PFS_RD); 1206163129Snetchild 1207163129Snetchild /* /proc/sys/... */ 1208167482Sdes dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1209163129Snetchild /* /proc/sys/kernel/... */ 1210167482Sdes dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1211167159Sjkim pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1212167482Sdes NULL, NULL, NULL, PFS_RD); 1213167159Sjkim pfs_create_file(dir, "ostype", &linprocfs_doostype, 1214167482Sdes NULL, NULL, NULL, PFS_RD); 1215167159Sjkim pfs_create_file(dir, "version", &linprocfs_doosbuild, 1216167482Sdes NULL, NULL, NULL, PFS_RD); 1217164692Sjkim pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1218167482Sdes NULL, NULL, NULL, PFS_RD); 1219163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1220167482Sdes NULL, NULL, NULL, PFS_RD); 1221164692Sjkim pfs_create_file(dir, "sem", &linprocfs_dosem, 1222167482Sdes NULL, NULL, NULL, PFS_RD); 1223163129Snetchild 122485129Sdes return (0); 122585129Sdes} 122685129Sdes 122785129Sdes/* 122885129Sdes * Destructor 122985129Sdes */ 123085129Sdesstatic int 123185129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 123285129Sdes{ 123385129Sdes 123485129Sdes /* nothing to do, pseudofs will GC */ 123585129Sdes return (0); 123685129Sdes} 123785129Sdes 123885129SdesPSEUDOFS(linprocfs, 1); 123978025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 124078025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1241