diff options
-rw-r--r-- | sys/i386/linux/linprocfs/linprocfs.h | 147 | ||||
-rw-r--r-- | sys/i386/linux/linprocfs/linprocfs_misc.c | 519 | ||||
-rw-r--r-- | sys/i386/linux/linprocfs/linprocfs_subr.c | 388 | ||||
-rw-r--r-- | sys/i386/linux/linprocfs/linprocfs_vfsops.c | 181 | ||||
-rw-r--r-- | sys/i386/linux/linprocfs/linprocfs_vnops.c | 1055 |
5 files changed, 0 insertions, 2290 deletions
diff --git a/sys/i386/linux/linprocfs/linprocfs.h b/sys/i386/linux/linprocfs/linprocfs.h deleted file mode 100644 index fb085fe..0000000 --- a/sys/i386/linux/linprocfs/linprocfs.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav - * Copyright (c) 1999 Pierre Beyssac - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs.h 8.9 (Berkeley) 5/14/95 - * - * $FreeBSD$ - */ - -/* - * The different types of node in a procfs filesystem - */ -typedef enum { - Proot, /* the filesystem root */ - Pself, /* symbolic link for curproc */ - Pproc, /* a process-specific sub-directory */ - Pexe, /* the executable file */ - Pmem, /* the process's memory image */ - Pcmdline, /* command line */ - Pprocstat, /* the process's status */ - Pprocstatus, /* the process's status (again) */ - Pmeminfo, /* memory system statistics */ - Pcpuinfo, /* CPU model, speed and features */ - Pstat, /* kernel/system statistics */ - Puptime, /* system uptime */ - Pversion, /* system version */ -} pfstype; - -/* - * control data for the proc file system. - */ -struct pfsnode { - struct pfsnode *pfs_next; /* next on list */ - struct vnode *pfs_vnode; /* vnode associated with this pfsnode */ - pfstype pfs_type; /* type of procfs node */ - pid_t pfs_pid; /* associated process */ - u_short pfs_mode; /* mode bits for stat() */ - u_long pfs_flags; /* open flags */ - u_long pfs_fileno; /* unique file id */ - pid_t pfs_lockowner; /* pfs lock owner */ -}; - -#define PROCFS_NAMELEN 8 /* max length of a filename component */ - -/* - * Kernel stuff follows - */ -#ifdef _KERNEL -#define CNEQ(cnp, s, len) \ - ((cnp)->cn_namelen == (len) && \ - (bcmp((s), (cnp)->cn_nameptr, (len)) == 0)) - -#define KMEM_GROUP 2 - -#define PROCFS_FILENO(pid, type) \ - (((type) < Pproc) ? \ - ((type) + 2) : \ - ((((pid)+1) << 4) + ((int) (type)))) - -/* - * Convert between pfsnode vnode - */ -#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data) -#define PFSTOV(pfs) ((pfs)->pfs_vnode) - -typedef struct vfs_namemap vfs_namemap_t; -struct vfs_namemap { - const char *nm_name; - int nm_val; -}; - -int vfs_getuserstr __P((struct uio *, char *, int *)); -vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); - -/* <machine/reg.h> */ -struct reg; -struct fpreg; -struct dbreg; - -#define PFIND(pid) ((pid) ? pfind(pid) : &proc0) - -void linprocfs_exit __P((struct proc *)); -int linprocfs_freevp __P((struct vnode *)); -int linprocfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); -int linprocfs_sstep __P((struct proc *)); -void linprocfs_fix_sstep __P((struct proc *)); -#if 0 -int linprocfs_read_regs __P((struct proc *, struct reg *)); -int linprocfs_write_regs __P((struct proc *, struct reg *)); -int linprocfs_read_fpregs __P((struct proc *, struct fpreg *)); -int linprocfs_write_fpregs __P((struct proc *, struct fpreg *)); -int linprocfs_read_dbregs __P((struct proc *, struct dbreg *)); -int linprocfs_write_dbregs __P((struct proc *, struct dbreg *)); -#endif -int linprocfs_domeminfo __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_docpuinfo __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_dostat __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_douptime __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_doversion __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_doprocstat __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int linprocfs_doprocstatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); - -/* functions to check whether or not files should be displayed */ -int linprocfs_validfile __P((struct proc *)); - -#define PROCFS_LOCKED 0x01 -#define PROCFS_WANT 0x02 - -extern vop_t **linprocfs_vnodeop_p; - -int linprocfs_root __P((struct mount *, struct vnode **)); -int linprocfs_rw __P((struct vop_read_args *)); -#endif /* _KERNEL */ diff --git a/sys/i386/linux/linprocfs/linprocfs_misc.c b/sys/i386/linux/linprocfs/linprocfs_misc.c deleted file mode 100644 index 5380856..0000000 --- a/sys/i386/linux/linprocfs/linprocfs_misc.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav - * Copyright (c) 1999 Pierre Beyssac - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/blist.h> -#include <sys/dkstat.h> -#include <sys/jail.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/resourcevar.h> -#include <sys/systm.h> -#include <sys/tty.h> -#include <sys/vnode.h> - -#include <vm/vm.h> -#include <vm/pmap.h> -#include <vm/vm_map.h> -#include <vm/vm_param.h> -#include <vm/vm_object.h> -#include <vm/swap_pager.h> - -#include <sys/exec.h> -#include <sys/user.h> -#include <sys/vmmeter.h> - -#include <machine/clock.h> -#include <machine/cputypes.h> -#include <machine/md_var.h> - -#include <i386/linux/linprocfs/linprocfs.h> - -/* - * Various conversion macros - */ -#define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */ -#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ -#define B2K(x) ((x) >> 10) /* bytes to kbytes */ -#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ -#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ -#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ - -int -linprocfs_domeminfo(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - char *ps; - int xlen; - char psbuf[512]; /* XXX - conservative */ - unsigned long memtotal; /* total memory in bytes */ - unsigned long memused; /* used memory in bytes */ - unsigned long memfree; /* free memory in bytes */ - unsigned long memshared; /* shared memory ??? */ - unsigned long buffers, cached; /* buffer / cache memory ??? */ - unsigned long swaptotal; /* total swap space in bytes */ - unsigned long swapused; /* used swap space in bytes */ - unsigned long swapfree; /* free swap space in bytes */ - vm_object_t object; - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - - memtotal = physmem * PAGE_SIZE; - /* - * The correct thing here would be: - * - memfree = cnt.v_free_count * PAGE_SIZE; - memused = memtotal - memfree; - * - * but it might mislead linux binaries into thinking there - * is very little memory left, so we cheat and tell them that - * all memory that isn't wired down is free. - */ - memused = cnt.v_wire_count * PAGE_SIZE; - memfree = memtotal - memused; - if (swapblist == NULL) { - swaptotal = 0; - swapfree = 0; - } else { - swaptotal = swapblist->bl_blocks * 1024; /* XXX why 1024? */ - swapfree = swapblist->bl_root->u.bmu_avail * PAGE_SIZE; - } - swapused = swaptotal - swapfree; - memshared = 0; - for (object = TAILQ_FIRST(&vm_object_list); object != NULL; - object = TAILQ_NEXT(object, object_list)) - if (object->shadow_count > 1) - memshared += object->resident_page_count; - memshared *= PAGE_SIZE; - /* - * We'd love to be able to write: - * - buffers = bufspace; - * - * but bufspace is internal to vfs_bio.c and we don't feel - * like unstaticizing it just for linprocfs's sake. - */ - buffers = 0; - cached = cnt.v_cache_count * PAGE_SIZE; - - ps = psbuf; - ps += sprintf(ps, - " total: used: free: shared: buffers: cached:\n" - "Mem: %lu %lu %lu %lu %lu %lu\n" - "Swap: %lu %lu %lu\n" - "MemTotal: %9lu kB\n" - "MemFree: %9lu kB\n" - "MemShared:%9lu kB\n" - "Buffers: %9lu kB\n" - "Cached: %9lu kB\n" - "SwapTotal:%9lu kB\n" - "SwapFree: %9lu kB\n", - memtotal, memused, memfree, memshared, buffers, cached, - swaptotal, swapused, swapfree, - B2K(memtotal), B2K(memfree), - B2K(memshared), B2K(buffers), B2K(cached), - B2K(swaptotal), B2K(swapfree)); - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -int -linprocfs_docpuinfo(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - char *ps; - int xlen; - char psbuf[512]; /* XXX - conservative */ - int class, i, fqmhz, fqkhz; - - /* - * We default the flags to include all non-conflicting flags, - * and the Intel versions of conflicting flags. - */ - static char *flags[] = { - "fpu", "vme", "de", "pse", "tsc", - "msr", "pae", "mce", "cx8", "apic", - "sep", "sep", "mtrr", "pge", "mca", - "cmov", "pat", "pse36", "pn", "b19", - "b20", "b21", "mmxext", "mmx", "fxsr", - "xmm", "b26", "b27", "b28", "b29", - "3dnowext", "3dnow" - }; - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - - switch (cpu_class) { - case CPUCLASS_286: - class = 2; - break; - case CPUCLASS_386: - class = 3; - break; - case CPUCLASS_486: - class = 4; - break; - case CPUCLASS_586: - class = 5; - break; - case CPUCLASS_686: - class = 6; - break; - default: - class = 0; - break; - } - - ps = psbuf; - ps += sprintf(ps, - "processor\t: %d\n" - "vendor_id\t: %.20s\n" - "cpu family\t: %d\n" - "model\t\t: %d\n" - "stepping\t: %d\n", - 0, cpu_vendor, class, cpu, cpu_id & 0xf); - - ps += sprintf(ps, - "flags\t\t:"); - - if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { - flags[16] = "fcmov"; - } else if (!strcmp(cpu_vendor, "CyrixInstead")) { - flags[24] = "cxmmx"; - } - - for (i = 0; i < 32; i++) - if (cpu_feature & (1 << i)) - ps += sprintf(ps, " %s", flags[i]); - ps += sprintf(ps, "\n"); - if (class >= 5) { - fqmhz = (tsc_freq + 4999) / 1000000; - fqkhz = ((tsc_freq + 4999) / 10000) % 100; - ps += sprintf(ps, - "cpu MHz\t\t: %d.%02d\n" - "bogomips\t: %d.%02d\n", - fqmhz, fqkhz, fqmhz, fqkhz); - } - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -int -linprocfs_dostat(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - char *ps; - char psbuf[512]; - int xlen; - - ps = psbuf; - ps += sprintf(ps, - "cpu %ld %ld %ld %ld\n" - "disk 0 0 0 0\n" - "page %u %u\n" - "swap %u %u\n" - "intr %u\n" - "ctxt %u\n" - "btime %ld\n", - T2J(cp_time[CP_USER]), - T2J(cp_time[CP_NICE]), - T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), - T2J(cp_time[CP_IDLE]), - cnt.v_vnodepgsin, - cnt.v_vnodepgsout, - cnt.v_swappgsin, - cnt.v_swappgsout, - cnt.v_intr, - cnt.v_swtch, - boottime.tv_sec); - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -int -linprocfs_douptime(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - char *ps; - int xlen; - char psbuf[64]; - struct timeval tv; - - getmicrouptime(&tv); - ps = psbuf; - ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n", - tv.tv_sec, tv.tv_usec / 10000, - T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -int -linprocfs_doversion(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - char *ps; - int xlen; - - ps = version; /* XXX not entirely correct */ - for (xlen = 0; ps[xlen] != '\n'; ++xlen) - /* nothing */ ; - ++xlen; - xlen -= uio->uio_offset; - ps += uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -int -linprocfs_doprocstat(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - struct eproc ep; - char *ps, psbuf[1024]; - int xlen; - - fill_eproc(p, &ep); - ps = psbuf; - ps += sprintf(ps, "%d", p->p_pid); -#define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg) - PS_ADD("comm", "(%s)", p->p_comm); - PS_ADD("statr", "%c", '0'); /* XXX */ - PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); - PS_ADD("pgrp", "%d", p->p_pgid); - PS_ADD("session", "%d", p->p_session->s_sid); - PS_ADD("tty", "%d", 0); /* XXX */ - PS_ADD("tpgid", "%d", 0); /* XXX */ - PS_ADD("flags", "%u", 0); /* XXX */ - PS_ADD("minflt", "%u", 0); /* XXX */ - PS_ADD("cminflt", "%u", 0); /* XXX */ - PS_ADD("majflt", "%u", 0); /* XXX */ - PS_ADD("cminflt", "%u", 0); /* XXX */ - PS_ADD("utime", "%d", 0); /* XXX */ - PS_ADD("stime", "%d", 0); /* XXX */ - PS_ADD("cutime", "%d", 0); /* XXX */ - PS_ADD("cstime", "%d", 0); /* XXX */ - PS_ADD("counter", "%d", 0); /* XXX */ - PS_ADD("priority", "%d", 0); /* XXX */ - PS_ADD("timeout", "%u", 0); /* XXX */ - PS_ADD("itrealvalue", "%u", 0); /* XXX */ - PS_ADD("starttime", "%d", 0); /* XXX */ - PS_ADD("vsize", "%u", ep.e_vm.vm_map.size); - PS_ADD("rss", "%u", P2K(ep.e_vm.vm_rssize)); - PS_ADD("rlim", "%u", 0); /* XXX */ - PS_ADD("startcode", "%u", (unsigned)ep.e_vm.vm_taddr); - PS_ADD("endcode", "%u", 0); /* XXX */ - PS_ADD("startstack", "%u", 0); /* XXX */ - PS_ADD("esp", "%u", 0); /* XXX */ - PS_ADD("eip", "%u", 0); /* XXX */ - PS_ADD("signal", "%d", 0); /* XXX */ - PS_ADD("blocked", "%d", 0); /* XXX */ - PS_ADD("sigignore", "%d", 0); /* XXX */ - PS_ADD("sigcatch", "%d", 0); /* XXX */ - PS_ADD("wchan", "%u", 0); /* XXX */ - PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ - PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ - PS_ADD("exitsignal", "%d", 0); /* XXX */ - PS_ADD("processor", "%d", 0); /* XXX */ -#undef PS_ADD - ps += sprintf(ps, "\n"); - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} - -/* - * Map process state to descriptive letter. Note that this does not - * quite correspond to what Linux outputs, but it's close enough. - */ -static char *state_str[] = { - "? (unknown)", - "I (idle)", - "R (running)", - "S (sleeping)", - "T (stopped)", - "Z (zombie)", - "W (waiting)", - "M (mutex)" -}; - -int -linprocfs_doprocstatus(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; -{ - struct eproc ep; - char *ps, psbuf[1024]; - char *state; - int i, xlen; - segsz_t lsize; - - ps = psbuf; - - mtx_enter(&sched_lock, MTX_SPIN); - if (p->p_stat > sizeof state_str / sizeof *state_str) - state = state_str[0]; - else - state = state_str[(int)p->p_stat]; - mtx_exit(&sched_lock, MTX_SPIN); - - fill_eproc(p, &ep); -#define PS_ADD ps += sprintf - PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */ - PS_ADD(ps, "State:\t%s\n", state); - - /* - * Credentials - */ - PS_ADD(ps, "Pid:\t%d\n", p->p_pid); - PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0); - PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid, - p->p_ucred->cr_uid, - p->p_cred->p_svuid, - /* FreeBSD doesn't have fsuid */ - p->p_ucred->cr_uid); - PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid, - p->p_ucred->cr_gid, - p->p_cred->p_svgid, - /* FreeBSD doesn't have fsgid */ - p->p_ucred->cr_gid); - PS_ADD(ps, "Groups:\t"); - for (i = 0; i < p->p_ucred->cr_ngroups; i++) - PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]); - PS_ADD(ps, "\n"); - - /* - * Memory - * - * While our approximation of VmLib may not be accurate (I - * don't know of a simple way to verify it, and I'm not sure - * it has much meaning anyway), I believe it's good enough. - * - * The same code that could (I think) accurately compute VmLib - * could also compute VmLck, but I don't really care enough to - * implement it. Submissions are welcome. - */ - PS_ADD(ps, "VmSize:\t%8u kB\n", B2K(ep.e_vm.vm_map.size)); - PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ - PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(ep.e_vm.vm_rssize)); - PS_ADD(ps, "VmData:\t%8u kB\n", P2K(ep.e_vm.vm_dsize)); - PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(ep.e_vm.vm_ssize)); - PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(ep.e_vm.vm_tsize)); - lsize = B2P(ep.e_vm.vm_map.size) - ep.e_vm.vm_dsize - - ep.e_vm.vm_ssize - ep.e_vm.vm_tsize - 1; - PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(lsize)); - - /* - * Signal masks - * - * We support up to 128 signals, while Linux supports 32, - * but we only define 32 (the same 32 as Linux, to boot), so - * just show the lower 32 bits of each mask. XXX hack. - * - * NB: on certain platforms (Sparc at least) Linux actually - * supports 64 signals, but this code is a long way from - * running on anything but i386, so ignore that for now. - */ - PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); - /* - * I can't seem to find out where the signal mask is in - * relation to struct proc, so SigBlk is left unimplemented. - */ - PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */ - PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); - PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); - - /* - * Linux also prints the capability masks, but we don't have - * capabilities yet, and when we do get them they're likely to - * be meaningless to Linux programs, so we lie. XXX - */ - PS_ADD(ps, "CapInh:\t%016x\n", 0); - PS_ADD(ps, "CapPrm:\t%016x\n", 0); - PS_ADD(ps, "CapEff:\t%016x\n", 0); -#undef PS_ADD - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); -} diff --git a/sys/i386/linux/linprocfs/linprocfs_subr.c b/sys/i386/linux/linprocfs/linprocfs_subr.c deleted file mode 100644 index 6c215cd..0000000 --- a/sys/i386/linux/linprocfs/linprocfs_subr.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav - * Copyright (c) 1999 Pierre Beyssac - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95 - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/malloc.h> -#include <i386/linux/linprocfs/linprocfs.h> - -static struct pfsnode *pfshead; -static int pfsvplock; - -extern int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -extern int procfs_docmdline __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); - -/* - * allocate a pfsnode/vnode pair. the vnode is - * referenced, but not locked. - * - * the pid, pfs_type, and mount point uniquely - * identify a pfsnode. the mount point is needed - * because someone might mount this filesystem - * twice. - * - * all pfsnodes are maintained on a singly-linked - * list. new nodes are only allocated when they cannot - * be found on this list. entries on the list are - * removed when the vfs reclaim entry is called. - * - * a single lock is kept for the entire list. this is - * needed because the getnewvnode() function can block - * waiting for a vnode to become free, in which case there - * may be more than one process trying to get the same - * vnode. this lock is only taken if we are going to - * call getnewvnode, since the kernel itself is single-threaded. - * - * if an entry is found on the list, then call vget() to - * take a reference. this is done because there may be - * zero references to it and so it needs to removed from - * the vnode free list. - */ -int -linprocfs_allocvp(mp, vpp, pid, pfs_type) - struct mount *mp; - struct vnode **vpp; - long pid; - pfstype pfs_type; -{ - struct proc *p = curproc; /* XXX */ - struct pfsnode *pfs; - struct vnode *vp; - struct pfsnode **pp; - int error; - -loop: - for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) { - vp = PFSTOV(pfs); - if (pfs->pfs_pid == pid && - pfs->pfs_type == pfs_type && - vp->v_mount == mp) { - if (vget(vp, 0, p)) - goto loop; - *vpp = vp; - return (0); - } - } - - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - if (pfsvplock & PROCFS_LOCKED) { - pfsvplock |= PROCFS_WANT; - (void) tsleep((caddr_t) &pfsvplock, PINOD, "pfsavp", 0); - goto loop; - } - pfsvplock |= PROCFS_LOCKED; - - /* - * Do the MALLOC before the getnewvnode since doing so afterward - * might cause a bogus v_data pointer to get dereferenced - * elsewhere if MALLOC should block. - */ - MALLOC(pfs, struct pfsnode *, sizeof(struct pfsnode), M_TEMP, M_WAITOK); - - if ((error = getnewvnode(VT_PROCFS, mp, linprocfs_vnodeop_p, vpp)) != 0) { - FREE(pfs, M_TEMP); - goto out; - } - vp = *vpp; - - vp->v_data = pfs; - - pfs->pfs_next = 0; - pfs->pfs_pid = (pid_t) pid; - pfs->pfs_type = pfs_type; - pfs->pfs_vnode = vp; - pfs->pfs_flags = 0; - pfs->pfs_lockowner = 0; - pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type); - - switch (pfs_type) { - case Proot: /* /proc = dr-xr-xr-x */ - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VDIR; - vp->v_flag = VROOT; - break; - - case Pself: /* /proc/self = lr--r--r-- */ - pfs->pfs_mode = (VREAD) | - (VREAD >> 3) | - (VREAD >> 6); - vp->v_type = VLNK; - break; - - case Pproc: - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VDIR; - break; - - case Pexe: - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VLNK; - break; - - case Pmem: - pfs->pfs_mode = (VREAD|VWRITE) | - (VREAD) >> 3;; - vp->v_type = VREG; - break; - - case Pprocstat: - case Pprocstatus: - case Pcmdline: - /* fallthrough */ - - case Pmeminfo: - case Pcpuinfo: - case Pstat: - case Puptime: - case Pversion: - pfs->pfs_mode = (VREAD) | - (VREAD >> 3) | - (VREAD >> 6); - vp->v_type = VREG; - break; - - default: - panic("linprocfs_allocvp"); - } - - /* add to procfs vnode list */ - for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) - continue; - *pp = pfs; - -out: - pfsvplock &= ~PROCFS_LOCKED; - - if (pfsvplock & PROCFS_WANT) { - pfsvplock &= ~PROCFS_WANT; - wakeup((caddr_t) &pfsvplock); - } - - return (error); -} - -int -linprocfs_freevp(vp) - struct vnode *vp; -{ - struct pfsnode **pfspp; - struct pfsnode *pfs = VTOPFS(vp); - - for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) { - if (*pfspp == pfs) { - *pfspp = pfs->pfs_next; - break; - } - } - - FREE(vp->v_data, M_TEMP); - vp->v_data = 0; - return (0); -} - -int -linprocfs_rw(ap) - struct vop_read_args *ap; -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct proc *curp = uio->uio_procp; - struct pfsnode *pfs = VTOPFS(vp); - struct proc *p; - int rtval; - - p = PFIND(pfs->pfs_pid); - if (p == 0) - return (EINVAL); - if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE) - return (EACCES); - - while (pfs->pfs_lockowner) { - tsleep(&pfs->pfs_lockowner, PRIBIO, "pfslck", 0); - } - pfs->pfs_lockowner = curproc->p_pid; - - switch (pfs->pfs_type) { - case Pcmdline: - rtval = procfs_docmdline(curp, p, pfs, uio); - break; - case Pmem: - rtval = procfs_domem(curp, p, pfs, uio); - break; - case Pprocstat: - rtval = linprocfs_doprocstat(curp, p, pfs, uio); - break; - case Pprocstatus: - rtval = linprocfs_doprocstatus(curp, p, pfs, uio); - break; - case Pmeminfo: - rtval = linprocfs_domeminfo(curp, p, pfs, uio); - break; - case Pcpuinfo: - rtval = linprocfs_docpuinfo(curp, p, pfs, uio); - break; - case Pstat: - rtval = linprocfs_dostat(curp, p, pfs, uio); - break; - case Puptime: - rtval = linprocfs_douptime(curp, p, pfs, uio); - break; - case Pversion: - rtval = linprocfs_doversion(curp, p, pfs, uio); - break; - default: - rtval = EOPNOTSUPP; - break; - } - pfs->pfs_lockowner = 0; - wakeup(&pfs->pfs_lockowner); - return rtval; -} - -#if 0 -/* - * Get a string from userland into (buf). Strip a trailing - * nl character (to allow easy access from the shell). - * The buffer should be *buflenp + 1 chars long. vfs_getuserstr - * will automatically add a nul char at the end. - * - * Returns 0 on success or the following errors - * - * EINVAL: file offset is non-zero. - * EMSGSIZE: message is longer than kernel buffer - * EFAULT: user i/o buffer is not addressable - */ -int -vfs_getuserstr(uio, buf, buflenp) - struct uio *uio; - char *buf; - int *buflenp; -{ - int xlen; - int error; - - if (uio->uio_offset != 0) - return (EINVAL); - - xlen = *buflenp; - - /* must be able to read the whole string in one go */ - if (xlen < uio->uio_resid) - return (EMSGSIZE); - xlen = uio->uio_resid; - - if ((error = uiomove(buf, xlen, uio)) != 0) - return (error); - - /* allow multiple writes without seeks */ - uio->uio_offset = 0; - - /* cleanup string and remove trailing newline */ - buf[xlen] = '\0'; - xlen = strlen(buf); - if (xlen > 0 && buf[xlen-1] == '\n') - buf[--xlen] = '\0'; - *buflenp = xlen; - - return (0); -} - -vfs_namemap_t * -vfs_findname(nm, buf, buflen) - vfs_namemap_t *nm; - char *buf; - int buflen; -{ - - for (; nm->nm_name; nm++) - if (bcmp(buf, nm->nm_name, buflen+1) == 0) - return (nm); - - return (0); -} -#endif - -void -linprocfs_exit(struct proc *p) -{ - struct pfsnode *pfs; - pid_t pid = p->p_pid; - - /* - * The reason for this loop is not obvious -- basicly, - * linprocfs_freevp(), which is called via vgone() (eventually), - * removes the specified procfs node from the pfshead list. - * It does this by *pfsp = pfs->pfs_next, meaning that it - * overwrites the node. So when we do pfs = pfs->next, we - * end up skipping the node that replaces the one that was - * vgone'd. Since it may have been the last one on the list, - * it may also have been set to null -- but *our* pfs pointer, - * here, doesn't see this. So the loop starts from the beginning - * again. - * - * This is not a for() loop because the final event - * would be "pfs = pfs->pfs_next"; in the case where - * pfs is set to pfshead again, that would mean that - * pfshead is skipped over. - * - */ - pfs = pfshead; - while (pfs) { - if (pfs->pfs_pid == pid) { - vgone(PFSTOV(pfs)); - pfs = pfshead; - } else - pfs = pfs->pfs_next; - } -} diff --git a/sys/i386/linux/linprocfs/linprocfs_vfsops.c b/sys/i386/linux/linprocfs/linprocfs_vfsops.c deleted file mode 100644 index 6f2310a..0000000 --- a/sys/i386/linux/linprocfs/linprocfs_vfsops.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav - * Copyright (c) 1999 Pierre Beyssac - * Copyright (c) 1993 Jan-Simon Pendry - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95 - * - * $FreeBSD$ - */ - -/* - * procfs VFS interface - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#include <sys/mount.h> -#include <sys/vnode.h> -#include <i386/linux/linprocfs/linprocfs.h> - -static int linprocfs_mount __P((struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct proc *p)); -static int linprocfs_statfs __P((struct mount *mp, struct statfs *sbp, - struct proc *p)); -static int linprocfs_unmount __P((struct mount *mp, int mntflags, - struct proc *p)); - -/* - * VFS Operations. - * - * mount system call - */ -/* ARGSUSED */ -static int -linprocfs_mount(mp, path, data, ndp, p) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct proc *p; -{ - size_t size; - int error; - - if (mp->mnt_flag & MNT_UPDATE) - return (EOPNOTSUPP); - - if (mp->mnt_vfc->vfc_refcount == 1 && (error = at_exit(linprocfs_exit))) { - printf("linprocfs: cannot register linprocfs_exit with at_exit\n"); - return(error); - } - - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = 0; - vfs_getnewfsid(mp); - - (void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size); - bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); - - size = sizeof("linprocfs") - 1; - bcopy("linprocfs", mp->mnt_stat.f_mntfromname, size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void)linprocfs_statfs(mp, &mp->mnt_stat, p); - - return (0); -} - -/* - * unmount system call - */ -static int -linprocfs_unmount(mp, mntflags, p) - struct mount *mp; - int mntflags; - struct proc *p; -{ - int error; - int flags = 0; - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - - error = vflush(mp, 0, flags); - if (error) - return (error); - - if (mp->mnt_vfc->vfc_refcount == 1) - rm_at_exit(linprocfs_exit); - - return (0); -} - -int -linprocfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - - return (linprocfs_allocvp(mp, vpp, 0, Proot)); -} - -/* - * Get file system statistics. - */ -static int -linprocfs_statfs(mp, sbp, p) - struct mount *mp; - struct statfs *sbp; - struct proc *p; -{ - sbp->f_bsize = PAGE_SIZE; - sbp->f_iosize = PAGE_SIZE; - sbp->f_blocks = 1; /* avoid divide by zero in some df's */ - sbp->f_bfree = 0; - sbp->f_bavail = 0; - sbp->f_files = maxproc; /* approx */ - sbp->f_ffree = maxproc - nprocs; /* approx */ - - if (sbp != &mp->mnt_stat) { - sbp->f_type = mp->mnt_vfc->vfc_typenum; - bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - - return (0); -} - -static struct vfsops linprocfs_vfsops = { - linprocfs_mount, - vfs_stdstart, - linprocfs_unmount, - linprocfs_root, - vfs_stdquotactl, - linprocfs_statfs, - vfs_stdsync, - vfs_stdvget, - vfs_stdfhtovp, - vfs_stdcheckexp, - vfs_stdvptofh, - vfs_stdinit, -}; - -VFS_SET(linprocfs_vfsops, linprocfs, VFCF_SYNTHETIC); -MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); diff --git a/sys/i386/linux/linprocfs/linprocfs_vnops.c b/sys/i386/linux/linprocfs/linprocfs_vnops.c deleted file mode 100644 index 36998bd..0000000 --- a/sys/i386/linux/linprocfs/linprocfs_vnops.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav - * Copyright (c) 1999 Pierre Beyssac - * Copyright (c) 1993, 1995 Jan-Simon Pendry - * Copyright (c) 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 - * - * $FreeBSD$ - */ - -/* - * procfs vnode interface - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/time.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/signalvar.h> -#include <sys/vnode.h> -#include <sys/mount.h> -#include <sys/namei.h> -#include <sys/dirent.h> -#include <sys/malloc.h> -#include <machine/reg.h> -#include <vm/vm_zone.h> -#include <i386/linux/linprocfs/linprocfs.h> -#include <sys/pioctl.h> - -extern struct vnode *procfs_findtextvp __P((struct proc *)); -extern int procfs_kmemaccess __P((struct proc *)); - -static int linprocfs_access __P((struct vop_access_args *)); -static int linprocfs_badop __P((void)); -static int linprocfs_bmap __P((struct vop_bmap_args *)); -static int linprocfs_close __P((struct vop_close_args *)); -static int linprocfs_getattr __P((struct vop_getattr_args *)); -static int linprocfs_inactive __P((struct vop_inactive_args *)); -static int linprocfs_ioctl __P((struct vop_ioctl_args *)); -static int linprocfs_lookup __P((struct vop_lookup_args *)); -static int linprocfs_open __P((struct vop_open_args *)); -static int linprocfs_print __P((struct vop_print_args *)); -static int linprocfs_readdir __P((struct vop_readdir_args *)); -static int linprocfs_readlink __P((struct vop_readlink_args *)); -static int linprocfs_reclaim __P((struct vop_reclaim_args *)); -static int linprocfs_setattr __P((struct vop_setattr_args *)); - -/* - * This is a list of the valid names in the - * process-specific sub-directories. It is - * used in linprocfs_lookup and linprocfs_readdir - */ -static struct proc_target { - u_char pt_type; - u_char pt_namlen; - char *pt_name; - pfstype pt_pfstype; - int (*pt_valid) __P((struct proc *p)); -} proc_targets[] = { -#define N(s) sizeof(s)-1, s - /* name type validp */ - { DT_DIR, N("."), Pproc, NULL }, - { DT_DIR, N(".."), Proot, NULL }, - { DT_REG, N("cmdline"), Pcmdline, NULL }, - { DT_LNK, N("exe"), Pexe, NULL }, - { DT_REG, N("mem"), Pmem, NULL }, - { DT_REG, N("stat"), Pprocstat, NULL }, - { DT_REG, N("status"), Pprocstatus, NULL }, -#undef N -}; -static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); - -static pid_t atopid __P((const char *, u_int)); - -/* - * set things up for doing i/o on - * the pfsnode (vp). (vp) is locked - * on entry, and should be left locked - * on exit. - * - * for procfs we don't need to do anything - * in particular for i/o. all that is done - * is to support exclusive open on process - * memory images. - */ -static int -linprocfs_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct proc *p1, *p2; - - p2 = PFIND(pfs->pfs_pid); - if (p2 == NULL) - return (ENOENT); - if (pfs->pfs_pid && p_can(ap->a_p, p2, P_CAN_SEE, NULL)) - return (ENOENT); - - switch (pfs->pfs_type) { - case Pmem: - if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || - ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) - return (EBUSY); - - p1 = ap->a_p; - if (p_can(p1, p2, P_CAN_DEBUG, NULL) && - !procfs_kmemaccess(p1)) - return (EPERM); - - if (ap->a_mode & FWRITE) - pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); - - return (0); - - default: - break; - } - - return (0); -} - -/* - * close the pfsnode (vp) after doing i/o. - * (vp) is not locked on entry or exit. - * - * nothing to do for procfs other than undo - * any exclusive open flag (see _open above). - */ -static int -linprocfs_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct proc *p; - - switch (pfs->pfs_type) { - case Pmem: - if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) - pfs->pfs_flags &= ~(FWRITE|O_EXCL); - /* - * If this is the last close, then it checks to see if - * the target process has PF_LINGER set in p_pfsflags, - * if this is *not* the case, then the process' stop flags - * are cleared, and the process is woken up. This is - * to help prevent the case where a process has been - * told to stop on an event, but then the requesting process - * has gone away or forgotten about it. - */ - if ((ap->a_vp->v_usecount < 2) - && (p = pfind(pfs->pfs_pid)) - && !(p->p_pfsflags & PF_LINGER)) { - p->p_stops = 0; - p->p_step = 0; - wakeup(&p->p_step); - } - break; - default: - break; - } - - return (0); -} - -/* - * do an ioctl operation on a pfsnode (vp). - * (vp) is not locked on entry or exit. - */ -static int -linprocfs_ioctl(ap) - struct vop_ioctl_args *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct proc *procp, *p; - int error; - int signo; - struct procfs_status *psp; - unsigned char flags; - - p = ap->a_p; - procp = pfind(pfs->pfs_pid); - if (procp == NULL) - return ENOTTY; - - if ((error = p_can(p, procp, P_CAN_DEBUG, NULL))) - return (error == ESRCH ? ENOENT : error); - - switch (ap->a_command) { - case PIOCBIS: - procp->p_stops |= *(unsigned int*)ap->a_data; - break; - case PIOCBIC: - procp->p_stops &= ~*(unsigned int*)ap->a_data; - break; - case PIOCSFL: - /* - * NFLAGS is "non-suser_xxx flags" -- currently, only - * PFS_ISUGID ("ignore set u/g id"); - */ -#define NFLAGS (PF_ISUGID) - flags = (unsigned char)*(unsigned int*)ap->a_data; - if (flags & NFLAGS && (error = suser(p))) - return error; - procp->p_pfsflags = flags; - break; - case PIOCGFL: - *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags; - case PIOCSTATUS: - psp = (struct procfs_status *)ap->a_data; - psp->state = (procp->p_step == 0); - psp->flags = procp->p_pfsflags; - psp->events = procp->p_stops; - if (procp->p_step) { - psp->why = procp->p_stype; - psp->val = procp->p_xstat; - } else { - psp->why = psp->val = 0; /* Not defined values */ - } - break; - case PIOCWAIT: - psp = (struct procfs_status *)ap->a_data; - if (procp->p_step == 0) { - error = tsleep(&procp->p_stype, PWAIT | PCATCH, "piocwait", 0); - if (error) - return error; - } - psp->state = 1; /* It stopped */ - psp->flags = procp->p_pfsflags; - psp->events = procp->p_stops; - psp->why = procp->p_stype; /* why it stopped */ - psp->val = procp->p_xstat; /* any extra info */ - break; - case PIOCCONT: /* Restart a proc */ - if (procp->p_step == 0) - return EINVAL; /* Can only start a stopped process */ - if ((signo = *(int*)ap->a_data) != 0) { - if (signo >= NSIG || signo <= 0) - return EINVAL; - psignal(procp, signo); - } - procp->p_step = 0; - wakeup(&procp->p_step); - break; - default: - return (ENOTTY); - } - return 0; -} - -/* - * do block mapping for pfsnode (vp). - * since we don't use the buffer cache - * for procfs this function should never - * be called. in any case, it's not clear - * what part of the kernel ever makes use - * of this function. for sanity, this is the - * usual no-op bmap, although returning - * (EIO) would be a reasonable alternative. - */ -static int -linprocfs_bmap(ap) - struct vop_bmap_args /* { - struct vnode *a_vp; - daddr_t a_bn; - struct vnode **a_vpp; - daddr_t *a_bnp; - int *a_runp; - } */ *ap; -{ - - if (ap->a_vpp != NULL) - *ap->a_vpp = ap->a_vp; - if (ap->a_bnp != NULL) - *ap->a_bnp = ap->a_bn; - if (ap->a_runp != NULL) - *ap->a_runp = 0; - return (0); -} - -/* - * linprocfs_inactive is called when the pfsnode - * is vrele'd and the reference count goes - * to zero. (vp) will be on the vnode free - * list, so to get it back vget() must be - * used. - * - * (vp) is locked on entry, but must be unlocked on exit. - */ -static int -linprocfs_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - - VOP_UNLOCK(vp, 0, ap->a_p); - - return (0); -} - -/* - * _reclaim is called when getnewvnode() - * wants to make use of an entry on the vnode - * free list. at this time the filesystem needs - * to free any private data and remove the node - * from any private lists. - */ -static int -linprocfs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (linprocfs_freevp(ap->a_vp)); -} - -/* - * _print is used for debugging. - * just print a readable description - * of (vp). - */ -static int -linprocfs_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - - printf("tag VT_PROCFS, type %d, pid %ld, mode %x, flags %lx\n", - pfs->pfs_type, (long)pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); - return (0); -} - -/* - * generic entry point for unsupported operations - */ -static int -linprocfs_badop() -{ - - return (EIO); -} - -/* - * Invent attributes for pfsnode (vp) and store - * them in (vap). - * Directories lengths are returned as zero since - * any real length would require the genuine size - * to be computed, and nothing cares anyway. - * - * this is relatively minimal for procfs. - */ -static int -linprocfs_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct vattr *vap = ap->a_vap; - struct proc *procp; - int error; - - /* - * First make sure that the process and its credentials - * still exist. - */ - switch (pfs->pfs_type) { - case Proot: - case Pself: - procp = 0; - break; - - default: - procp = PFIND(pfs->pfs_pid); - if (procp == 0 || procp->p_cred == NULL || - procp->p_ucred == NULL) - return (ENOENT); - - if (p_can(ap->a_p, procp, P_CAN_SEE, NULL)) - return (ENOENT); - } - - error = 0; - - /* start by zeroing out the attributes */ - VATTR_NULL(vap); - - /* next do all the common fields */ - vap->va_type = ap->a_vp->v_type; - vap->va_mode = pfs->pfs_mode; - vap->va_fileid = pfs->pfs_fileno; - vap->va_flags = 0; - vap->va_blocksize = PAGE_SIZE; - vap->va_bytes = vap->va_size = 0; - vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; - - /* - * Make all times be current TOD. - * It would be possible to get the process start - * time from the p_stat structure, but there's - * no "file creation" time stamp anyway, and the - * p_stat structure is not addressible if u. gets - * swapped out for that process. - */ - nanotime(&vap->va_ctime); - vap->va_atime = vap->va_mtime = vap->va_ctime; - - /* - * If the process has exercised some setuid or setgid - * privilege, then rip away read/write permission so - * that only root can gain access. - */ - switch (pfs->pfs_type) { - case Pmem: - /* Retain group kmem readablity. */ - if (procp->p_flag & P_SUGID) - vap->va_mode &= ~(VREAD|VWRITE); - break; - default: - break; - } - - /* - * now do the object specific fields - * - * The size could be set from struct reg, but it's hardly - * worth the trouble, and it puts some (potentially) machine - * dependent data into this machine-independent code. If it - * becomes important then this function should break out into - * a per-file stat function in the corresponding .c file. - */ - - vap->va_nlink = 1; - if (procp) { - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = procp->p_ucred->cr_gid; - } - - switch (pfs->pfs_type) { - case Proot: - /* - * Set nlink to 1 to tell fts(3) we don't actually know. - */ - vap->va_nlink = 1; - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_size = vap->va_bytes = DEV_BSIZE; - break; - - case Pself: { - char buf[16]; /* should be enough */ - vap->va_uid = 0; - vap->va_gid = 0; - vap->va_size = vap->va_bytes = - snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); - break; - } - - case Pproc: - vap->va_nlink = nproc_targets; - vap->va_size = vap->va_bytes = DEV_BSIZE; - break; - - case Pexe: { - char *fullpath, *freepath; - error = textvp_fullpath(procp, &fullpath, &freepath); - if (error == 0) { - vap->va_size = strlen(fullpath); - free(freepath, M_TEMP); - } else { - vap->va_size = sizeof("unknown") - 1; - error = 0; - } - vap->va_bytes = vap->va_size; - break; - } - - case Pmeminfo: - case Pcpuinfo: - case Pstat: - case Puptime: - case Pversion: - vap->va_bytes = vap->va_size = 0; - vap->va_uid = 0; - vap->va_gid = 0; - break; - - case Pmem: - /* - * If we denied owner access earlier, then we have to - * change the owner to root - otherwise 'ps' and friends - * will break even though they are setgid kmem. *SIGH* - */ - if (procp->p_flag & P_SUGID) - vap->va_uid = 0; - else - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = KMEM_GROUP; - break; - - case Pcmdline: - case Pprocstat: - case Pprocstatus: - vap->va_bytes = vap->va_size = 0; - /* uid, gid are already set */ - break; - - default: - panic("linprocfs_getattr"); - } - - return (error); -} - -static int -linprocfs_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - - if (ap->a_vap->va_flags != VNOVAL) - return (EOPNOTSUPP); - - /* - * just fake out attribute setting - * it's not good to generate an error - * return, otherwise things like creat() - * will fail when they try to set the - * file length to 0. worse, this means - * that echo $note > /proc/$pid/note will fail. - */ - - return (0); -} - -/* - * implement access checking. - * - * actually, the check for super-user is slightly - * broken since it will allow read access to write-only - * objects. this doesn't cause any particular trouble - * but does mean that the i/o entry points need to check - * that the operation really does make sense. - */ -static int -linprocfs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct vnode *vp = ap->a_vp; - struct proc *procp; - struct vattr *vap; - struct vattr vattr; - int error; - - switch (pfs->pfs_type) { - case Proot: - case Pself: - case Pmeminfo: - case Pcpuinfo: - case Pstat: - case Puptime: - case Pversion: - break; - default: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL) - return (ENOENT); - if (p_can(ap->a_p, procp, P_CAN_SEE, NULL)) - return (ENOENT); - } - - vap = &vattr; - error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); - if (error) - return (error); - - return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, - ap->a_mode, ap->a_cred, NULL)); -} - -/* - * lookup. this is incredibly complicated in the - * general case, however for most pseudo-filesystems - * very little needs to be done. - * - * unless you want to get a migraine, just make sure your - * filesystem doesn't do any locking of its own. otherwise - * read and inwardly digest ufs_lookup(). - */ -static int -linprocfs_lookup(ap) - struct vop_lookup_args /* { - struct vnode * a_dvp; - struct vnode ** a_vpp; - struct componentname * a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct proc *curp = cnp->cn_proc; - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct proc_target *pt; - pid_t pid; - struct pfsnode *pfs; - struct proc *p; - int i; - - *vpp = NULL; - - if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME || - cnp->cn_nameiop == CREATE) - return (EROFS); - - if (cnp->cn_namelen == 1 && *pname == '.') { - *vpp = dvp; - VREF(dvp); - /* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */ - return (0); - } - - pfs = VTOPFS(dvp); - switch (pfs->pfs_type) { - case Proot: - if (cnp->cn_flags & ISDOTDOT) - return (EIO); - - if (CNEQ(cnp, "self", 4)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pself)); - if (CNEQ(cnp, "meminfo", 7)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmeminfo)); - if (CNEQ(cnp, "cpuinfo", 7)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo)); - if (CNEQ(cnp, "stat", 4)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat)); - if (CNEQ(cnp, "uptime", 6)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Puptime)); - if (CNEQ(cnp, "version", 7)) - return (linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion)); - - pid = atopid(pname, cnp->cn_namelen); - if (pid == NO_PID) - break; - - p = PFIND(pid); - if (p == 0) - break; - - if (p_can(curp, p, P_CAN_SEE, NULL)) - break; - - return (linprocfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); - - case Pproc: - if (cnp->cn_flags & ISDOTDOT) - return (linprocfs_root(dvp->v_mount, vpp)); - - p = PFIND(pfs->pfs_pid); - if (p == 0) - break; - - for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { - if (cnp->cn_namelen == pt->pt_namlen && - bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && - (pt->pt_valid == NULL || (*pt->pt_valid)(p))) - goto found; - } - break; - - found: - return (linprocfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, - pt->pt_pfstype)); - - default: - return (ENOTDIR); - } - - return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); -} - -/* - * Does this process have a text file? - */ -int -linprocfs_validfile(p) - struct proc *p; -{ - - return (procfs_findtextvp(p) != NULLVP); -} - -/* - * readdir() returns directory entries from pfsnode (vp). - * - * We generate just one directory entry at a time, as it would probably - * not pay off to buffer several entries locally to save uiomove calls. - */ -static int -linprocfs_readdir(ap) - struct vop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - int *a_eofflag; - int *a_ncookies; - u_long **a_cookies; - } */ *ap; -{ - struct uio *uio = ap->a_uio; - struct dirent d; - struct dirent *dp = &d; - struct pfsnode *pfs; - int count, error, i, off; - static u_int delen; - - if (!delen) { - - d.d_namlen = PROCFS_NAMELEN; - delen = GENERIC_DIRSIZ(&d); - } - - pfs = VTOPFS(ap->a_vp); - - off = (int)uio->uio_offset; - if (off != uio->uio_offset || off < 0 || - off % delen != 0 || uio->uio_resid < delen) - return (EINVAL); - - error = 0; - count = 0; - i = off / delen; - - switch (pfs->pfs_type) { - /* - * this is for the process-specific sub-directories. - * all that is needed to is copy out all the entries - * from the procent[] table (top of this file). - */ - case Pproc: { - struct proc *p; - struct proc_target *pt; - - p = PFIND(pfs->pfs_pid); - if (p == NULL) - break; - if (p_can(curproc, p, P_CAN_SEE, NULL)) - break; - - for (pt = &proc_targets[i]; - uio->uio_resid >= delen && i < nproc_targets; pt++, i++) { - if (pt->pt_valid && (*pt->pt_valid)(p) == 0) - continue; - - dp->d_reclen = delen; - dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); - dp->d_namlen = pt->pt_namlen; - bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); - dp->d_type = pt->pt_type; - - if ((error = uiomove((caddr_t)dp, delen, uio)) != 0) - break; - } - - break; - } - - /* - * this is for the root of the procfs filesystem - * what is needed is a special entry for "self" - * followed by an entry for each process on allproc -#ifdef PROCFS_ZOMBIE - * and zombproc. -#endif - */ - - case Proot: { -#ifdef PROCFS_ZOMBIE - int doingzomb = 0; -#endif - int pcnt = 0; - struct proc *p = allproc.lh_first; - - for (; p && uio->uio_resid >= delen; i++, pcnt++) { - bzero((char *) dp, delen); - dp->d_reclen = delen; - - switch (i) { - case 0: /* `.' */ - case 1: /* `..' */ - dp->d_fileno = PROCFS_FILENO(0, Proot); - dp->d_namlen = i + 1; - bcopy("..", dp->d_name, dp->d_namlen); - dp->d_name[i + 1] = '\0'; - dp->d_type = DT_DIR; - break; - - case 2: - dp->d_fileno = PROCFS_FILENO(0, Pself); - dp->d_namlen = 4; - bcopy("self", dp->d_name, 5); - dp->d_type = DT_LNK; - break; - - case 3: - dp->d_fileno = PROCFS_FILENO(0, Pmeminfo); - dp->d_namlen = 7; - bcopy("meminfo", dp->d_name, 8); - dp->d_type = DT_REG; - break; - - case 4: - dp->d_fileno = PROCFS_FILENO(0, Pcpuinfo); - dp->d_namlen = 7; - bcopy("cpuinfo", dp->d_name, 8); - dp->d_type = DT_REG; - break; - - case 5: - dp->d_fileno = PROCFS_FILENO(0, Pstat); - dp->d_namlen = 4; - bcopy("stat", dp->d_name, 5); - dp->d_type = DT_REG; - break; - - case 6: - dp->d_fileno = PROCFS_FILENO(0, Puptime); - dp->d_namlen = 6; - bcopy("uptime", dp->d_name, 7); - dp->d_type = DT_REG; - break; - - case 7: - dp->d_fileno = PROCFS_FILENO(0, Pversion); - dp->d_namlen = 7; - bcopy("version", dp->d_name, 8); - dp->d_type = DT_REG; - break; - - default: - while (pcnt < i) { - p = p->p_list.le_next; - if (!p) - goto done; - if (p_can(curproc, p, P_CAN_SEE, NULL)) - continue; - pcnt++; - } - while (p_can(curproc, p, P_CAN_SEE, NULL)) { - p = p->p_list.le_next; - if (!p) - goto done; - } - dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); - dp->d_namlen = sprintf(dp->d_name, "%ld", - (long)p->p_pid); - dp->d_type = DT_DIR; - p = p->p_list.le_next; - break; - } - - if ((error = uiomove((caddr_t)dp, delen, uio)) != 0) - break; - } - done: - -#ifdef PROCFS_ZOMBIE - if (p == 0 && doingzomb == 0) { - doingzomb = 1; - p = zombproc.lh_first; - goto again; - } -#endif - - break; - - } - - default: - error = ENOTDIR; - break; - } - - uio->uio_offset = i * delen; - - return (error); -} - -/* - * readlink reads the link of `self' or `exe' - */ -static int -linprocfs_readlink(ap) - struct vop_readlink_args *ap; -{ - char buf[16]; /* should be enough */ - struct proc *procp; - struct vnode *vp = ap->a_vp; - struct pfsnode *pfs = VTOPFS(vp); - char *fullpath, *freepath; - int error, len; - - switch (pfs->pfs_type) { - case Pself: - if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself)) - return (EINVAL); - - len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); - - return (uiomove(buf, len, ap->a_uio)); - /* - * There _should_ be no way for an entire process to disappear - * from under us... - */ - case Pexe: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL || procp->p_cred == NULL || - procp->p_ucred == NULL) { - printf("linprocfs_readlink: pid %d disappeared\n", - pfs->pfs_pid); - return (uiomove("unknown", sizeof("unknown") - 1, - ap->a_uio)); - } - error = textvp_fullpath(procp, &fullpath, &freepath); - if (error != 0) - return (uiomove("unknown", sizeof("unknown") - 1, - ap->a_uio)); - error = uiomove(fullpath, strlen(fullpath), ap->a_uio); - free(freepath, M_TEMP); - return (error); - default: - return (EINVAL); - } -} - -/* - * convert decimal ascii to pid_t - */ -static pid_t -atopid(b, len) - const char *b; - u_int len; -{ - pid_t p = 0; - - while (len--) { - char c = *b++; - if (c < '0' || c > '9') - return (NO_PID); - p = 10 * p + (c - '0'); - if (p > PID_MAX) - return (NO_PID); - } - - return (p); -} - -/* - * procfs vnode operations. - */ -vop_t **linprocfs_vnodeop_p; -static struct vnodeopv_entry_desc linprocfs_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_defaultop }, - { &vop_access_desc, (vop_t *) linprocfs_access }, - { &vop_advlock_desc, (vop_t *) linprocfs_badop }, - { &vop_bmap_desc, (vop_t *) linprocfs_bmap }, - { &vop_close_desc, (vop_t *) linprocfs_close }, - { &vop_create_desc, (vop_t *) linprocfs_badop }, - { &vop_getattr_desc, (vop_t *) linprocfs_getattr }, - { &vop_inactive_desc, (vop_t *) linprocfs_inactive }, - { &vop_link_desc, (vop_t *) linprocfs_badop }, - { &vop_lookup_desc, (vop_t *) linprocfs_lookup }, - { &vop_mkdir_desc, (vop_t *) linprocfs_badop }, - { &vop_mknod_desc, (vop_t *) linprocfs_badop }, - { &vop_open_desc, (vop_t *) linprocfs_open }, - { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, - { &vop_print_desc, (vop_t *) linprocfs_print }, - { &vop_read_desc, (vop_t *) linprocfs_rw }, - { &vop_readdir_desc, (vop_t *) linprocfs_readdir }, - { &vop_readlink_desc, (vop_t *) linprocfs_readlink }, - { &vop_reclaim_desc, (vop_t *) linprocfs_reclaim }, - { &vop_remove_desc, (vop_t *) linprocfs_badop }, - { &vop_rename_desc, (vop_t *) linprocfs_badop }, - { &vop_rmdir_desc, (vop_t *) linprocfs_badop }, - { &vop_setattr_desc, (vop_t *) linprocfs_setattr }, - { &vop_symlink_desc, (vop_t *) linprocfs_badop }, - { &vop_write_desc, (vop_t *) linprocfs_rw }, - { &vop_ioctl_desc, (vop_t *) linprocfs_ioctl }, - { NULL, NULL } -}; -static struct vnodeopv_desc linprocfs_vnodeop_opv_desc = - { &linprocfs_vnodeop_p, linprocfs_vnodeop_entries }; - -VNODEOP_SET(linprocfs_vnodeop_opv_desc); |