linprocfs.c revision 163129
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 163129 2006-10-08 16:55:27Z netchild $"); 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 */ 124159995Snetchildstatic 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/* 41978113Sdes * Filler function for proc/version 42078113Sdes */ 42178025Sdesstatic int 42278025Sdeslinprocfs_doversion(PFS_FILL_ARGS) 42365633Sdes{ 42487275Srwatson char osname[LINUX_MAX_UTSNAME]; 42587275Srwatson char osrelease[LINUX_MAX_UTSNAME]; 42687275Srwatson 427112206Sjhb linux_get_osname(td, osname); 428112206Sjhb linux_get_osrelease(td, osrelease); 42987275Srwatson 43078025Sdes sbuf_printf(sb, 43169995Sdes "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 43287275Srwatson " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 43378025Sdes return (0); 43465633Sdes} 43565633Sdes 43678113Sdes/* 43778113Sdes * Filler function for proc/loadavg 43878113Sdes */ 43978025Sdesstatic int 44078025Sdeslinprocfs_doloadavg(PFS_FILL_ARGS) 44176839Sjlemon{ 44278025Sdes sbuf_printf(sb, 44376839Sjlemon "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 44476839Sjlemon (int)(averunnable.ldavg[0] / averunnable.fscale), 44576839Sjlemon (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 44676839Sjlemon (int)(averunnable.ldavg[1] / averunnable.fscale), 44776839Sjlemon (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 44876839Sjlemon (int)(averunnable.ldavg[2] / averunnable.fscale), 44976839Sjlemon (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 45076839Sjlemon 1, /* number of running tasks */ 45176839Sjlemon nprocs, /* number of tasks */ 45278116Sdes lastpid /* the last pid */ 45376839Sjlemon ); 454119068Sdes 45578025Sdes return (0); 45676839Sjlemon} 45776839Sjlemon 45878113Sdes/* 45978113Sdes * Filler function for proc/pid/stat 46078113Sdes */ 46178025Sdesstatic int 46278025Sdeslinprocfs_doprocstat(PFS_FILL_ARGS) 46367588Sdes{ 46469995Sdes struct kinfo_proc kp; 46567588Sdes 46694307Sjhb PROC_LOCK(p); 46769995Sdes fill_kinfo_proc(p, &kp); 46878025Sdes sbuf_printf(sb, "%d", p->p_pid); 46978025Sdes#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 47067588Sdes PS_ADD("comm", "(%s)", p->p_comm); 471159995Snetchild KASSERT(kp.ki_stat <= sizeof(linux_state), 472159995Snetchild ("linprocfs: don't know how to handle unknown FreeBSD state")); 473159995Snetchild PS_ADD("state", "%c", linux_state[kp.ki_stat - 1]); 47473923Sjhb PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 47567588Sdes PS_ADD("pgrp", "%d", p->p_pgid); 47667588Sdes PS_ADD("session", "%d", p->p_session->s_sid); 47791140Stanimura PROC_UNLOCK(p); 47867588Sdes PS_ADD("tty", "%d", 0); /* XXX */ 479159995Snetchild PS_ADD("tpgid", "%d", kp.ki_tpgid); 48067588Sdes PS_ADD("flags", "%u", 0); /* XXX */ 481159995Snetchild PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 482159995Snetchild PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 483159995Snetchild PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 484159995Snetchild PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 485159995Snetchild PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 486159995Snetchild PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 487159995Snetchild PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 488159995Snetchild PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 489159995Snetchild PS_ADD("priority", "%d", kp.ki_pri.pri_user); 490159995Snetchild PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 491159995Snetchild PS_ADD("0", "%d", 0); /* removed field */ 492159995Snetchild PS_ADD("itrealvalue", "%d", 0); /* XXX */ 493159995Snetchild /* XXX: starttime is not right, it is the _same_ for _every_ process. 494159995Snetchild It should be the number of jiffies between system boot and process 495159995Snetchild start. */ 496159995Snetchild PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 497159995Snetchild PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 498159995Snetchild PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 499159995Snetchild PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 50069995Sdes PS_ADD("startcode", "%u", (unsigned)0); 50167588Sdes PS_ADD("endcode", "%u", 0); /* XXX */ 50267588Sdes PS_ADD("startstack", "%u", 0); /* XXX */ 503159995Snetchild PS_ADD("kstkesp", "%u", 0); /* XXX */ 504159995Snetchild PS_ADD("kstkeip", "%u", 0); /* XXX */ 505159995Snetchild PS_ADD("signal", "%u", 0); /* XXX */ 506159995Snetchild PS_ADD("blocked", "%u", 0); /* XXX */ 507159995Snetchild PS_ADD("sigignore", "%u", 0); /* XXX */ 508159995Snetchild PS_ADD("sigcatch", "%u", 0); /* XXX */ 50967588Sdes PS_ADD("wchan", "%u", 0); /* XXX */ 510159995Snetchild PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 511159995Snetchild PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 51269799Sdes PS_ADD("exitsignal", "%d", 0); /* XXX */ 513159995Snetchild PS_ADD("processor", "%u", kp.ki_lastcpu); 514159995Snetchild PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 515159995Snetchild PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 51667588Sdes#undef PS_ADD 51778025Sdes sbuf_putc(sb, '\n'); 518119068Sdes 51978025Sdes return (0); 52067588Sdes} 52167588Sdes 52267588Sdes/* 523119911Sdes * Filler function for proc/pid/statm 524119911Sdes */ 525119911Sdesstatic int 526119911Sdeslinprocfs_doprocstatm(PFS_FILL_ARGS) 527119911Sdes{ 528119911Sdes struct kinfo_proc kp; 529119911Sdes segsz_t lsize; 530120340Sdes 531119911Sdes PROC_LOCK(p); 532119911Sdes fill_kinfo_proc(p, &kp); 533119911Sdes PROC_UNLOCK(p); 534119911Sdes 535119911Sdes /* 536119911Sdes * See comments in linprocfs_doprocstatus() regarding the 537119911Sdes * computation of lsize. 538119911Sdes */ 539119911Sdes /* size resident share trs drs lrs dt */ 540119911Sdes sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 541119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 542119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 543119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 544119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 545119911Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 546119911Sdes kp.ki_ssize - kp.ki_tsize - 1; 547119911Sdes sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 548119911Sdes sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 549119911Sdes 550119911Sdes return (0); 551119911Sdes} 552119911Sdes 553119911Sdes/* 55478113Sdes * Filler function for proc/pid/status 55578113Sdes */ 55678025Sdesstatic int 55778025Sdeslinprocfs_doprocstatus(PFS_FILL_ARGS) 55867588Sdes{ 55969995Sdes struct kinfo_proc kp; 56067588Sdes char *state; 56169799Sdes segsz_t lsize; 56299072Sjulian struct thread *td2; 563114983Sjhb struct sigacts *ps; 56474135Sjlemon int i; 56567588Sdes 566113611Sjhb PROC_LOCK(p); 56799072Sjulian td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 56899072Sjulian 56999072Sjulian if (P_SHOULDSTOP(p)) { 57099072Sjulian state = "T (stopped)"; 57199072Sjulian } else { 572113611Sjhb mtx_lock_spin(&sched_lock); 57399072Sjulian switch(p->p_state) { 57499072Sjulian case PRS_NEW: 57599072Sjulian state = "I (idle)"; 57699072Sjulian break; 57799072Sjulian case PRS_NORMAL: 57899072Sjulian if (p->p_flag & P_WEXIT) { 57999072Sjulian state = "X (exiting)"; 58099072Sjulian break; 58199072Sjulian } 58299072Sjulian switch(td2->td_state) { 583103216Sjulian case TDS_INHIBITED: 58499072Sjulian state = "S (sleeping)"; 58599072Sjulian break; 58699072Sjulian case TDS_RUNQ: 58799072Sjulian case TDS_RUNNING: 58899072Sjulian state = "R (running)"; 58999072Sjulian break; 59099072Sjulian default: 59199072Sjulian state = "? (unknown)"; 59299072Sjulian break; 59399072Sjulian } 59499072Sjulian break; 59599072Sjulian case PRS_ZOMBIE: 59699072Sjulian state = "Z (zombie)"; 59799072Sjulian break; 59899072Sjulian default: 59999072Sjulian state = "? (unknown)"; 60099072Sjulian break; 60199072Sjulian } 602113611Sjhb mtx_unlock_spin(&sched_lock); 60399072Sjulian } 60467588Sdes 60569995Sdes fill_kinfo_proc(p, &kp); 60678025Sdes sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 60778031Sdes sbuf_printf(sb, "State:\t%s\n", state); 60867588Sdes 60967588Sdes /* 61067588Sdes * Credentials 61167588Sdes */ 61278025Sdes sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 61378025Sdes sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 61473923Sjhb p->p_pptr->p_pid : 0); 61578031Sdes sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 61678031Sdes p->p_ucred->cr_uid, 61778031Sdes p->p_ucred->cr_svuid, 61878031Sdes /* FreeBSD doesn't have fsuid */ 61978031Sdes p->p_ucred->cr_uid); 62078031Sdes sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 62178031Sdes p->p_ucred->cr_gid, 62278031Sdes p->p_ucred->cr_svgid, 62378031Sdes /* FreeBSD doesn't have fsgid */ 62478031Sdes p->p_ucred->cr_gid); 62578025Sdes sbuf_cat(sb, "Groups:\t"); 62667588Sdes for (i = 0; i < p->p_ucred->cr_ngroups; i++) 62778031Sdes sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 62871471Sjhb PROC_UNLOCK(p); 62978025Sdes sbuf_putc(sb, '\n'); 630119068Sdes 63167588Sdes /* 63267588Sdes * Memory 63369799Sdes * 63469799Sdes * While our approximation of VmLib may not be accurate (I 63569799Sdes * don't know of a simple way to verify it, and I'm not sure 63669799Sdes * it has much meaning anyway), I believe it's good enough. 63769799Sdes * 63869799Sdes * The same code that could (I think) accurately compute VmLib 63969799Sdes * could also compute VmLck, but I don't really care enough to 64069799Sdes * implement it. Submissions are welcome. 64167588Sdes */ 642113574Sjhb sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 64378025Sdes sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 644113574Sjhb sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 645113574Sjhb sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 646113574Sjhb sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 647113574Sjhb sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 64869995Sdes lsize = B2P(kp.ki_size) - kp.ki_dsize - 64969995Sdes kp.ki_ssize - kp.ki_tsize - 1; 650113574Sjhb sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 65167588Sdes 65267588Sdes /* 65367588Sdes * Signal masks 65467588Sdes * 65567588Sdes * We support up to 128 signals, while Linux supports 32, 65667588Sdes * but we only define 32 (the same 32 as Linux, to boot), so 65767588Sdes * just show the lower 32 bits of each mask. XXX hack. 65867588Sdes * 65967588Sdes * NB: on certain platforms (Sparc at least) Linux actually 66067588Sdes * supports 64 signals, but this code is a long way from 66167588Sdes * running on anything but i386, so ignore that for now. 66267588Sdes */ 66371471Sjhb PROC_LOCK(p); 664104306Sjmallett sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 66569799Sdes /* 66669799Sdes * I can't seem to find out where the signal mask is in 66769799Sdes * relation to struct proc, so SigBlk is left unimplemented. 66869799Sdes */ 66978025Sdes sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 670114983Sjhb ps = p->p_sigacts; 671114983Sjhb mtx_lock(&ps->ps_mtx); 672114983Sjhb sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 673114983Sjhb sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 674114983Sjhb mtx_unlock(&ps->ps_mtx); 67571471Sjhb PROC_UNLOCK(p); 676119068Sdes 67767588Sdes /* 67867588Sdes * Linux also prints the capability masks, but we don't have 67967588Sdes * capabilities yet, and when we do get them they're likely to 68067588Sdes * be meaningless to Linux programs, so we lie. XXX 68167588Sdes */ 68278025Sdes sbuf_printf(sb, "CapInh:\t%016x\n", 0); 68378025Sdes sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 68478025Sdes sbuf_printf(sb, "CapEff:\t%016x\n", 0); 685119068Sdes 68678025Sdes return (0); 68767588Sdes} 68874135Sjlemon 689119911Sdes 69078113Sdes/* 691119911Sdes * Filler function for proc/pid/cwd 692119911Sdes */ 693119911Sdesstatic int 694119911Sdeslinprocfs_doproccwd(PFS_FILL_ARGS) 695119911Sdes{ 696119911Sdes char *fullpath = "unknown"; 697119911Sdes char *freepath = NULL; 698119911Sdes 699119911Sdes vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 700119911Sdes sbuf_printf(sb, "%s", fullpath); 701119911Sdes if (freepath) 702119911Sdes free(freepath, M_TEMP); 703119911Sdes return (0); 704119911Sdes} 705119911Sdes 706119911Sdes/* 707119911Sdes * Filler function for proc/pid/root 708119911Sdes */ 709119911Sdesstatic int 710119911Sdeslinprocfs_doprocroot(PFS_FILL_ARGS) 711119911Sdes{ 712119911Sdes struct vnode *rvp; 713119911Sdes char *fullpath = "unknown"; 714119911Sdes char *freepath = NULL; 715119911Sdes 716119911Sdes rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 717119911Sdes vn_fullpath(td, rvp, &fullpath, &freepath); 718119911Sdes sbuf_printf(sb, "%s", fullpath); 719119911Sdes if (freepath) 720119911Sdes free(freepath, M_TEMP); 721119911Sdes return (0); 722119911Sdes} 723119911Sdes 724119911Sdes/* 72578113Sdes * Filler function for proc/pid/cmdline 72678113Sdes */ 72778025Sdesstatic int 72878113Sdeslinprocfs_doproccmdline(PFS_FILL_ARGS) 72978113Sdes{ 73078113Sdes struct ps_strings pstr; 731138281Scperciva char **ps_argvstr; 73278113Sdes int error, i; 73378113Sdes 73478113Sdes /* 73578113Sdes * If we are using the ps/cmdline caching, use that. Otherwise 73678113Sdes * revert back to the old way which only implements full cmdline 73778113Sdes * for the currept process and just p->p_comm for all other 73878113Sdes * processes. 73978113Sdes * Note that if the argv is no longer available, we deliberately 74078113Sdes * don't fall back on p->p_comm or return an error: the authentic 74178113Sdes * Linux behaviour is to return zero-length in this case. 74278113Sdes */ 74378113Sdes 74494620Sjhb PROC_LOCK(p); 745127694Spjd if (p->p_args && p_cansee(td, p) == 0) { 74694620Sjhb sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 74794620Sjhb PROC_UNLOCK(p); 74894620Sjhb } else if (p != td->td_proc) { 74994620Sjhb PROC_UNLOCK(p); 75094620Sjhb sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 75194620Sjhb } else { 75294620Sjhb PROC_UNLOCK(p); 753103767Sjake error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 754103767Sjake sizeof(pstr)); 75594620Sjhb if (error) 75694620Sjhb return (error); 757138281Scperciva if (pstr.ps_nargvstr > ARG_MAX) 758138281Scperciva return (E2BIG); 759138281Scperciva ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 760138281Scperciva M_TEMP, M_WAITOK); 761138281Scperciva error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 762138281Scperciva pstr.ps_nargvstr * sizeof(char *)); 763138281Scperciva if (error) { 764138281Scperciva free(ps_argvstr, M_TEMP); 765138281Scperciva return (error); 766138281Scperciva } 76794620Sjhb for (i = 0; i < pstr.ps_nargvstr; i++) { 768138281Scperciva sbuf_copyin(sb, ps_argvstr[i], 0); 76994620Sjhb sbuf_printf(sb, "%c", '\0'); 77078113Sdes } 771138281Scperciva free(ps_argvstr, M_TEMP); 77278113Sdes } 77378113Sdes 77478113Sdes return (0); 77578113Sdes} 77678113Sdes 77778113Sdes/* 778116173Sobrien * Filler function for proc/pid/environ 779116173Sobrien */ 780116173Sobrienstatic int 781116173Sobrienlinprocfs_doprocenviron(PFS_FILL_ARGS) 782116173Sobrien{ 783116173Sobrien sbuf_printf(sb, "doprocenviron\n%c", '\0'); 784116173Sobrien 785116173Sobrien return (0); 786116173Sobrien} 787116173Sobrien 788116173Sobrien/* 789116173Sobrien * Filler function for proc/pid/maps 790116173Sobrien */ 791116173Sobrienstatic int 792116173Sobrienlinprocfs_doprocmaps(PFS_FILL_ARGS) 793116173Sobrien{ 794121265Scognet char mebuffer[512]; 795121246Scognet vm_map_t map = &p->p_vmspace->vm_map; 796121246Scognet vm_map_entry_t entry; 797121265Scognet vm_object_t obj, tobj, lobj; 798121265Scognet vm_ooffset_t off = 0; 799121265Scognet char *name = "", *freename = NULL; 800121265Scognet size_t len; 801121265Scognet ino_t ino; 802121265Scognet int ref_count, shadow_count, flags; 803121265Scognet int error; 804137507Sphk struct vnode *vp; 805137507Sphk struct vattr vat; 806161094Skib int locked; 807121246Scognet 808121246Scognet PROC_LOCK(p); 809121246Scognet error = p_candebug(td, p); 810121246Scognet PROC_UNLOCK(p); 811121246Scognet if (error) 812121246Scognet return (error); 813121246Scognet 814121246Scognet if (uio->uio_rw != UIO_READ) 815121246Scognet return (EOPNOTSUPP); 816121246Scognet 817121246Scognet if (uio->uio_offset != 0) 818121246Scognet return (0); 819121246Scognet 820121246Scognet error = 0; 821121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 822121246Scognet vm_map_lock_read(map); 823121246Scognet for (entry = map->header.next; 824121246Scognet ((uio->uio_resid > 0) && (entry != &map->header)); 825121246Scognet entry = entry->next) { 826121265Scognet name = ""; 827121265Scognet freename = NULL; 828121246Scognet if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 829121246Scognet continue; 830121246Scognet obj = entry->object.vm_object; 831121246Scognet for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 832121246Scognet lobj = tobj; 833121246Scognet ino = 0; 834121246Scognet if (lobj) { 835121246Scognet VM_OBJECT_LOCK(lobj); 836121246Scognet off = IDX_TO_OFF(lobj->size); 837161094Skib if (lobj->type == OBJT_VNODE) { 838161094Skib vp = lobj->handle; 839161094Skib if (vp) 840161094Skib vref(vp); 841121246Scognet } 842161094Skib else 843161094Skib vp = NULL; 844121246Scognet flags = obj->flags; 845121246Scognet ref_count = obj->ref_count; 846121246Scognet shadow_count = obj->shadow_count; 847121246Scognet VM_OBJECT_UNLOCK(lobj); 848161094Skib if (vp) { 849161094Skib vn_fullpath(td, vp, &name, &freename); 850161094Skib locked = VFS_LOCK_GIANT(vp->v_mount); 851161094Skib vn_lock(vp, LK_SHARED | LK_RETRY, td); 852161094Skib VOP_GETATTR(vp, &vat, td->td_ucred, td); 853161094Skib ino = vat.va_fileid; 854161094Skib vput(vp); 855161094Skib VFS_UNLOCK_GIANT(locked); 856161094Skib } 857121246Scognet } else { 858121246Scognet flags = 0; 859121246Scognet ref_count = 0; 860121246Scognet shadow_count = 0; 861121246Scognet } 862121246Scognet 863121246Scognet /* 864121246Scognet * format: 865121246Scognet * start, end, access, offset, major, minor, inode, name. 866121246Scognet */ 867121246Scognet snprintf(mebuffer, sizeof mebuffer, 868121246Scognet "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 869121246Scognet (u_long)entry->start, (u_long)entry->end, 870121246Scognet (entry->protection & VM_PROT_READ)?"r":"-", 871121246Scognet (entry->protection & VM_PROT_WRITE)?"w":"-", 872121246Scognet (entry->protection & VM_PROT_EXECUTE)?"x":"-", 873121246Scognet "p", 874121265Scognet (u_long)off, 875121246Scognet 0, 876121246Scognet 0, 877121265Scognet (u_long)ino, 878121246Scognet *name ? " " : "", 879121246Scognet name 880121246Scognet ); 881121246Scognet if (freename) 882121246Scognet free(freename, M_TEMP); 883121246Scognet len = strlen(mebuffer); 884121246Scognet if (len > uio->uio_resid) 885121246Scognet len = uio->uio_resid; /* 886121246Scognet * XXX We should probably return 887121246Scognet * EFBIG here, as in procfs. 888121246Scognet */ 889121246Scognet error = uiomove(mebuffer, len, uio); 890121246Scognet if (error) 891121246Scognet break; 892121246Scognet } 893121246Scognet if (map != &curthread->td_proc->p_vmspace->vm_map) 894121246Scognet vm_map_unlock_read(map); 895121246Scognet 896121246Scognet return (error); 897121246Scognet} 898121246Scognet 899116173Sobrien/* 90078113Sdes * Filler function for proc/net/dev 90178113Sdes */ 90278025Sdesstatic int 90378025Sdeslinprocfs_donetdev(PFS_FILL_ARGS) 90474135Sjlemon{ 90585129Sdes char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 90674135Sjlemon struct ifnet *ifp; 90774135Sjlemon 90885129Sdes sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 90983926Sdes "Inter-", " Receive", " Transmit", " face", 91085129Sdes "bytes packets errs drop fifo frame compressed", 91183926Sdes "bytes packets errs drop fifo frame compressed"); 91274135Sjlemon 913108172Shsu IFNET_RLOCK(); 91474135Sjlemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 91585129Sdes linux_ifname(ifp, ifname, sizeof ifname); 91685129Sdes sbuf_printf(sb, "%6.6s:", ifname); 91783926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 91883926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 91983926Sdes sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 92083926Sdes 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 92174135Sjlemon } 922108172Shsu IFNET_RUNLOCK(); 923119068Sdes 92478025Sdes return (0); 92574135Sjlemon} 92674135Sjlemon 927158311Sambrisko/* 928163129Snetchild * Filler function for proc/pid_max 929163129Snetchild */ 930163129Snetchildstatic int 931163129Snetchildlinprocfs_dopid_max(PFS_FILL_ARGS) 932163129Snetchild{ 933163129Snetchild sbuf_printf(sb, "%i\n", PID_MAX); 934163129Snetchild 935163129Snetchild return (0); 936163129Snetchild} 937163129Snetchild 938163129Snetchild/* 939158311Sambrisko * Filler function for proc/scsi/device_info 940158311Sambrisko */ 941158311Sambriskostatic int 942158311Sambriskolinprocfs_doscsidevinfo(PFS_FILL_ARGS) 943158311Sambrisko{ 944158311Sambrisko return (0); 945158311Sambrisko} 946158311Sambrisko 947158311Sambrisko/* 948158311Sambrisko * Filler function for proc/scsi/scsi 949158311Sambrisko */ 950158311Sambriskostatic int 951158311Sambriskolinprocfs_doscsiscsi(PFS_FILL_ARGS) 952158311Sambrisko{ 953158311Sambrisko return (0); 954158311Sambrisko} 955158311Sambrisko 95685538Sphkextern struct cdevsw *cdevsw[]; 95785538Sphk 95878113Sdes/* 95978113Sdes * Filler function for proc/devices 96078113Sdes */ 96178025Sdesstatic int 96278025Sdeslinprocfs_dodevices(PFS_FILL_ARGS) 96374135Sjlemon{ 964158311Sambrisko char *char_devices; 96578025Sdes sbuf_printf(sb, "Character devices:\n"); 96674135Sjlemon 967158311Sambrisko char_devices = linux_get_char_devices(); 968158311Sambrisko sbuf_printf(sb, "%s", char_devices); 969158311Sambrisko linux_free_get_char_devices(char_devices); 97074135Sjlemon 97178025Sdes sbuf_printf(sb, "\nBlock devices:\n"); 972119068Sdes 97378025Sdes return (0); 97474135Sjlemon} 97574135Sjlemon 97678113Sdes/* 97778113Sdes * Filler function for proc/cmdline 97878113Sdes */ 97978025Sdesstatic int 98078025Sdeslinprocfs_docmdline(PFS_FILL_ARGS) 98174135Sjlemon{ 98278025Sdes sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 98378025Sdes sbuf_printf(sb, " ro root=302\n"); 98478025Sdes return (0); 98578025Sdes} 98674135Sjlemon 98783926Sdes#if 0 98878025Sdes/* 98983926Sdes * Filler function for proc/modules 99083926Sdes */ 99183926Sdesstatic int 99283926Sdeslinprocfs_domodules(PFS_FILL_ARGS) 99383926Sdes{ 99483926Sdes struct linker_file *lf; 995119068Sdes 99683926Sdes TAILQ_FOREACH(lf, &linker_files, link) { 99783926Sdes sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 99883926Sdes (unsigned long)lf->size, lf->refs); 99983926Sdes } 100083926Sdes return (0); 100183926Sdes} 100283926Sdes#endif 100383926Sdes 100483926Sdes/* 100585129Sdes * Constructor 100678025Sdes */ 100785129Sdesstatic int 100885129Sdeslinprocfs_init(PFS_INIT_ARGS) 100985129Sdes{ 101085129Sdes struct pfs_node *root; 101185129Sdes struct pfs_node *dir; 101274135Sjlemon 101385129Sdes root = pi->pi_root; 101478025Sdes 1015119923Sdes /* /proc/... */ 1016119911Sdes pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1017119911Sdes NULL, NULL, PFS_RD); 1018119911Sdes pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1019119911Sdes NULL, NULL, PFS_RD); 1020119911Sdes pfs_create_file(root, "devices", &linprocfs_dodevices, 1021119911Sdes NULL, NULL, PFS_RD); 1022119911Sdes pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1023119911Sdes NULL, NULL, PFS_RD); 1024119911Sdes pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1025119911Sdes NULL, NULL, PFS_RD); 102683926Sdes#if 0 1027119911Sdes pfs_create_file(root, "modules", &linprocfs_domodules, 1028119911Sdes NULL, NULL, PFS_RD); 102983926Sdes#endif 1030158311Sambrisko pfs_create_file(root, "mounts", &linprocfs_domtab, 1031158311Sambrisko NULL, NULL, PFS_RD); 1032119911Sdes pfs_create_file(root, "mtab", &linprocfs_domtab, 1033119911Sdes NULL, NULL, PFS_RD); 103487543Sdes pfs_create_link(root, "self", &procfs_docurproc, 103585129Sdes NULL, NULL, 0); 1036119911Sdes pfs_create_file(root, "stat", &linprocfs_dostat, 1037119911Sdes NULL, NULL, PFS_RD); 1038119911Sdes pfs_create_file(root, "uptime", &linprocfs_douptime, 1039119911Sdes NULL, NULL, PFS_RD); 1040119911Sdes pfs_create_file(root, "version", &linprocfs_doversion, 1041119911Sdes NULL, NULL, PFS_RD); 104278025Sdes 1043119923Sdes /* /proc/net/... */ 104485129Sdes dir = pfs_create_dir(root, "net", NULL, NULL, 0); 104585129Sdes pfs_create_file(dir, "dev", &linprocfs_donetdev, 104685129Sdes NULL, NULL, PFS_RD); 104778025Sdes 1048119923Sdes /* /proc/<pid>/... */ 104985129Sdes dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 105085129Sdes pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 105185129Sdes NULL, NULL, PFS_RD); 1052119911Sdes pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1053119911Sdes NULL, NULL, 0); 1054116173Sobrien pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1055116173Sobrien NULL, NULL, PFS_RD); 105687543Sdes pfs_create_link(dir, "exe", &procfs_doprocfile, 105787543Sdes NULL, &procfs_notsystem, 0); 1058116173Sobrien pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1059116173Sobrien NULL, NULL, PFS_RD); 106085129Sdes pfs_create_file(dir, "mem", &procfs_doprocmem, 106185129Sdes &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1062119911Sdes pfs_create_link(dir, "root", &linprocfs_doprocroot, 1063119911Sdes NULL, NULL, 0); 106485129Sdes pfs_create_file(dir, "stat", &linprocfs_doprocstat, 106585129Sdes NULL, NULL, PFS_RD); 1066119911Sdes pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1067119911Sdes NULL, NULL, PFS_RD); 106885129Sdes pfs_create_file(dir, "status", &linprocfs_doprocstatus, 106985129Sdes NULL, NULL, PFS_RD); 107085129Sdes 1071158311Sambrisko /* /proc/scsi/... */ 1072158311Sambrisko dir = pfs_create_dir(root, "scsi", NULL, NULL, 0); 1073158311Sambrisko pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1074158311Sambrisko NULL, NULL, PFS_RD); 1075158311Sambrisko pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1076158311Sambrisko NULL, NULL, PFS_RD); 1077163129Snetchild 1078163129Snetchild /* /proc/sys/... */ 1079163129Snetchild dir = pfs_create_dir(root, "sys", NULL, NULL, 0); 1080163129Snetchild /* /proc/sys/kernel/... */ 1081163129Snetchild dir = pfs_create_dir(dir, "kernel", NULL, NULL, 0); 1082163129Snetchild pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1083163129Snetchild NULL, NULL, PFS_RD); 1084163129Snetchild 108585129Sdes return (0); 108685129Sdes} 108785129Sdes 108885129Sdes/* 108985129Sdes * Destructor 109085129Sdes */ 109185129Sdesstatic int 109285129Sdeslinprocfs_uninit(PFS_INIT_ARGS) 109385129Sdes{ 109485129Sdes 109585129Sdes /* nothing to do, pseudofs will GC */ 109685129Sdes return (0); 109785129Sdes} 109885129Sdes 109985129SdesPSEUDOFS(linprocfs, 1); 110078025SdesMODULE_DEPEND(linprocfs, linux, 1, 1, 1); 110178025SdesMODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1102