From 3a669c52a81fa52a7c3aa5ac06ef6f1da5981db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Tue, 4 Dec 2001 01:35:06 +0000 Subject: [PATCH] Pseudofsize procfs(5). --- sys/conf/files | 5 +- sys/fs/procfs/procfs.c | 198 +++++ sys/fs/procfs/procfs.h | 119 +-- sys/fs/procfs/procfs_ctl.c | 61 +- sys/fs/procfs/procfs_dbregs.c | 23 +- sys/fs/procfs/procfs_fpregs.c | 20 +- sys/fs/procfs/procfs_ioctl.c | 132 ++++ sys/fs/procfs/procfs_map.c | 37 +- sys/fs/procfs/procfs_mem.c | 16 +- sys/fs/procfs/procfs_note.c | 26 +- sys/fs/procfs/procfs_regs.c | 21 +- sys/fs/procfs/procfs_rlimit.c | 47 +- sys/fs/procfs/procfs_status.c | 160 +--- sys/fs/procfs/procfs_subr.c | 413 ----------- sys/fs/procfs/procfs_type.c | 41 +- sys/fs/procfs/procfs_vfsops.c | 177 ----- sys/fs/procfs/procfs_vnops.c | 1023 -------------------------- sys/modules/Makefile | 1 - sys/modules/fs/Makefile | 1 + sys/modules/{ => fs}/procfs/Makefile | 8 +- 20 files changed, 484 insertions(+), 2045 deletions(-) create mode 100644 sys/fs/procfs/procfs.c create mode 100644 sys/fs/procfs/procfs_ioctl.c delete mode 100644 sys/fs/procfs/procfs_subr.c delete mode 100644 sys/fs/procfs/procfs_vfsops.c delete mode 100644 sys/fs/procfs/procfs_vnops.c rename sys/modules/{ => fs}/procfs/Makefile (72%) diff --git a/sys/conf/files b/sys/conf/files index 7c2407d92754..6238eb3e6533 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -644,19 +644,18 @@ fs/nwfs/nwfs_vfsops.c optional nwfs fs/nwfs/nwfs_vnops.c optional nwfs fs/portalfs/portal_vfsops.c optional portalfs fs/portalfs/portal_vnops.c optional portalfs +fs/procfs/procfs.c optional procfs fs/procfs/procfs_ctl.c optional procfs fs/procfs/procfs_dbregs.c optional procfs fs/procfs/procfs_fpregs.c optional procfs +fs/procfs/procfs_ioctl.c optional procfs fs/procfs/procfs_map.c optional procfs fs/procfs/procfs_mem.c optional procfs fs/procfs/procfs_note.c optional procfs fs/procfs/procfs_regs.c optional procfs fs/procfs/procfs_rlimit.c optional procfs fs/procfs/procfs_status.c optional procfs -fs/procfs/procfs_subr.c optional procfs fs/procfs/procfs_type.c optional procfs -fs/procfs/procfs_vfsops.c optional procfs -fs/procfs/procfs_vnops.c optional procfs fs/pseudofs/pseudofs.c optional pseudofs fs/pseudofs/pseudofs_fileno.c optional pseudofs fs/pseudofs/pseudofs_vncache.c optional pseudofs diff --git a/sys/fs/procfs/procfs.c b/sys/fs/procfs/procfs.c new file mode 100644 index 000000000000..e4883d4567b3 --- /dev/null +++ b/sys/fs/procfs/procfs.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2001 Dag-Erling Smørgrav + * 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$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* + * Filler function for proc/pid/self + */ +static int +procfs_doprocfile(PFS_FILL_ARGS) +{ + char *fullpath = "unknown"; + char *freepath = NULL; + + vn_fullpath(td, td->td_proc->p_textvp, &fullpath, &freepath); + sbuf_printf(sb, "%s", fullpath); + if (freepath) + free(freepath, M_TEMP); + return (0); +} + +/* + * Filler function for proc/curproc + */ +static int +procfs_docurproc(PFS_FILL_ARGS) +{ + sbuf_printf(sb, "%ld", (long)td->td_proc->p_pid); + return (0); +} + +/* + * Adjust mode for some nodes that need it + */ +int +procfs_attr(PFS_ATTR_ARGS) +{ + /* XXX inefficient, split into separate functions */ + if (strcmp(pn->pn_name, "ctl") == 0 || + strcmp(pn->pn_name, "note") == 0 || + strcmp(pn->pn_name, "notepg") == 0) + vap->va_mode = 0200; + else if (strcmp(pn->pn_name, "mem") == 0 || + strcmp(pn->pn_name, "regs") == 0 || + strcmp(pn->pn_name, "dbregs") == 0 || + strcmp(pn->pn_name, "fpregs") == 0) + vap->va_mode = 0600; + + /* p is locked by caller */ + vap->va_uid = p->p_ucred->cr_uid; + vap->va_gid = p->p_ucred->cr_gid; + + return (0); +} + +/* + * Visibility: some files only exist for non-system processes + * Non-static because linprocfs uses it. + */ +int +procfs_notsystem(PFS_VIS_ARGS) +{ + return ((p->p_flag & P_SYSTEM) == 0); +} + +/* + * Visibility: some files are only visible to process that can debug + * the target process. + */ +int +procfs_candebug(PFS_VIS_ARGS) +{ + return ((p->p_flag & P_SYSTEM) == 0 && + p_candebug(td->td_proc, p) == 0); +} + +/* + * Constructor + */ +static int +procfs_init(PFS_INIT_ARGS) +{ + struct pfs_node *root; + struct pfs_node *dir; + struct pfs_node *node; + + root = pi->pi_root; + + pfs_create_link(root, "curproc", &procfs_docurproc, + NULL, NULL, 0); + + dir = pfs_create_dir(root, "pid", + &procfs_attr, NULL, PFS_PROCDEP); + pfs_create_file(dir, "cmdline", &procfs_doproccmdline, + NULL, NULL, PFS_RD); + pfs_create_file(dir, "ctl", &procfs_doprocctl, + &procfs_attr, NULL, PFS_WR); + pfs_create_file(dir, "dbregs", &procfs_doprocdbregs, + &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); + pfs_create_file(dir, "etype", &procfs_doproctype, + NULL, NULL, PFS_RD); + pfs_create_file(dir, "fpregs", &procfs_doprocfpregs, + &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); + pfs_create_file(dir, "map", &procfs_doprocmap, + NULL, &procfs_notsystem, PFS_RD); + node = pfs_create_file(dir, "mem", &procfs_doprocmem, + &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); +#ifdef PROCFS_DEBUG + node->pn_ioctl = &procfs_ioctl; + node->pn_close = &procfs_close; +#endif + pfs_create_file(dir, "note", &procfs_doprocnote, + &procfs_attr, &procfs_candebug, PFS_WR); + pfs_create_file(dir, "notepg", &procfs_doprocnote, + &procfs_attr, &procfs_candebug, PFS_WR); + pfs_create_file(dir, "regs", &procfs_doprocregs, + &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); + pfs_create_file(dir, "rlimit", &procfs_doprocrlimit, + NULL, NULL, PFS_RD); + pfs_create_file(dir, "status", &procfs_doprocstatus, + NULL, NULL, PFS_RD); + + pfs_create_link(dir, "file", &procfs_doprocfile, + NULL, procfs_notsystem, 0); + + return (0); +} + +/* + * Destructor + */ +static int +procfs_uninit(PFS_INIT_ARGS) +{ + + /* nothing to do, pseudofs will GC */ + return (0); +} + +PSEUDOFS(procfs, 1); diff --git a/sys/fs/procfs/procfs.h b/sys/fs/procfs/procfs.h index 67af4be6b792..059cab8a27b9 100644 --- a/sys/fs/procfs/procfs.h +++ b/sys/fs/procfs/procfs.h @@ -40,109 +40,30 @@ * $FreeBSD$ */ -/* - * The different types of node in a procfs filesystem - */ -typedef enum { - Proot, /* the filesystem root */ - Pcurproc, /* symbolic link for curproc */ - Pproc, /* a process-specific sub-directory */ - Pfile, /* the executable file */ - Pmem, /* the process's memory image */ - Pregs, /* the process's register set */ - Pfpregs, /* the process's FP register set */ - Pdbregs, /* the process's debug register set */ - Pctl, /* process control */ - Pstatus, /* process status */ - Pnote, /* process notifier */ - Pnotepg, /* process group notifier */ - Pmap, /* memory map */ - Ptype, /* executable type */ - Pcmdline, /* command line */ - Prlimit /* resource limits */ -} 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_NOTELEN 64 /* max length of a note (/proc/$pid/note) */ -#define PROCFS_CTLLEN 8 /* max length of a ctl msg (/proc/$pid/ctl */ -#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 PROCFS_FILENO(pid, type) \ - (((type) < Pproc) ? \ - ((type) + 2) : \ - ((((pid)+1) << 4) + ((int) (type)))) +int procfs_doproccmdline(PFS_FILL_ARGS); +int procfs_doprocctl(PFS_FILL_ARGS); +int procfs_doprocdbregs(PFS_FILL_ARGS); +int procfs_doprocfpregs(PFS_FILL_ARGS); +int procfs_doprocmap(PFS_FILL_ARGS); +int procfs_doprocmem(PFS_FILL_ARGS); +int procfs_doprocnote(PFS_FILL_ARGS); +int procfs_doprocregs(PFS_FILL_ARGS); +int procfs_doprocrlimit(PFS_FILL_ARGS); +int procfs_doprocstatus(PFS_FILL_ARGS); +int procfs_doproctype(PFS_FILL_ARGS); +int procfs_ioctl(PFS_IOCTL_ARGS); +int procfs_close(PFS_CLOSE_ARGS); -/* - * Convert between pfsnode vnode - */ -#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data) -#define PFSTOV(pfs) ((pfs)->pfs_vnode) +/* Return 1 if process has special kernel digging privileges */ +int procfs_kmemaccess(struct proc *); -typedef struct vfs_namemap vfs_namemap_t; -struct vfs_namemap { - const char *nm_name; - int nm_val; -}; +/* Attributes */ +int procfs_attr(PFS_ATTR_ARGS); -int vfs_getuserstr __P((struct uio *, char *, int *)); -vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); +/* Visbility */ +int procfs_notsystem(PFS_VIS_ARGS); +int procfs_candebug(PFS_VIS_ARGS); -/* */ -struct reg; -struct fpreg; -struct dbreg; - -#define PFIND(pid) (pfind(pid)) - -void procfs_exit __P((struct proc *)); -int procfs_freevp __P((struct vnode *)); -int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); -int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dodbregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_docmdline __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); -int procfs_dorlimit __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); - -/* functions to check whether or not files should be displayed */ -int procfs_validfile __P((struct thread *)); -int procfs_validfpregs __P((struct thread *)); -int procfs_validregs __P((struct thread *)); -int procfs_validdbregs __P((struct thread *)); -int procfs_validmap __P((struct thread *)); -int procfs_validtype __P((struct thread *)); - -#define PROCFS_LOCKED 0x01 -#define PROCFS_WANT 0x02 - -extern vop_t **procfs_vnodeop_p; - -int procfs_root __P((struct mount *, struct vnode **)); -int procfs_rw __P((struct vop_read_args *)); #endif /* _KERNEL */ diff --git a/sys/fs/procfs/procfs_ctl.c b/sys/fs/procfs/procfs_ctl.c index 2dcae24071bc..d4c37fe471c8 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/procfs/procfs_ctl.c @@ -44,10 +44,12 @@ #include #include #include +#include #include #include -#include +#include +#include #include #include @@ -67,7 +69,12 @@ #define PROCFS_CTL_RUN 4 #define PROCFS_CTL_WAIT 5 -static vfs_namemap_t ctlnames[] = { +struct namemap { + const char *nm_name; + int nm_val; +}; + +static struct namemap ctlnames[] = { /* special /proc commands */ { "attach", PROCFS_CTL_ATTACH }, { "detach", PROCFS_CTL_DETACH }, @@ -77,7 +84,7 @@ static vfs_namemap_t ctlnames[] = { { 0 }, }; -static vfs_namemap_t signames[] = { +static struct namemap signames[] = { /* regular signal names */ { "hup", SIGHUP }, { "int", SIGINT }, { "quit", SIGQUIT }, { "ill", SIGILL }, @@ -101,10 +108,7 @@ static vfs_namemap_t signames[] = { static int procfs_control __P((struct proc *curp, struct proc *p, int op)); static int -procfs_control(curp, p, op) - struct proc *curp; - struct proc *p; - int op; +procfs_control(struct proc *curp, struct proc *p, int op) { int error = 0; @@ -240,7 +244,6 @@ procfs_control(curp, p, op) * Step. Let the target process execute a single instruction. */ case PROCFS_CTL_STEP: - _PHOLD(p); PROC_UNLOCK(p); error = proc_sstep(&p->p_thread); /* XXXKSE */ PRELE(p); @@ -301,26 +304,26 @@ procfs_control(curp, p, op) return (0); } -int -procfs_doctl(curp, p, pfs, uio) - struct proc *curp; - struct pfsnode *pfs; - struct uio *uio; - struct proc *p; +static struct namemap * +findname(struct namemap *nm, char *buf, int buflen) +{ + + for (; nm->nm_name; nm++) + if (bcmp(buf, nm->nm_name, buflen+1) == 0) + return (nm); + + return (0); +} + +int +procfs_doprocctl(PFS_FILL_ARGS) { - int xlen; int error; - char msg[PROCFS_CTLLEN+1]; - vfs_namemap_t *nm; + struct namemap *nm; - if (uio->uio_rw != UIO_WRITE) + if (uio == NULL || uio->uio_rw != UIO_WRITE) return (EOPNOTSUPP); - xlen = PROCFS_CTLLEN; - error = vfs_getuserstr(uio, msg, &xlen); - if (error) - return (error); - /* * Map signal names into signal generation * or debug control. Unknown commands and/or signals @@ -332,15 +335,19 @@ procfs_doctl(curp, p, pfs, uio) */ error = EOPNOTSUPP; - nm = vfs_findname(ctlnames, msg, xlen); + sbuf_trim(sb); + sbuf_finish(sb); + nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb)); if (nm) { - error = procfs_control(curp, p, nm->nm_val); + printf("procfs: got a %s command\n", sbuf_data(sb)); + error = procfs_control(td->td_proc, p, nm->nm_val); } else { - nm = vfs_findname(signames, msg, xlen); + nm = findname(signames, sbuf_data(sb), sbuf_len(sb)); if (nm) { + printf("procfs: got a sig%s\n", sbuf_data(sb)); PROC_LOCK(p); mtx_lock_spin(&sched_lock); - if (TRACE_WAIT_P(curp, p)) { + if (TRACE_WAIT_P(td->td_proc, p)) { p->p_xstat = nm->nm_val; #ifdef FIX_SSTEP FIX_SSTEP(&p->p_thread); /* XXXKSE */ diff --git a/sys/fs/procfs/procfs_dbregs.c b/sys/fs/procfs/procfs_dbregs.c index dad4025cca0b..897795591824 100644 --- a/sys/fs/procfs/procfs_dbregs.c +++ b/sys/fs/procfs/procfs_dbregs.c @@ -49,27 +49,22 @@ #include #include #include -#include +#include #include +#include #include -#include - int -procfs_dodbregs(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocdbregs(PFS_FILL_ARGS) { int error; struct dbreg r; char *kv; int kl; - if (p_candebug(curp, p)) + if (p_candebug(td->td_proc, p) != 0) return (EPERM); kl = sizeof(r); kv = (char *) &r; @@ -79,8 +74,6 @@ procfs_dodbregs(curp, p, pfs, uio) if (kl > uio->uio_resid) kl = uio->uio_resid; - PHOLD(p); - if (kl < 0) error = EINVAL; else @@ -93,15 +86,7 @@ procfs_dodbregs(curp, p, pfs, uio) else error = proc_write_dbregs(&p->p_thread, &r); /* XXXKSE */ } - PRELE(p); uio->uio_offset = 0; return (error); } - -int -procfs_validdbregs(struct thread *td) -{ - - return ((td->td_proc->p_flag & P_SYSTEM) == 0); -} diff --git a/sys/fs/procfs/procfs_fpregs.c b/sys/fs/procfs/procfs_fpregs.c index 99ed221dac23..23be2962c74c 100644 --- a/sys/fs/procfs/procfs_fpregs.c +++ b/sys/fs/procfs/procfs_fpregs.c @@ -46,27 +46,22 @@ #include #include #include -#include +#include #include +#include #include -#include - int -procfs_dofpregs(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocfpregs(PFS_FILL_ARGS) { int error; struct fpreg r; char *kv; int kl; - if (p_candebug(curp, p)) + if (p_candebug(td->td_proc, p)) return EPERM; kl = sizeof(r); kv = (char *) &r; @@ -95,10 +90,3 @@ procfs_dofpregs(curp, p, pfs, uio) uio->uio_offset = 0; return (error); } - -int -procfs_validfpregs(struct thread *td) -{ - - return (( td->td_proc->p_flag & P_SYSTEM) == 0); -} diff --git a/sys/fs/procfs/procfs_ioctl.c b/sys/fs/procfs/procfs_ioctl.c new file mode 100644 index 000000000000..b5cec143f79d --- /dev/null +++ b/sys/fs/procfs/procfs_ioctl.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef PROCFS_DEBUG +/* + * Process ioctls + */ +int +procfs_ioctl(PFS_IOCTL_ARGS) +{ + struct procfs_status *ps; + int error, sig; + + PROC_LOCK(p); + error = 0; + switch (cmd) { + case PIOCBIS: + p->p_stops |= *(unsigned int *)data; + break; + case PIOCBIC: + p->p_stops &= ~*(unsigned int *)data; + break; + case PIOCSFL: + /* ignore */ + break; + case PIOCGFL: + *(unsigned int *)data = 0; /* nope */ + break; + case PIOCWAIT: + while (p->p_step == 0) { + /* sleep until p stops */ + error = msleep(&p->p_stype, &p->p_mtx, + PWAIT|PCATCH, "pioctl", 0); + if (error != 0) + break; + } + /* fall through to PIOCSTATUS */ + case PIOCSTATUS: + ps = (struct procfs_status *)data; + ps->state = (p->p_step == 0); + ps->flags = 0; /* nope */ + ps->events = p->p_stops; + ps->why = p->p_step ? p->p_stype : 0; + ps->val = p->p_step ? p->p_xstat : 0; + break; + case PIOCCONT: + if (p->p_step) + break; + sig = *(int *)data; + if (!_SIG_VALID(sig)) { + error = EINVAL; + break; + } +#if 0 + mtx_lock_spin(&sched_lock); + p->p_step = 0; + if (p->p_stat == SSTOP) { + p->p_xstat = sig; + setrunnable(&p->p_thread); + mtx_unlock_spin(&sched_lock); + } else { + mtx_unlock_spin(&sched_lock); + if (sig) + psignal(p, sig); + } +#else + if (sig) + psignal(p, sig); + wakeup(&p->p_step); +#endif + break; + default: + error = (ENOTTY); + } + PROC_UNLOCK(p); + + return (error); +} + +/* + * Clean up on last close + */ +int +procfs_close(PFS_CLOSE_ARGS) +{ + if (p != NULL && (p->p_pfsflags & PF_LINGER) == 0) { + p->p_pfsflags = 0; + p->p_stops = 0; + p->p_step = 0; + wakeup(&p->p_step); + } + return (0); +} +#endif diff --git a/sys/fs/procfs/procfs_map.c b/sys/fs/procfs/procfs_map.c index 945639a636d9..cae1fc4e7d91 100644 --- a/sys/fs/procfs/procfs_map.c +++ b/sys/fs/procfs/procfs_map.c @@ -44,8 +44,9 @@ #include #include #include -#include +#include +#include #include #include @@ -68,11 +69,7 @@ * can try a bigger buffer. */ int -procfs_domap(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocmap(PFS_FILL_ARGS) { int len; int error; @@ -90,7 +87,7 @@ procfs_domap(curp, p, pfs, uio) return (0); error = 0; - if (map != &curproc->p_vmspace->vm_map) + if (map != &curthread->td_proc->p_vmspace->vm_map) vm_map_lock_read(map); for (entry = map->header.next; ((uio->uio_resid > 0) && (entry != &map->header)); @@ -118,23 +115,22 @@ procfs_domap(curp, p, pfs, uio) addr += PAGE_SIZE; } - for( lobj = tobj = obj; tobj; tobj = tobj->backing_object) + for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) lobj = tobj; if (lobj) { switch(lobj->type) { - -default: -case OBJT_DEFAULT: + default: + case OBJT_DEFAULT: type = "default"; break; -case OBJT_VNODE: + case OBJT_VNODE: type = "vnode"; break; -case OBJT_SWAP: + case OBJT_SWAP: type = "swap"; break; -case OBJT_DEVICE: + case OBJT_DEVICE: type = "device"; break; } @@ -148,13 +144,12 @@ case OBJT_DEVICE: ref_count = 0; shadow_count = 0; } - /* * format: * start, end, resident, private resident, cow, access, type. */ - snprintf(mebuffer, sizeof(mebuffer), + snprintf(mebuffer, sizeof mebuffer, "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s\n", (u_long)entry->start, (u_long)entry->end, resident, privateresident, obj, @@ -175,14 +170,8 @@ case OBJT_DEVICE: if (error) break; } - if (map != &curproc->p_vmspace->vm_map) + if (map != &curthread->td_proc->p_vmspace->vm_map) vm_map_unlock_read(map); - return error; -} - -int -procfs_validmap(struct thread *td) -{ - return ((td->td_proc->p_flag & P_SYSTEM) == 0); + return (error); } diff --git a/sys/fs/procfs/procfs_mem.c b/sys/fs/procfs/procfs_mem.c index 95c91f249718..5e51cab55c15 100644 --- a/sys/fs/procfs/procfs_mem.c +++ b/sys/fs/procfs/procfs_mem.c @@ -41,14 +41,13 @@ */ #include -#include #include #include #include #include -#include -#include +#include +#include #include /* @@ -58,20 +57,17 @@ * from the kernel address space. */ int -procfs_domem(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocmem(PFS_FILL_ARGS) { int error; if (uio->uio_resid == 0) return (0); - error = p_candebug(curp, p); + error = p_candebug(td->td_proc, p); if (error) return (error); + error = proc_rwmem(p, uio); - return (proc_rwmem(p, uio)); + return (error); } diff --git a/sys/fs/procfs/procfs_note.c b/sys/fs/procfs/procfs_note.c index c669654bab2e..41f32b03734e 100644 --- a/sys/fs/procfs/procfs_note.c +++ b/sys/fs/procfs/procfs_note.c @@ -40,28 +40,18 @@ */ #include -#include +#include +#include +#include + +#include #include int -procfs_donote(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocnote(PFS_FILL_ARGS) { - int xlen; - int error; - char note[PROCFS_NOTELEN+1]; - - if (uio->uio_rw != UIO_WRITE) - return (EINVAL); - - xlen = PROCFS_NOTELEN; - error = vfs_getuserstr(uio, note, &xlen); - if (error) - return (error); - + sbuf_trim(sb); + sbuf_finish(sb); /* send to process's notify function */ return (EOPNOTSUPP); } diff --git a/sys/fs/procfs/procfs_regs.c b/sys/fs/procfs/procfs_regs.c index 8488f13ccd66..623eb45538db 100644 --- a/sys/fs/procfs/procfs_regs.c +++ b/sys/fs/procfs/procfs_regs.c @@ -46,28 +46,22 @@ #include #include #include -#include +#include #include -#include -#include - +#include #include int -procfs_doregs(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocregs(PFS_FILL_ARGS) { int error; struct reg r; char *kv; int kl; - if (p_candebug(curp, p)) + if (p_candebug(td->td_proc, p)) return EPERM; kl = sizeof(r); kv = (char *) &r; @@ -96,10 +90,3 @@ procfs_doregs(curp, p, pfs, uio) uio->uio_offset = 0; return (error); } - -int -procfs_validregs(struct thread *td) -{ - - return ((td->td_proc->p_flag & P_SYSTEM) == 0); -} diff --git a/sys/fs/procfs/procfs_rlimit.c b/sys/fs/procfs/procfs_rlimit.c index f74874d2c6c5..aecfb0716090 100644 --- a/sys/fs/procfs/procfs_rlimit.c +++ b/sys/fs/procfs/procfs_rlimit.c @@ -48,31 +48,18 @@ #include #include #include -#include #include #include -#include +#include + +#include #include int -procfs_dorlimit(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocrlimit(PFS_FILL_ARGS) { - char *ps; int i; - int xlen; - int error; - char psbuf[512]; /* XXX - conservative */ - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - - - ps = psbuf; for (i = 0; i < RLIM_NLIMITS; i++) { @@ -80,7 +67,7 @@ procfs_dorlimit(curp, p, pfs, uio) * Add the rlimit ident */ - ps += sprintf(ps, "%s ", rlimit_ident[i]); + sbuf_printf(sb, "%s ", rlimit_ident[i]); /* * Replace RLIM_INFINITY with -1 in the string @@ -91,9 +78,9 @@ procfs_dorlimit(curp, p, pfs, uio) */ if (p->p_rlimit[i].rlim_cur == RLIM_INFINITY) { - ps += sprintf(ps, "-1 "); + sbuf_printf(sb, "-1 "); } else { - ps += sprintf(ps, "%llu ", + sbuf_printf(sb, "%llu ", (unsigned long long)p->p_rlimit[i].rlim_cur); } @@ -102,27 +89,13 @@ procfs_dorlimit(curp, p, pfs, uio) */ if (p->p_rlimit[i].rlim_max == RLIM_INFINITY) { - ps += sprintf(ps, "-1\n"); + sbuf_printf(sb, "-1\n"); } else { - ps += sprintf(ps, "%llu\n", + sbuf_printf(sb, "%llu\n", (unsigned long long)p->p_rlimit[i].rlim_max); } } - /* - * This logic is rather tasty - but its from procfs_status.c, so - * I guess I'll use it here. - */ - - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - if (xlen <= 0) - error = 0; - else - error = uiomove(ps, xlen, uio); - - return (error); + return (0); } diff --git a/sys/fs/procfs/procfs_status.c b/sys/fs/procfs/procfs_status.c index 6dd34c721d1c..44772d3b67eb 100644 --- a/sys/fs/procfs/procfs_status.c +++ b/sys/fs/procfs/procfs_status.c @@ -49,36 +49,26 @@ #include #include #include +#include #include -#include #include #include #include +#include #include -#define DOCHECK() do { if (ps >= psbuf+sizeof(psbuf)) goto bailout; } while (0) int -procfs_dostatus(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doprocstatus(PFS_FILL_ARGS) { struct session *sess; struct tty *tp; struct ucred *cr; - char *ps, *pc; + char *pc; char *sep; int pid, ppid, pgid, sid; int i; - int xlen; - int error; - char psbuf[256]; /* XXX - conservative */ - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); pid = p->p_pid; PROC_LOCK(p); @@ -91,45 +81,31 @@ procfs_dostatus(curp, p, pfs, uio) /* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg euid ruid rgid,egid,groups[1 .. NGROUPS] */ - KASSERT(sizeof(psbuf) > MAXCOMLEN, - ("Too short buffer for new MAXCOMLEN")); - ps = psbuf; pc = p->p_comm; - xlen = strlen(p->p_comm); do { if (*pc < 33 || *pc > 126 || *pc == '\\') - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\\%03o", - *pc); + sbuf_printf(sb, "\\%03o", *pc); else - *ps++ = *pc; - DOCHECK(); - } while (++pc < p->p_comm + xlen); - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - " %d %d %d %d ", pid, ppid, pgid, sid); - DOCHECK(); + sbuf_putc(sb, *pc); + } while (*++pc); + sbuf_printf(sb, " %d %d %d %d ", pid, ppid, pgid, sid); if ((p->p_flag&P_CONTROLT) && (tp = sess->s_ttyp)) - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - "%d,%d ", major(tp->t_dev), minor(tp->t_dev)); + sbuf_printf(sb, "%d,%d ", major(tp->t_dev), minor(tp->t_dev)); else - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - "%d,%d ", -1, -1); - DOCHECK(); + sbuf_printf(sb, "%d,%d ", -1, -1); sep = ""; if (sess->s_ttyvp) { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%sctty", sep); + sbuf_printf(sb, "%sctty", sep); sep = ","; - DOCHECK(); } if (SESS_LEADER(p)) { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "%ssldr", sep); + sbuf_printf(sb, "%ssldr", sep); sep = ","; - DOCHECK(); } if (*sep != ',') { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "noflags"); - DOCHECK(); + sbuf_printf(sb, "noflags"); } mtx_lock_spin(&sched_lock); @@ -138,92 +114,56 @@ procfs_dostatus(curp, p, pfs, uio) calcru(p, &ut, &st, (struct timeval *) NULL); mtx_unlock_spin(&sched_lock); - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - " %lld,%ld %ld,%ld %ld,%ld", + sbuf_printf(sb, " %lld,%ld %ld,%ld %ld,%ld", (long long)p->p_stats->p_start.tv_sec, p->p_stats->p_start.tv_usec, - (long)ut.tv_sec, ut.tv_usec, - (long)st.tv_sec, st.tv_usec); + ut.tv_sec, ut.tv_usec, + st.tv_sec, st.tv_usec); } else { mtx_unlock_spin(&sched_lock); - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - " -1,-1 -1,-1 -1,-1"); + sbuf_printf(sb, " -1,-1 -1,-1 -1,-1"); } - DOCHECK(); if (p->p_flag & P_KSES) { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s", - "-kse- "); + sbuf_printf(sb, " %s", "-kse- "); } else { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s", + sbuf_printf(sb, " %s", (p->p_thread.td_wchan && p->p_thread.td_wmesg) ? p->p_thread.td_wmesg : "nochan"); } - DOCHECK(); cr = p->p_ucred; - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %lu %lu %lu", + sbuf_printf(sb, " %lu %lu %lu", (u_long)cr->cr_uid, (u_long)cr->cr_ruid, (u_long)cr->cr_rgid); - DOCHECK(); /* egid (cr->cr_svgid) is equal to cr_ngroups[0] see also getegid(2) in /sys/kern/kern_prot.c */ for (i = 0; i < cr->cr_ngroups; i++) { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - ",%lu", (u_long)cr->cr_groups[i]); - DOCHECK(); + sbuf_printf(sb, ",%lu", (u_long)cr->cr_groups[i]); } if (jailed(p->p_ucred)) { mtx_lock(&p->p_ucred->cr_prison->pr_mtx); - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, - " %s", p->p_ucred->cr_prison->pr_host); + sbuf_printf(sb, " %s", p->p_ucred->cr_prison->pr_host); mtx_unlock(&p->p_ucred->cr_prison->pr_mtx); } else { - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " -"); + sbuf_printf(sb, " -"); } - DOCHECK(); - ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, "\n"); - DOCHECK(); + sbuf_printf(sb, "\n"); - xlen = ps - psbuf; - xlen -= uio->uio_offset; - ps = psbuf + uio->uio_offset; - xlen = imin(xlen, uio->uio_resid); - if (xlen <= 0) - error = 0; - else - error = uiomove(ps, xlen, uio); - - return (error); - -bailout: - return (ENOMEM); + return (0); } int -procfs_docmdline(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doproccmdline(PFS_FILL_ARGS) { - char *ps; - int xlen; - int error; - char *buf, *bp; - int buflen; struct ps_strings pstr; - int i; - size_t bytes_left, done; + int error, i; - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - /* * If we are using the ps/cmdline caching, use that. Otherwise * revert back to the old way which only implements full cmdline @@ -234,47 +174,19 @@ procfs_docmdline(curp, p, pfs, uio) * Linux behaviour is to return zero-length in this case. */ - if (p->p_args && (ps_argsopen || !p_cansee(curp, p))) { - bp = p->p_args->ar_args; - buflen = p->p_args->ar_length; - buf = 0; - } else if (p != curp) { - bp = p->p_comm; - buflen = MAXCOMLEN; - buf = 0; + if (p->p_args && (ps_argsopen || !p_cansee(td->td_proc, p))) { + sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); + } else if (p != td->td_proc) { + sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); } else { - buflen = 256; - MALLOC(buf, char *, buflen + 1, M_TEMP, M_WAITOK); - bp = buf; - ps = buf; error = copyin((void*)PS_STRINGS, &pstr, sizeof(pstr)); - if (error) { - FREE(buf, M_TEMP); + if (error) return (error); + for (i = 0; i < pstr.ps_nargvstr; i++) { + sbuf_copyin(sb, pstr.ps_argvstr[i], 0); + sbuf_printf(sb, "%c", '\0'); } - bytes_left = buflen; - for (i = 0; bytes_left && (i < pstr.ps_nargvstr); i++) { - error = copyinstr(pstr.ps_argvstr[i], ps, - bytes_left, &done); - /* If too long or malformed, just truncate */ - if (error) { - error = 0; - break; - } - ps += done; - bytes_left -= done; - } - buflen = ps - buf; } - buflen -= uio->uio_offset; - ps = bp + uio->uio_offset; - xlen = min(buflen, uio->uio_resid); - if (xlen <= 0) - error = 0; - else - error = uiomove(ps, xlen, uio); - if (buf) - FREE(buf, M_TEMP); - return (error); + return (0); } diff --git a/sys/fs/procfs/procfs_subr.c b/sys/fs/procfs/procfs_subr.c deleted file mode 100644 index a07cedce244d..000000000000 --- a/sys/fs/procfs/procfs_subr.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct pfsnode *pfshead; -static int pfsvplock; - -/* - * 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 -procfs_allocvp(mp, vpp, pid, pfs_type) - struct mount *mp; - struct vnode **vpp; - long pid; - pfstype pfs_type; -{ - struct thread *td = curthread; /* 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, td)) - 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, procfs_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 Pcurproc: /* /proc/curproc = 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 Pfile: - pfs->pfs_mode = (VREAD|VEXEC) | - (VREAD|VEXEC) >> 3 | - (VREAD|VEXEC) >> 6; - vp->v_type = VLNK; - break; - - case Pmem: - pfs->pfs_mode = (VREAD|VWRITE); - vp->v_type = VREG; - break; - - case Pregs: - case Pfpregs: - case Pdbregs: - pfs->pfs_mode = (VREAD|VWRITE); - vp->v_type = VREG; - break; - - case Pctl: - case Pnote: - case Pnotepg: - pfs->pfs_mode = (VWRITE); - vp->v_type = VREG; - break; - - case Ptype: - case Pmap: - case Pstatus: - case Pcmdline: - case Prlimit: - pfs->pfs_mode = (VREAD) | - (VREAD >> 3) | - (VREAD >> 6); - vp->v_type = VREG; - break; - - default: - panic("procfs_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 -procfs_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 -procfs_rw(ap) - struct vop_read_args *ap; -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct proc *curp = uio->uio_td->td_proc; - struct pfsnode *pfs = VTOPFS(vp); - struct proc *p; - int rtval; - - p = PFIND(pfs->pfs_pid); - if (p == NULL) - return (EINVAL); - PROC_UNLOCK(p); - - mp_fixme("pfs_lockowner needs a lock"); - while (pfs->pfs_lockowner) { - tsleep(&pfs->pfs_lockowner, PRIBIO, "pfslck", 0); - } - pfs->pfs_lockowner = curproc->p_pid; - - switch (pfs->pfs_type) { - case Pnote: - case Pnotepg: - rtval = procfs_donote(curp, p, pfs, uio); - break; - - case Pregs: - rtval = procfs_doregs(curp, p, pfs, uio); - break; - - case Pfpregs: - rtval = procfs_dofpregs(curp, p, pfs, uio); - break; - - case Pdbregs: - rtval = procfs_dodbregs(curp, p, pfs, uio); - break; - - case Pctl: - rtval = procfs_doctl(curp, p, pfs, uio); - break; - - case Pstatus: - rtval = procfs_dostatus(curp, p, pfs, uio); - break; - - case Pmap: - rtval = procfs_domap(curp, p, pfs, uio); - break; - - case Pmem: - rtval = procfs_domem(curp, p, pfs, uio); - break; - - case Ptype: - rtval = procfs_dotype(curp, p, pfs, uio); - break; - - case Pcmdline: - rtval = procfs_docmdline(curp, p, pfs, uio); - break; - - case Prlimit: - rtval = procfs_dorlimit(curp, p, pfs, uio); - break; - - default: - rtval = EOPNOTSUPP; - break; - } - pfs->pfs_lockowner = 0; - wakeup(&pfs->pfs_lockowner); - return rtval; -} - -/* - * 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); -} - -void -procfs_exit(struct proc *p) -{ - struct pfsnode *pfs; - pid_t pid = p->p_pid; - - /* - * The reason for this loop is not obvious -- basicly, - * procfs_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/fs/procfs/procfs_type.c b/sys/fs/procfs/procfs_type.c index 31cbcf08127d..f164b672d282 100644 --- a/sys/fs/procfs/procfs_type.c +++ b/sys/fs/procfs/procfs_type.c @@ -40,45 +40,22 @@ #include #include #include +#include #include -#include + +#include #include int -procfs_dotype(curp, p, pfs, uio) - struct proc *curp; - struct proc *p; - struct pfsnode *pfs; - struct uio *uio; +procfs_doproctype(PFS_FILL_ARGS) { - int len; - int error; - /* - * buffer for emulation type - */ - char mebuffer[256]; - char *none = "Not Available"; - - if (uio->uio_rw != UIO_READ) - return (EOPNOTSUPP); - - if (uio->uio_offset != 0) - return (0); + static const char *none = "Not Available"; if (p && p->p_sysent && p->p_sysent->sv_name) { - len = strlen(p->p_sysent->sv_name); - bcopy(p->p_sysent->sv_name, mebuffer, len); + sbuf_printf(sb, p->p_sysent->sv_name); } else { - len = strlen(none); - bcopy(none, mebuffer, len); + sbuf_printf(sb, none); } - mebuffer[len++] = '\n'; - error = uiomove(mebuffer, len, uio); - return error; -} - -int -procfs_validtype(struct thread *td) -{ - return ((td->td_proc->p_flag & P_SYSTEM) == 0); + sbuf_putc(sb, '\n'); + return (0); } diff --git a/sys/fs/procfs/procfs_vfsops.c b/sys/fs/procfs/procfs_vfsops.c deleted file mode 100644 index 24420228968e..000000000000 --- a/sys/fs/procfs/procfs_vfsops.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include - -static int procfs_mount __P((struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct thread *td)); -static int procfs_statfs __P((struct mount *mp, struct statfs *sbp, - struct thread *td)); -static int procfs_unmount __P((struct mount *mp, int mntflags, - struct thread *td)); - -/* - * VFS Operations. - * - * mount system call - */ -/* ARGSUSED */ -static int -procfs_mount(mp, path, data, ndp, td) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct thread *td; -{ - size_t size; - int error; - - if (mp->mnt_flag & MNT_UPDATE) - return (EOPNOTSUPP); - - if (mp->mnt_vfc->vfc_refcount == 1 && (error = at_exit(procfs_exit))) { - printf("procfs: cannot register procfs_exit with at_exit\n"); - return(error); - } - - mp->mnt_flag |= MNT_LOCAL; - mp->mnt_data = 0; - vfs_getnewfsid(mp); - - size = sizeof("procfs") - 1; - bcopy("procfs", mp->mnt_stat.f_mntfromname, size); - bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void)procfs_statfs(mp, &mp->mnt_stat, td); - - return (0); -} - -/* - * unmount system call - */ -static int -procfs_unmount(mp, mntflags, td) - struct mount *mp; - int mntflags; - struct thread *td; -{ - 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(procfs_exit); - - return (0); -} - -int -procfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - - return (procfs_allocvp(mp, vpp, 0, Proot)); -} - -/* - * Get file system statistics. - */ -static int -procfs_statfs(mp, sbp, td) - struct mount *mp; - struct statfs *sbp; - struct thread *td; -{ - 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 procfs_vfsops = { - procfs_mount, - vfs_stdstart, - procfs_unmount, - procfs_root, - vfs_stdquotactl, - procfs_statfs, - vfs_stdsync, - vfs_stdvget, - vfs_stdfhtovp, - vfs_stdcheckexp, - vfs_stdvptofh, - vfs_stdinit, - vfs_stduninit, - vfs_stdextattrctl, -}; - -VFS_SET(procfs_vfsops, procfs, VFCF_SYNTHETIC); -MODULE_VERSION(procfs, 1); diff --git a/sys/fs/procfs/procfs_vnops.c b/sys/fs/procfs/procfs_vnops.c deleted file mode 100644 index cd168aa01ba1..000000000000 --- a/sys/fs/procfs/procfs_vnops.c +++ /dev/null @@ -1,1023 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -static int procfs_access __P((struct vop_access_args *)); -static int procfs_badop __P((void)); -static int procfs_close __P((struct vop_close_args *)); -static int procfs_getattr __P((struct vop_getattr_args *)); -static int procfs_ioctl __P((struct vop_ioctl_args *)); -static int procfs_lookup __P((struct vop_lookup_args *)); -static int procfs_open __P((struct vop_open_args *)); -static int procfs_print __P((struct vop_print_args *)); -static int procfs_readdir __P((struct vop_readdir_args *)); -static int procfs_readlink __P((struct vop_readlink_args *)); -static int procfs_reclaim __P((struct vop_reclaim_args *)); -static int procfs_setattr __P((struct vop_setattr_args *)); - -/* - * This is a list of the valid names in the - * process-specific sub-directories. It is - * used in procfs_lookup and procfs_readdir - */ -static struct proc_target { - u_char pt_type; - u_char pt_namlen; - char *pt_name; - pfstype pt_pfstype; - int (*pt_valid) __P((struct thread *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("mem"), Pmem, NULL }, - { DT_REG, N("regs"), Pregs, procfs_validregs }, - { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, - { DT_REG, N("dbregs"), Pdbregs, procfs_validdbregs }, - { DT_REG, N("ctl"), Pctl, NULL }, - { DT_REG, N("status"), Pstatus, NULL }, - { DT_REG, N("note"), Pnote, NULL }, - { DT_REG, N("notepg"), Pnotepg, NULL }, - { DT_REG, N("map"), Pmap, procfs_validmap }, - { DT_REG, N("etype"), Ptype, procfs_validtype }, - { DT_REG, N("cmdline"), Pcmdline, NULL }, - { DT_REG, N("rlimit"), Prlimit, NULL }, - { DT_LNK, N("file"), Pfile, 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 -procfs_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - struct pfsnode *pfs = VTOPFS(ap->a_vp); - struct proc *p1, *p2; - int error = 0; - - p2 = PFIND(pfs->pfs_pid); - if (p2 == NULL) - return (ENOENT); - if (pfs->pfs_pid && p_cansee(ap->a_td->td_proc, p2)) { - error = ENOENT; - goto out; - } - - 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))) { - error = EBUSY; - goto out; - } - - p1 = ap->a_td->td_proc; - error = p_candebug(p1, p2); - if (error) - goto out; - - if (ap->a_mode & FWRITE) - pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); - - default: - break; - } -out: - PROC_UNLOCK(p2); - return (error); -} - -/* - * 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 -procfs_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct thread *a_td; - } */ *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))) { - if (!(p->p_pfsflags & PF_LINGER)) { - p->p_stops = 0; - p->p_step = 0; - wakeup(&p->p_step); - } - PROC_UNLOCK(p); - } - break; - default: - break; - } - - return (0); -} - -/* - * do an ioctl operation on a pfsnode (vp). - * (vp) is not locked on entry or exit. - */ -static int -procfs_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_td->td_proc; - procp = pfind(pfs->pfs_pid); - if (procp == NULL) { - return ENOTTY; - } - - if ((error = p_candebug(p, procp))) { - PROC_UNLOCK(procp); - 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))) { - PROC_UNLOCK(procp); - return error; - } - procp->p_pfsflags = flags; - break; - case PIOCGFL: - *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags; - break; - 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 = msleep(&procp->p_stype, &procp->p_mtx, PWAIT | PCATCH, - "piocwait", 0); - if (error) { - PROC_UNLOCK(procp); - 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) { - PROC_UNLOCK(procp); - return EINVAL; /* Can only start a stopped process */ - } - if ((signo = *(int*)ap->a_data) != 0) { - if (signo >= NSIG || signo <= 0) { - PROC_UNLOCK(procp); - return EINVAL; - } - psignal(procp, signo); - } - procp->p_step = 0; - wakeup(&procp->p_step); - break; - default: - PROC_UNLOCK(procp); - return (ENOTTY); - } - PROC_UNLOCK(procp); - 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 -procfs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - return (procfs_freevp(ap->a_vp)); -} - -/* - * _print is used for debugging. - * just print a readable description - * of (vp). - */ -static int -procfs_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 -procfs_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 -procfs_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct thread *a_td; - } */ *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 Pcurproc: - procp = NULL; - break; - - default: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL) - return (ENOENT); - if (procp->p_ucred == NULL) { - PROC_UNLOCK(procp); - return (ENOENT); - } - - if (p_cansee(ap->a_td->td_proc, procp)) { - PROC_UNLOCK(procp); - return (ENOENT); - } - PROC_UNLOCK(procp); - } - - 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 Pctl: - case Pregs: - case Pfpregs: - case Pdbregs: - case Pmem: - PROC_LOCK(procp); - if (procp->p_flag & P_SUGID) - vap->va_mode &= ~((VREAD|VWRITE)| - ((VREAD|VWRITE)>>3)| - ((VREAD|VWRITE)>>6)); - PROC_UNLOCK(procp); - 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) { - PROC_LOCK(procp); - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = procp->p_ucred->cr_gid; - PROC_UNLOCK(procp); - } - - 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 Pcurproc: { - 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 Pfile: { - 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 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* - * XXX: ps and friends are no longer setgid kmem, why - * is this needed? - */ - PROC_LOCK(procp); - if (procp->p_flag & P_SUGID) - vap->va_uid = 0; - else - vap->va_uid = procp->p_ucred->cr_uid; - PROC_UNLOCK(procp); - break; - - case Pregs: - vap->va_bytes = vap->va_size = sizeof(struct reg); - break; - - case Pfpregs: - vap->va_bytes = vap->va_size = sizeof(struct fpreg); - break; - - case Pdbregs: - vap->va_bytes = vap->va_size = sizeof(struct dbreg); - break; - - case Ptype: - case Pmap: - case Pctl: - case Pstatus: - case Pnote: - case Pnotepg: - case Pcmdline: - case Prlimit: - break; - - default: - panic("procfs_getattr"); - } - - return (error); -} - -static int -procfs_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct thread *a_td; - } */ *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 -procfs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *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 Pcurproc: - break; - default: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL) - return (ENOENT); - if (p_cansee(ap->a_td->td_proc, procp)) { - PROC_UNLOCK(procp); - return (ENOENT); - } - PROC_UNLOCK(procp); - } - - vap = &vattr; - error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td); - 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 -procfs_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 vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct proc *curp = cnp->cn_thread->td_proc; - struct proc_target *pt; - pid_t pid; - struct pfsnode *pfs; - struct proc *p; - int i; - struct thread *td; - - *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, "curproc", 7)) - return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); - - pid = atopid(pname, cnp->cn_namelen); - if (pid == NO_PID) - break; - - p = PFIND(pid); - if (p == NULL) - break; - - if (p_cansee(curp, p)) { - PROC_UNLOCK(p); - break; - } - PROC_UNLOCK(p); - - return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); - - case Pproc: - if (cnp->cn_flags & ISDOTDOT) - return (procfs_root(dvp->v_mount, vpp)); - - p = PFIND(pfs->pfs_pid); - td = &p->p_thread; /* XXXKSE */ - if (p == NULL) - 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)(td))) - goto found; - } - PROC_UNLOCK(p); - break; - found: - PROC_UNLOCK(p); - return (procfs_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 -procfs_validfile(td) - struct thread *td; -{ - - return (td->td_proc->p_textvp != 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 -procfs_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; - struct thread *td; - - 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); - td = &p->p_thread; /* XXXKSE */ - if (p == NULL) - break; - if (p_cansee(curthread->td_proc, p)) { - PROC_UNLOCK(p); - break; - } - - for (pt = &proc_targets[i]; - uio->uio_resid >= delen && i < nproc_targets; pt++, i++) { - if (pt->pt_valid && (*pt->pt_valid)(td) == 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; - - PROC_UNLOCK(p); - if ((error = uiomove((caddr_t)dp, delen, uio)) != 0) - break; - PROC_LOCK(p); - } - PROC_UNLOCK(p); - - break; - } - - /* - * this is for the root of the procfs filesystem - * what is needed is a special entry for "curproc" - * 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; - - sx_slock(&allproc_lock); - p = LIST_FIRST(&allproc); - 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, Pcurproc); - dp->d_namlen = 7; - bcopy("curproc", dp->d_name, 8); - dp->d_type = DT_LNK; - break; - - default: - while (pcnt < i) { - p = LIST_NEXT(p, p_list); - if (p == NULL) - goto done; - if (p_cansee(curthread->td_proc, p)) - continue; - pcnt++; - } - while (p_cansee(curthread->td_proc, p)) { - p = LIST_NEXT(p, p_list); - if (p == NULL) - 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 = LIST_NEXT(p, p_list); - break; - } - - if ((error = uiomove((caddr_t)dp, delen, uio)) != 0) - break; - } - done: - -#ifdef PROCFS_ZOMBIE - if (p == NULL && doingzomb == 0) { - doingzomb = 1; - p = LIST_FIRST(&zombproc); - goto again; - } -#endif - - sx_sunlock(&allproc_lock); - break; - - } - - default: - error = ENOTDIR; - break; - } - - uio->uio_offset = i * delen; - - return (error); -} - -/* - * readlink reads the link of `curproc' or `file' - */ -static int -procfs_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 Pcurproc: - if (pfs->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) - 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 Pfile: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL || procp->p_ucred == NULL) { - if (procp != NULL) - PROC_UNLOCK(procp); - printf("procfs_readlink: pid %d disappeared\n", - pfs->pfs_pid); - return (uiomove("unknown", sizeof("unknown") - 1, - ap->a_uio)); - } - PROC_UNLOCK(procp); - 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 **procfs_vnodeop_p; -static struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_defaultop }, - { &vop_access_desc, (vop_t *) procfs_access }, - { &vop_advlock_desc, (vop_t *) procfs_badop }, - { &vop_close_desc, (vop_t *) procfs_close }, - { &vop_create_desc, (vop_t *) procfs_badop }, - { &vop_getattr_desc, (vop_t *) procfs_getattr }, - { &vop_link_desc, (vop_t *) procfs_badop }, - { &vop_lookup_desc, (vop_t *) procfs_lookup }, - { &vop_mkdir_desc, (vop_t *) procfs_badop }, - { &vop_mknod_desc, (vop_t *) procfs_badop }, - { &vop_open_desc, (vop_t *) procfs_open }, - { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, - { &vop_print_desc, (vop_t *) procfs_print }, - { &vop_read_desc, (vop_t *) procfs_rw }, - { &vop_readdir_desc, (vop_t *) procfs_readdir }, - { &vop_readlink_desc, (vop_t *) procfs_readlink }, - { &vop_reclaim_desc, (vop_t *) procfs_reclaim }, - { &vop_remove_desc, (vop_t *) procfs_badop }, - { &vop_rename_desc, (vop_t *) procfs_badop }, - { &vop_rmdir_desc, (vop_t *) procfs_badop }, - { &vop_setattr_desc, (vop_t *) procfs_setattr }, - { &vop_symlink_desc, (vop_t *) procfs_badop }, - { &vop_write_desc, (vop_t *) procfs_rw }, - { &vop_ioctl_desc, (vop_t *) procfs_ioctl }, - { NULL, NULL } -}; -static struct vnodeopv_desc procfs_vnodeop_opv_desc = - { &procfs_vnodeop_p, procfs_vnodeop_entries }; - -VNODEOP_SET(procfs_vnodeop_opv_desc); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 6d92802153c4..e6660b2bccc2 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -68,7 +68,6 @@ SUBDIR= 3dfx \ ppbus \ ppi \ pps \ - procfs \ ${_random} \ rl \ rp \ diff --git a/sys/modules/fs/Makefile b/sys/modules/fs/Makefile index 49244f360ee5..bedaa5aa79f9 100644 --- a/sys/modules/fs/Makefile +++ b/sys/modules/fs/Makefile @@ -2,6 +2,7 @@ SUBDIR = SUBDIR += linprocfs +SUBDIR += procfs SUBDIR += pseudofs .include diff --git a/sys/modules/procfs/Makefile b/sys/modules/fs/procfs/Makefile similarity index 72% rename from sys/modules/procfs/Makefile rename to sys/modules/fs/procfs/Makefile index 3d9338e31c51..ffb2ae7a336f 100644 --- a/sys/modules/procfs/Makefile +++ b/sys/modules/fs/procfs/Makefile @@ -1,22 +1,20 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../fs/procfs +.PATH: ${.CURDIR}/../../../fs/procfs KMOD= procfs SRCS= vnode_if.h \ procfs_ctl.c \ procfs_dbregs.c \ procfs_fpregs.c \ + procfs_ioctl.c \ procfs_map.c \ procfs_mem.c \ procfs_note.c \ procfs_regs.c \ procfs_rlimit.c \ procfs_status.c \ - procfs_subr.c \ procfs_type.c \ - procfs_vfsops.c \ - procfs_vnops.c -NOMAN= + procfs.c .include