diff --git a/sys/miscfs/procfs/README b/sys/miscfs/procfs/README new file mode 100644 index 000000000000..dca8efee6349 --- /dev/null +++ b/sys/miscfs/procfs/README @@ -0,0 +1,114 @@ +saute procfs lyonnais + +procfs supports two levels of directory. the filesystem root +directory contains a representation of the system process table. +this consists of an entry for each active and zombie process, and +an additional entry "curproc" which always represents the process +making the lookup request. + +each of the sub-directories contains several files. these files +are used to control and interrogate processes. the files implemented +are: + + file - xxx. the exec'ed file. + + status - r/o. returns process status. + + ctl - w/o. sends a control message to the process. + for example: + echo hup > /proc/curproc/note + will send a SIGHUP to the shell. + whereas + echo attach > /proc/1293/ctl + would set up process 1293 for debugging. + see below for more details. + + mem - r/w. virtual memory image of the process. + parts of the address space are readable + only if they exist in the target process. + a more reasonable alternative might be + to return zero pages instead of an error. + comments? + + note - w/o. writing a string here sends the + equivalent note to the process. + [ not implemented. ] + + notepg - w/o. the same as note, but sends to all + members of the process group. + [ not implemented. ] + + regs - r/w. process register set. this can be read + at any time even if the process is not stopped. + since the bsd kernel is single-processor, this + implementation will get the "right" register values. + a multi-proc kernel would need to do some + synchronisation. + writing is only allowed to a stopped process. + +this then looks like: + +% ls -li /proc +total 0 + 9 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 0 + 17 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 1 + 89 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 10 + 25 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 2 +2065 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 257 +2481 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 309 + 265 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 32 +3129 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 390 +3209 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 400 +3217 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 401 +3273 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 408 + 393 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 48 + 409 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 50 + 465 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 57 + 481 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 59 + 537 dr-xr-xr-x 2 root kmem 0 Sep 21 15:06 66 + 545 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 67 + 657 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 81 + 665 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 82 + 673 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 83 + 681 dr-xr-xr-x 2 root wheel 0 Sep 21 15:06 84 +3273 dr-xr-xr-x 2 jsp staff 0 Sep 21 15:06 curproc +% ls -li /proc/curproc +total 408 +3341 --w------- 1 jsp staff 0 Sep 21 15:06 ctl +1554 -r-xr-xr-x 1 bin bin 90112 Mar 29 04:52 file +3339 -rw------- 1 jsp staff 118784 Sep 21 15:06 mem +3343 --w------- 1 jsp staff 0 Sep 21 15:06 note +3344 --w------- 1 jsp staff 0 Sep 21 15:06 notepg +3340 -rw------- 1 jsp staff 0 Sep 21 15:06 regs +3342 -r--r--r-- 1 jsp staff 0 Sep 21 15:06 status +% df /proc/curproc /proc/curproc/file +Filesystem 512-blocks Used Avail Capacity Mounted on +proc 2 2 0 100% /proc +/dev/wd0a 16186 13548 1018 93% / +% cat /proc/curproc/status +cat 446 439 400 81 12,0 ctty 748620684 270000 0 0 0 20000 nochan 11 20 20 20 0 21 117 + + + +the basic sequence of commands written to "ctl" would be + + attach - this stops the target process and + arranges for the sending process + to become the debug control process + wait - wait for the target process to come to + a steady state ready for debugging. + step - single step, with no signal delivery. + run - continue running, with no signal delivery, + until next trap or breakpoint. + - deliver signal and continue running. + detach - continue execution of the target process + and remove it from control by the debug process + +in a normal debugging environment, where the target is fork/exec'd by +the debugger, the debugger should fork and the child should stop itself +(with a self-inflicted SIGSTOP). the parent should do a "wait" then an +"attach". as before, the child will hit a breakpoint on the first +instruction in any newly exec'd image. + +From: Id: README,v 4.1 1993/12/17 10:47:45 jsp Rel +$Id: README,v 1.1 1994/01/05 07:51:08 cgd Exp $ diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h new file mode 100644 index 000000000000..622c1aada651 --- /dev/null +++ b/sys/miscfs/procfs/procfs.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs.h,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs.h,v 1.1 1994/01/05 07:51:12 cgd Exp $ + */ + +/* + * The different types of node in a procfs filesystem + */ +typedef enum { + Proot, /* the filesystem root */ + Pproc, /* a process-specific sub-directory */ + Pfile, /* the executable file */ + Pmem, /* the process's memory image */ + Pregs, /* the process's register set */ + Pctl, /* process control */ + Pstatus, /* process status */ + Pnote, /* process notifier */ + Pnotepg /* process group notifier */ +} 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 */ +}; + +#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 */ + +/* + * Kernel stuff follows + */ +#ifdef KERNEL + +#ifndef VT_PROCFS +#define VT_PROCFS VT_UFS +#endif + +#define NDEQ(ndp, s, len) \ + ((ndp)->ni_namelen == (len) && \ + (bcmp((s), (ndp)->ni_ptr, (len)) == 0)) + +/* + * Format of a directory entry in /proc, ... + * This must map onto struct dirent (see ) + */ +#define PROCFS_NAMELEN 8 +struct pfsdent { + u_long d_fileno; + u_short d_reclen; + u_short d_namlen; + char d_name[PROCFS_NAMELEN]; +}; +#define UIO_MX sizeof(struct pfsdent) +#define PROCFS_FILENO(pid, type) \ + (((type) == Proot) ? \ + 2 : \ + ((((pid)+1) << 3) + ((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; +}; + +extern int vfs_getuserstr __P((struct uio *, char *, int *)); +extern vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int)); + +struct reg; + +#define PFIND(pid) ((pid) ? pfind(pid) : &proc0) +extern int procfs_freevp __P((struct vnode *)); +extern int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype)); +extern struct vnode *procfs_findtextvp __P((struct proc *)); +extern int procfs_sstep __P((struct proc *)); +extern int procfs_read_regs __P((struct proc *, struct reg *)); +extern int procfs_write_regs __P((struct proc *, struct reg *)); +extern int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +extern int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +extern int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +extern int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +extern int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +extern int procfs_rw __P((struct vnode *, struct uio *, int, struct ucred *)); + +#define PROCFS_LOCKED 0x01 +#define PROCFS_WANT 0x02 + +extern struct vnodeops procfs_vnodeops; +extern struct vfsops procfs_vfsops; + +/* + * Prototypes for procfs vnode ops + */ +int procfs_badop(); /* varargs */ +int procfs_rw __P(( + struct vnode *vp, + struct uio *uio, + int ioflag, + struct ucred *cred)); +int procfs_lookup __P(( + struct vnode *vp, + struct nameidata *ndp, + struct proc *p)); +#define procfs_create ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct proc *p))) procfs_badop) +#define procfs_mknod ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct ucred *cred, \ + struct proc *p))) procfs_badop) +int procfs_open __P(( + struct vnode *vp, + int mode, + struct ucred *cred, + struct proc *p)); +int procfs_close __P(( + struct vnode *vp, + int fflag, + struct ucred *cred, + struct proc *p)); +int procfs_access __P(( + struct vnode *vp, + int mode, + struct ucred *cred, + struct proc *p)); +int procfs_getattr __P(( + struct vnode *vp, + struct vattr *vap, + struct ucred *cred, + struct proc *p)); +int procfs_setattr __P(( + struct vnode *vp, + struct vattr *vap, + struct ucred *cred, + struct proc *p)); +#define procfs_read procfs_rw +#define procfs_write procfs_rw +int procfs_ioctl __P(( + struct vnode *vp, + int command, + caddr_t data, + int fflag, + struct ucred *cred, + struct proc *p)); +#define procfs_select ((int (*) __P(( \ + struct vnode *vp, \ + int which, \ + int fflags, \ + struct ucred *cred, \ + struct proc *p))) procfs_badop) +#define procfs_mmap ((int (*) __P(( \ + struct vnode *vp, \ + int fflags, \ + struct ucred *cred, \ + struct proc *p))) procfs_badop) +#define procfs_fsync ((int (*) __P(( \ + struct vnode *vp, \ + int fflags, \ + struct ucred *cred, \ + int waitfor, \ + struct proc *p))) procfs_badop) +#define procfs_seek ((int (*) __P(( \ + struct vnode *vp, \ + off_t oldoff, \ + off_t newoff, \ + struct ucred *cred))) procfs_badop) +#define procfs_remove ((int (*) __P(( \ + struct nameidata *ndp, \ + struct proc *p))) procfs_badop) +#define procfs_link ((int (*) __P(( \ + struct vnode *vp, \ + struct nameidata *ndp, \ + struct proc *p))) procfs_badop) +#define procfs_rename ((int (*) __P(( \ + struct nameidata *fndp, \ + struct nameidata *tdnp, \ + struct proc *p))) procfs_badop) +#define procfs_mkdir ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct proc *p))) procfs_badop) +#define procfs_rmdir ((int (*) __P(( \ + struct nameidata *ndp, \ + struct proc *p))) procfs_badop) +#define procfs_symlink ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + char *target, \ + struct proc *p))) procfs_badop) +int procfs_readdir __P(( + struct vnode *vp, + struct uio *uio, + struct ucred *cred, + int *eofflagp, + u_int *cookies, + int ncookies)); +#define procfs_readlink ((int (*) __P(( \ + struct vnode *vp, \ + struct uio *uio, \ + struct ucred *cred))) procfs_badop) +int procfs_abortop __P(( + struct nameidata *ndp)); +int procfs_inactive __P(( + struct vnode *vp, + struct proc *p)); +int procfs_reclaim __P(( + struct vnode *vp)); +#define procfs_lock ((int (*) __P(( \ + struct vnode *vp))) nullop) +#define procfs_unlock ((int (*) __P(( \ + struct vnode *vp))) nullop) +int procfs_bmap __P(( + struct vnode *vp, + daddr_t bn, + struct vnode **vpp, + daddr_t *bnp)); +#define procfs_strategy ((int (*) __P(( \ + struct buf *bp))) procfs_badop) +int procfs_print __P(( + struct vnode *vp)); +#define procfs_islocked ((int (*) __P(( \ + struct vnode *vp))) nullop) +#define procfs_advlock ((int (*) __P(( \ + struct vnode *vp, \ + caddr_t id, \ + int op, \ + struct flock *fl, \ + int flags))) procfs_badop) + +#endif /* KERNEL */ diff --git a/sys/miscfs/procfs/procfs_ctl.c b/sys/miscfs/procfs/procfs_ctl.c new file mode 100644 index 000000000000..02c4d96f1f23 --- /dev/null +++ b/sys/miscfs/procfs/procfs_ctl.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs_ctl.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_ctl.c,v 1.1 1994/01/05 07:51:15 cgd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * True iff process (p) is in trace wait state + * relative to process (curp) + */ +#define TRACE_WAIT_P(curp, p) \ + ((p)->p_stat == SSTOP && \ + (p)->p_pptr == (curp) && \ + ((p)->p_flag & STRC)) + +#define FIX_SSTEP(p) { \ + if ((p)->p_stat & SSSTEP) { \ + procfs_fix_sstep(p); \ + (p)->p_stat &= ~SSSTEP; \ + } \ +} + +#define PROCFS_CTL_ATTACH 1 +#define PROCFS_CTL_DETACH 2 +#define PROCFS_CTL_STEP 3 +#define PROCFS_CTL_RUN 4 +#define PROCFS_CTL_WAIT 5 + +static vfs_namemap_t ctlnames[] = { + /* special /proc commands */ + { "attach", PROCFS_CTL_ATTACH }, + { "detach", PROCFS_CTL_DETACH }, + { "step", PROCFS_CTL_STEP }, + { "run", PROCFS_CTL_RUN }, + { "wait", PROCFS_CTL_WAIT }, + { 0 }, +}; + +static vfs_namemap_t signames[] = { + /* regular signal names */ + { "hup", SIGHUP }, { "int", SIGINT }, + { "quit", SIGQUIT }, { "ill", SIGILL }, + { "trap", SIGTRAP }, { "abrt", SIGABRT }, + { "iot", SIGIOT }, { "emt", SIGEMT }, + { "fpe", SIGFPE }, { "kill", SIGKILL }, + { "bus", SIGBUS }, { "segv", SIGSEGV }, + { "sys", SIGSYS }, { "pipe", SIGPIPE }, + { "alrm", SIGALRM }, { "term", SIGTERM }, + { "urg", SIGURG }, { "stop", SIGSTOP }, + { "tstp", SIGTSTP }, { "cont", SIGCONT }, + { "chld", SIGCHLD }, { "ttin", SIGTTIN }, + { "ttou", SIGTTOU }, { "io", SIGIO }, + { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ }, + { "vtalrm", SIGVTALRM }, { "prof", SIGPROF }, + { "winch", SIGWINCH }, { "info", SIGINFO }, + { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 }, + { 0 }, +}; + +static int +procfs_control(curp, p, op) + struct proc *curp; + struct proc *p; + int op; +{ + int error; + + /* + * Attach - attaches the target process for debugging + * by the calling process. + */ + if (op == PROCFS_CTL_ATTACH) { + /* check whether already being traced */ + if (p->p_flag & STRC) + return (EBUSY); + + /* can't trace yourself! */ + if (p->p_pid == curp->p_pid) + return (EINVAL); + + /* + * Go ahead and set the trace flag. + * Save the old parent (it's reset in + * _DETACH, and also in kern_exit.c:wait4() + * Reparent the process so that the tracing + * proc gets to see all the action. + * Stop the target. + */ + p->p_flag |= STRC; + p->p_xstat = 0; /* XXX ? */ + if (p->p_pptr != curp) { + p->p_oppid = p->p_pptr->p_pid; + proc_reparent(p, curp); + } + psignal(p, SIGSTOP); + return (0); + } + + /* + * Target process must be stopped, owned by (curp) and + * be set up for tracing (STRC flag set). + * Allow DETACH to take place at any time for sanity. + * Allow WAIT any time, of course. + */ + switch (op) { + case PROCFS_CTL_DETACH: + case PROCFS_CTL_WAIT: + break; + + default: + if (!TRACE_WAIT_P(curp, p)) + return (EBUSY); + } + + /* + * do single-step fixup if needed + */ + FIX_SSTEP(p); + + /* + * Don't deliver any signal by default. + * To continue with a signal, just send + * the signal name to the ctl file + */ + p->p_xstat = 0; + + switch (op) { + /* + * Detach. Cleans up the target process, reparent it if possible + * and set it running once more. + */ + case PROCFS_CTL_DETACH: + /* if not being traced, then this is a painless no-op */ + if ((p->p_flag & STRC) == 0) + return (0); + + /* not being traced any more */ + p->p_flag &= ~STRC; + + /* give process back to original parent */ + if (p->p_oppid != p->p_pptr->p_pid) { + struct proc *pp; + + pp = pfind(p->p_oppid); + if (pp) + proc_reparent(p, pp); + } + + p->p_oppid = 0; + p->p_flag &= ~SWTED; /* XXX ? */ + wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */ + + break; + + /* + * Step. Let the target process execute a single instruction. + */ + case PROCFS_CTL_STEP: + procfs_sstep(p); + break; + + /* + * Run. Let the target process continue running until a breakpoint + * or some other trap. + */ + case PROCFS_CTL_RUN: + break; + + /* + * Wait for the target process to stop. + * If the target is not being traced then just wait + * to enter + */ + case PROCFS_CTL_WAIT: + error = 0; + if (p->p_flag & STRC) { + while (error == 0 && + (p->p_stat != SSTOP) && + (p->p_flag & STRC) && + (p->p_pptr == curp)) { + error = tsleep((caddr_t) p, + PWAIT|PCATCH, "procfsx", 0); + } + if (error == 0 && !TRACE_WAIT_P(curp, p)) + error = EBUSY; + } else { + while (error == 0 && p->p_stat != SSTOP) { + error = tsleep((caddr_t) p, + PWAIT|PCATCH, "procfs", 0); + } + } + return (error); + + default: + panic("procfs_control"); + } + + if (p->p_stat == SSTOP) + setrun(p); + return (0); +} + +pfs_doctl(curp, p, pfs, uio) + struct proc *curp; + struct pfsnode *pfs; + struct uio *uio; + struct proc *p; +{ + int len = uio->uio_resid; + int xlen; + int error; + struct sigmap *sm; + char msg[PROCFS_CTLLEN+1]; + char *cp = msg; + vfs_namemap_t *nm; + + if (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 + * return EOPNOTSUPP. + * + * Sending a signal while the process is being debugged + * also has the side effect of letting the target continue + * to run. There is no way to single-step a signal delivery. + */ + error = EOPNOTSUPP; + + nm = vfs_findname(ctlnames, msg, xlen); + if (nm) { + error = procfs_control(curp, p, nm->nm_val); + } else { + nm = vfs_findname(signames, msg, xlen); + if (nm) { + if (TRACE_WAIT_P(curp, p)) { + p->p_xstat = nm->nm_val; + FIX_SSTEP(p); + setrun(p); + } else { + psignal(p, nm->nm_val); + } + error = 0; + } + } + + return (error); +} diff --git a/sys/miscfs/procfs/procfs_mem.c b/sys/miscfs/procfs/procfs_mem.c new file mode 100644 index 000000000000..a89012d64ec3 --- /dev/null +++ b/sys/miscfs/procfs/procfs_mem.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs_mem.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_mem.c,v 1.1 1994/01/05 07:51:18 cgd Exp $ + */ + +/* + * This is a lightly hacked and merged version + * of sef's pread/pwrite functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +pfs_rwmem(p, uio) + struct proc *p; + struct uio *uio; +{ + int error; + int writing; + + writing = uio->uio_rw == UIO_WRITE; + + /* + * Only map in one page at a time. We don't have to, but it + * makes things easier. This way is trivial - right? + */ + do { + vm_map_t map, tmap; + vm_object_t object; + vm_offset_t kva; + vm_offset_t uva; + int page_offset; /* offset into page */ + vm_offset_t pageno; /* page number */ + vm_map_entry_t out_entry; + vm_prot_t out_prot; + vm_page_t m; + boolean_t wired, single_use; + vm_offset_t off; + u_int len; + int fix_prot; + + uva = (vm_offset_t) uio->uio_offset; + if (uva > VM_MAXUSER_ADDRESS) { + error = 0; + break; + } + + /* + * Get the page number of this segment. + */ + pageno = trunc_page(uva); + page_offset = uva - pageno; + + /* + * How many bytes to copy + */ + len = min(PAGE_SIZE - page_offset, uio->uio_resid); + + /* + * The map we want... + */ + map = &p->p_vmspace->vm_map; + + /* + * Check the permissions for the area we're interested + * in. + */ + fix_prot = 0; + if (writing) + fix_prot = !vm_map_check_protection(map, pageno, + pageno + PAGE_SIZE, VM_PROT_WRITE); + + if (fix_prot) { + /* + * If the page is not writable, we make it so. + * XXX It is possible that a page may *not* be + * read/executable, if a process changes that! + * We will assume, for now, that a page is either + * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE. + */ + error = vm_map_protect(map, pageno, + pageno + PAGE_SIZE, VM_PROT_ALL, 0); + if (error) + break; + } + + /* + * Now we need to get the page. out_entry, out_prot, wired, + * and single_use aren't used. One would think the vm code + * would be a *bit* nicer... We use tmap because + * vm_map_lookup() can change the map argument. + */ + tmap = map; + error = vm_map_lookup(&tmap, pageno, + writing ? VM_PROT_WRITE : VM_PROT_READ, + &out_entry, &object, &off, &out_prot, + &wired, &single_use); + /* + * We're done with tmap now. + */ + if (!error) + vm_map_lookup_done(tmap, out_entry); + + /* + * Fault the page in... + */ + if (!error && writing && object->shadow) { + m = vm_page_lookup(object, off); + if (m == 0 || m->copy_on_write) + error = vm_fault(map, pageno, + VM_PROT_WRITE, FALSE); + } + + /* Find space in kernel_map for the page we're interested in */ + if (!error) + error = vm_map_find(kernel_map, object, off, &kva, + PAGE_SIZE, 1); + + if (!error) { + /* + * Neither vm_map_lookup() nor vm_map_find() appear + * to add a reference count to the object, so we do + * that here and now. + */ + vm_object_reference(object); + + /* + * Mark the page we just found as pageable. + */ + error = vm_map_pageable(kernel_map, kva, + kva + PAGE_SIZE, 0); + + /* + * Now do the i/o move. + */ + if (!error) + error = uiomove(kva + page_offset, len, uio); + + vm_map_remove(kernel_map, kva, kva + PAGE_SIZE); + } + if (fix_prot) + vm_map_protect(map, pageno, pageno + PAGE_SIZE, + VM_PROT_READ|VM_PROT_EXECUTE, 0); + } while (error == 0 && uio->uio_resid > 0); + + return (error); +} + +/* + * Copy data in and out of the target process. + * We do this by mapping the process's page into + * the kernel and then doing a uiomove direct + * from the kernel address space. + */ +pfs_domem(curp, p, pfs, uio) + struct proc *curp; + struct proc *p; + struct pfsnode *pfs; + struct uio *uio; +{ + int error; + + if (uio->uio_resid == 0) + return (0); + + error = pfs_rwmem(p, uio); + + return (error); +} + +/* + * Given process (p), find the vnode from which + * it's text segment is being executed. + * + * It would be nice to grab this information from + * the VM system, however, there is no sure-fire + * way of doing that. Instead, fork(), exec() and + * wait() all maintain the p_textvp field in the + * process proc structure which contains a held + * reference to the exec'ed vnode. + */ +struct vnode * +procfs_findtextvp(p) + struct proc *p; +{ + return (p->p_textvp); +} + + +#ifdef probably_never +/* + * Given process (p), find the vnode from which + * it's text segment is being mapped. + * + * (This is here, rather than in procfs_subr in order + * to keep all the VM related code in one place.) + */ +struct vnode * +procfs_findtextvp(p) + struct proc *p; +{ + int error; + vm_object_t object; + vm_offset_t pageno; /* page number */ + + /* find a vnode pager for the user address space */ + + for (pageno = VM_MIN_ADDRESS; + pageno < VM_MAXUSER_ADDRESS; + pageno += PAGE_SIZE) { + vm_map_t map; + vm_map_entry_t out_entry; + vm_prot_t out_prot; + boolean_t wired, single_use; + vm_offset_t off; + + map = &p->p_vmspace->vm_map; + error = vm_map_lookup(&map, pageno, + VM_PROT_READ, + &out_entry, &object, &off, &out_prot, + &wired, &single_use); + + if (!error) { + vm_pager_t pager; + + printf("procfs: found object\n"); + vm_map_lookup_done(map, out_entry); + printf("procfs: object = %x\n", object); + + /* + * At this point, assuming no errors, object + * is the VM object mapping UVA (pageno). + * Ensure it has a vnode pager, then grab + * the vnode from that pager's handle. + */ + + pager = object->pager; + printf("procfs: pager = %x\n", pager); + if (pager) + printf("procfs: found pager, type = %d\n", pager->pg_type); + if (pager && pager->pg_type == PG_VNODE) { + struct vnode *vp; + + vp = (struct vnode *) pager->pg_handle; + printf("procfs: vp = 0x%x\n", vp); + return (vp); + } + } + } + + printf("procfs: not found\n"); + return (0); +} +#endif /* notyet */ diff --git a/sys/miscfs/procfs/procfs_note.c b/sys/miscfs/procfs/procfs_note.c new file mode 100644 index 000000000000..1c616c77191c --- /dev/null +++ b/sys/miscfs/procfs/procfs_note.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs_note.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_note.c,v 1.1 1994/01/05 07:51:22 cgd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +pfs_donote(curp, p, pfs, uio) + struct proc *curp; + struct proc *p; + struct pfsnode *pfs; + struct uio *uio; +{ + int len = uio->uio_resid; + int xlen; + int error; + struct sigmap *sm; + char note[PROCFS_NOTELEN+1]; + char *cp = note; + + if (uio->uio_rw != UIO_WRITE) + return (EINVAL); + + xlen = PROCFS_NOTELEN; + error = vfs_getuserstr(uio, note, &xlen); + if (error) + return (error); + + /* send to process's notify function */ + return (EOPNOTSUPP); +} diff --git a/sys/miscfs/procfs/procfs_regs.c b/sys/miscfs/procfs/procfs_regs.c new file mode 100644 index 000000000000..59e20b1df870 --- /dev/null +++ b/sys/miscfs/procfs/procfs_regs.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs_regs.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_regs.c,v 1.1 1994/01/05 07:51:24 cgd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +pfs_doregs(curp, p, pfs, uio) + struct proc *curp; + struct proc *p; + struct pfsnode *pfs; + struct uio *uio; +{ + int error; + struct reg r; + char *kv; + int kl; + + kl = sizeof(r); + kv = (char *) &r; + + kv += uio->uio_offset; + kl -= uio->uio_offset; + if (kl > uio->uio_resid) + kl = uio->uio_resid; + + if (kl < 0) + error = EINVAL; + else + error = procfs_read_regs(p, &r); + if (error == 0) + error = uiomove(kv, kl, uio); + if (error == 0 && uio->uio_rw == UIO_WRITE) { + if ((p->p_flag & SSTOP) == 0) + error = EBUSY; + else + error = procfs_write_regs(p, &r); + } + + uio->uio_offset = 0; + return (error); +} diff --git a/sys/miscfs/procfs/procfs_status.c b/sys/miscfs/procfs/procfs_status.c new file mode 100644 index 000000000000..2055a7c25972 --- /dev/null +++ b/sys/miscfs/procfs/procfs_status.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * 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. + * + * From: + * Id: procfs_status.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_status.c,v 1.1 1994/01/05 07:51:27 cgd Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +pfs_dostatus(curp, p, pfs, uio) + struct proc *curp; + struct proc *p; + struct pfsnode *pfs; + struct uio *uio; +{ + struct session *sess; + struct tty *tp; + struct ucred *cr; + char *ps; + 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; + ppid = p->p_pptr ? p->p_pptr->p_pid : 0, + pgid = p->p_pgrp->pg_id; + sess = p->p_pgrp->pg_session; + sid = sess->s_leader ? sess->s_leader->p_pid : 0; + +/* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg uid groups ... */ + + ps = psbuf; + bcopy(p->p_comm, ps, MAXCOMLEN); + ps[MAXCOMLEN] = '\0'; + ps += strlen(ps); + ps += sprintf(ps, " %d %d %d %d ", pid, ppid, pgid, sid); + + if ((p->p_flag&SCTTY) && (tp = sess->s_ttyp)) + ps += sprintf(ps, "%d,%d ", major(tp->t_dev), minor(tp->t_dev)); + else + ps += sprintf(ps, "%d,%d ", -1, -1); + + sep = ""; + if (sess->s_ttyvp) { + ps += sprintf(ps, "%sctty", sep); + sep = ","; + } + if (SESS_LEADER(p)) { + ps += sprintf(ps, "%ssldr", sep); + sep = ","; + } + if (*sep != ',') + ps += sprintf(ps, "noflags"); + + if (p->p_stat & SLOAD) + ps += sprintf(ps, " %d %d", + p->p_stats->p_start.tv_sec, + p->p_stats->p_start.tv_usec); + else + ps += sprintf(ps, " -1 -1"); + + ps += sprintf(ps, " %d %d %d %d", + p->p_utime.tv_sec, + p->p_utime.tv_usec, + p->p_stime.tv_sec, + p->p_stime.tv_usec); + + ps += sprintf(ps, " %s", + (p->p_wchan && p->p_wmesg) ? p->p_wmesg : "nochan"); + + cr = p->p_ucred; + + ps += sprintf(ps, " %d %d", cr->cr_uid, cr->cr_gid); + for (i = 0; i < cr->cr_ngroups; i++) + ps += sprintf(ps, " %d", cr->cr_groups[i]); + ps += sprintf(ps, "\n"); + + xlen = ps - psbuf; + xlen -= uio->uio_offset; + ps = psbuf + uio->uio_offset; + xlen = min(xlen, uio->uio_resid); + if (xlen <= 0) + error = 0; + else + error = uiomove(ps, xlen, uio); + + return (error); +} diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c index b46cf819f5d0..f5042aefa7a5 100644 --- a/sys/miscfs/procfs/procfs_subr.c +++ b/sys/miscfs/procfs/procfs_subr.c @@ -1,7 +1,11 @@ /* - * Copyright (c) 1993 Paul Kranenburg + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry * 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: @@ -12,369 +16,289 @@ * 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 Paul Kranenburg. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software withough specific prior written permission + * 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 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. + * 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. * - * $Id: procfs_subr.c,v 1.4 1993/12/18 03:58:08 mycroft Exp $ + * From: + * Id: procfs_subr.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_subr.c,v 1.5 1994/01/05 07:51:29 cgd Exp $ */ + #include #include #include #include -#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include - -#include +static struct pfsnode *pfshead; +static int pfsvplock; /* - * Get process address map (PIOCGMAP) + * 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 -pfs_vmmap(procp, pfsp, pmapp) -struct proc *procp; -struct nfsnode *pfsp; -struct procmap *pmapp; +procfs_allocvp(mp, vpp, pid, pfs_type) + struct mount *mp; + struct vnode **vpp; + long pid; + pfstype pfs_type; { - int error = 0; - vm_map_t map; - vm_map_entry_t entry; - struct procmap prmap; + int error; + struct pfsnode *pfs; + struct pfsnode **pp; + struct vnode *vp; - map = &procp->p_vmspace->vm_map; - vm_map_lock(map); - entry = map->header.next; - - while (entry != &map->header) { - if (entry->is_a_map) { - vm_map_t submap = entry->object.share_map; - vm_map_entry_t subentry; - - vm_map_lock(submap); - subentry = submap->header.next; - while (subentry != &submap->header) { - prmap.vaddr = subentry->start; - prmap.size = subentry->end - subentry->start; - prmap.offset = subentry->offset; - prmap.prot = subentry->protection; - error = copyout(&prmap, pmapp, sizeof(prmap)); - if (error) - break; - pmapp++; - subentry = subentry->next; - } - vm_map_unlock(submap); - if (error) - break; +loop: + for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) { + if (pfs->pfs_pid == pid && + pfs->pfs_type == pfs_type && + PFSTOV(pfs)->v_mount == mp) { + if (vget(pfs->pfs_vnode)) + goto loop; + VOP_UNLOCK(pfs->pfs_vnode); + *vpp = pfs->pfs_vnode; + return (0); } - prmap.vaddr = entry->start; - prmap.size = entry->end - entry->start; - prmap.offset = entry->offset; - prmap.prot = entry->protection; - error = copyout(&prmap, pmapp, sizeof(prmap)); - if (error) - break; - pmapp++; - entry = entry->next; } - vm_map_unlock(map); - return error; -} - -/* - * Count number of VM entries of process (PIOCNMAP) - */ -int -pfs_vm_nentries(procp, pfsp) -struct proc *procp; -struct nfsnode *pfsp; -{ - int count = 0; - vm_map_t map; - vm_map_entry_t entry; - - map = &procp->p_vmspace->vm_map; - vm_map_lock(map); - entry = map->header.next; - - while (entry != &map->header) { - if (entry->is_a_map) - count += entry->object.share_map->nentries; - else - count++; - entry = entry->next; + /* + * otherwise lock the vp list while we call getnewvnode + * since that can block. + */ + if (pfsvplock & PROCFS_LOCKED) { + pfsvplock |= PROCFS_WANT; + sleep((caddr_t) &pfsvplock, PINOD); + goto loop; } + pfsvplock |= PROCFS_LOCKED; - vm_map_unlock(map); - return count; -} - -/* - * Map process mapped file to file descriptor (PIOCGMAPFD) - */ -int -pfs_vmfd(procp, pfsp, vmfdp, p) -struct proc *procp; -struct pfsnode *pfsp; -struct vmfd *vmfdp; -struct proc *p; -{ - int rv; - vm_map_t map; - vm_offset_t addr; - vm_size_t size; - vm_prot_t prot, maxprot; - vm_inherit_t inherit; - boolean_t shared; - vm_object_t object; - vm_offset_t objoff; - struct vnode *vp; - struct file *fp; - extern struct fileops vnops; - - map = &procp->p_vmspace->vm_map; - - addr = vmfdp->vaddr; - rv = vm_region(map, &addr, &size, &prot, &maxprot, - &inherit, &shared, &object, &objoff); - - if (rv != KERN_SUCCESS) - return EINVAL; - - while (object != NULL && object->pager == NULL) - object = object->shadow; - - if (object == NULL || object->pager == NULL - /* Nobody seems to care || !object->pager_ready */ ) - return ENOENT; - - if (object->pager->pg_type != PG_VNODE) - return ENOENT; - - /* We have a vnode pager, allocate file descriptor */ - vp = (struct vnode *)object->pager->pg_handle; - if (VOP_ACCESS(vp, VREAD, p->p_ucred, p)) { - rv = EACCES; - goto out; - } - rv = falloc(p, &fp, &vmfdp->fd); - if (rv) + error = getnewvnode(VT_PROCFS, mp, &procfs_vnodeops, vpp); + if (error) goto out; - VREF(vp); - fp->f_type = DTYPE_VNODE; - fp->f_ops = &vnops; - fp->f_data = (caddr_t)vp; - fp->f_flag = FREAD; + /* 4.4: at this point, need to allocate a pfsnode */ + + pfs = VTOPFS(*vpp); + pfs->pfs_next = 0; + pfs->pfs_pid = (pid_t) pid; + pfs->pfs_type = pfs_type; + pfs->pfs_vnode = *vpp; + pfs->pfs_flags = 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; + break; + + case Pproc: + pfs->pfs_mode = (VREAD|VEXEC) | + (VREAD|VEXEC) >> 3 | + (VREAD|VEXEC) >> 6; + break; + + case Pfile: + pfs->pfs_mode = (VREAD|VWRITE); + break; + + case Pmem: + pfs->pfs_mode = (VREAD|VWRITE); + break; + + case Pregs: + pfs->pfs_mode = (VREAD|VWRITE); + break; + + case Pctl: + pfs->pfs_mode = (VWRITE); + break; + + case Pstatus: + pfs->pfs_mode = (VREAD) | + (VREAD >> 3) | + (VREAD >> 6); + break; + + case Pnote: + pfs->pfs_mode = (VWRITE); + break; + + case Pnotepg: + pfs->pfs_mode = (VWRITE); + break; + + default: + panic("procfs_allocvp"); + } + + /* add to procfs vnode list */ + for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) + continue; + *pp = pfs; out: - vm_object_unlock(object); - return rv; -} + pfsvplock &= ~PROCFS_LOCKED; -/* - * Vnode op for reading/writing. - */ -/* ARGSUSED */ -pfs_doio(vp, uio, ioflag, cred) - struct vnode *vp; - register struct uio *uio; - int ioflag; - struct ucred *cred; -{ - struct pfsnode *pfsp = VTOPFS(vp); - struct proc *procp; - int error = 0; - long n, on; - -#ifdef DEBUG - if (pfs_debug) - printf("pfs_doio(%s): vp 0x%x, proc %x\n", - uio->uio_rw==UIO_READ?"R":"W", vp, uio->uio_procp); -#endif - -#ifdef DIAGNOSTIC - if (vp->v_type != VPROC) - panic("pfs_doio vtype"); -#endif - procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0; - if (!procp) - return ESRCH; - - if (procp->p_flag & SSYS) - return EACCES; - - if (uio->uio_resid == 0) - return (0); - if (uio->uio_offset < 0) - return (EINVAL); - - do { /* One page at a time */ - int rv; - vm_map_t map; - vm_offset_t offset; - vm_size_t size; - vm_prot_t oldprot = 0, prot, maxprot; - vm_inherit_t inherit; - boolean_t shared; - vm_object_t object; - vm_offset_t objoff; - vm_page_t m; - vm_offset_t kva; - - on = uio->uio_offset - trunc_page(uio->uio_offset); - n = MIN(PAGE_SIZE-on, uio->uio_resid); - - /* Map page into kernel space */ - - map = &procp->p_vmspace->vm_map; -#if 0 - vm_map_print(map, 1); -#endif - - offset = trunc_page(uio->uio_offset); - - rv = vm_region(map, &offset, &size, &prot, &maxprot, - &inherit, &shared, &object, &objoff); - if (rv != KERN_SUCCESS) - return EINVAL; - - vm_object_unlock(object); - - if (uio->uio_rw == UIO_WRITE && (prot & VM_PROT_WRITE) == 0) { - oldprot = prot; - prot |= VM_PROT_WRITE; - rv = vm_protect(map, offset, PAGE_SIZE, FALSE, prot); - if (rv != KERN_SUCCESS) - return EPERM; - } - /* Just fault the page */ - rv = vm_fault(map, offset, prot, FALSE); - if (rv != KERN_SUCCESS) - return EFAULT; - - /* Look up again as vm_fault() may have inserted a shadow object */ - rv = vm_region(map, &offset, &size, &prot, &maxprot, - &inherit, &shared, &object, &objoff); - if (rv != KERN_SUCCESS) - return EINVAL; - - /* Now find the page */ - /* XXX hope it's still there, should we have wired it? */ - m = vm_page_lookup(object, objoff); - if (m == NULL) - return ESRCH; - - kva = kmem_alloc_wait(kernel_map, PAGE_SIZE); - - pmap_enter(vm_map_pmap(kernel_map), kva, VM_PAGE_TO_PHYS(m), - VM_PROT_DEFAULT, TRUE); - - error = uiomove(kva + on, (int)n, uio); - - pmap_remove(vm_map_pmap(kernel_map), kva, kva + PAGE_SIZE); - kmem_free_wakeup(kernel_map, kva, PAGE_SIZE); - if (oldprot) { - rv = vm_protect(map, offset, PAGE_SIZE, FALSE, oldprot); - if (rv != KERN_SUCCESS) - return EPERM; - } - - } while (error == 0 && uio->uio_resid > 0); + if (pfsvplock & PROCFS_WANT) { + pfsvplock &= ~PROCFS_WANT; + wakeup((caddr_t) &pfsvplock); + } return (error); } -#if 00 -int -pfs_map(procp, kva, rw, offset) -struct proc *procp; -int rw; -vm_offset_t *kva, offset; +procfs_freevp(vp) + struct vnode *vp; { - int rv; - vm_map_t map; - vm_size_t size; - vm_prot_t prot, maxprot; - vm_inherit_t inherit; - boolean_t shared; - vm_object_t object; - vm_offset_t objoff; - vm_page_t m; + struct pfsnode **pfspp; + struct pfsnode *pfs = VTOPFS(vp); - map = &procp->p_vmspace->vm_map; -#if 0 - vm_map_print(map, 1); -#endif + /* 4.4: at this point, need to deallocate the pfsnode */ - offset = trunc_page(offset); - - rv = vm_region(map, &offset, &size, &prot, &maxprot, - &inherit, &shared, &object, &objoff); - if (rv != KERN_SUCCESS) - return EINVAL; - - vm_object_unlock(object); - - if (rw == UIO_WRITE && (prot & VM_PROT_WRITE) == 0) { - prot |= VM_PROT_WRITE; - rv = vm_protect(map, offset, PAGE_SIZE, FALSE, prot); - if (rv != KERN_SUCCESS) - return EPERM; + for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) { + if (*pfspp == pfs) { + *pfspp = pfs->pfs_next; + break; + } } - /* Just fault page */ - rv = vm_fault(map, offset, prot, FALSE); - if (rv != KERN_SUCCESS) - return EFAULT; - /* Look up again as vm_fault() may have inserted a shadow object */ - rv = vm_region(map, &offset, &size, &prot, &maxprot, - &inherit, &shared, &object, &objoff); - if (rv != KERN_SUCCESS) - return EINVAL; - - m = vm_page_lookup(object, objoff); - if (m == NULL) - return ESRCH; - - *kva = kmem_alloc_wait(kernel_map, PAGE_SIZE); - - pmap_enter(vm_map_pmap(kernel_map), *kva, VM_PAGE_TO_PHYS(m), - VM_PROT_DEFAULT, TRUE); - - return 0; + return (0); } -int -pfs_unmap(procp, kva) -struct proc *procp; -vm_offset_t kva; +procfs_rw(vp, uio, ioflag, cred) + struct vnode *vp; + struct uio *uio; + int ioflag; + struct ucred *cred; { - pmap_remove(vm_map_pmap(kernel_map), kva, kva + PAGE_SIZE); - kmem_free_wakeup(kernel_map, kva, PAGE_SIZE); + struct proc *curp = uio->uio_procp; + struct pfsnode *pfs = VTOPFS(vp); + struct proc *p; + + p = PFIND(pfs->pfs_pid); + if (p == 0) + return (EINVAL); + + switch (pfs->pfs_type) { + case Pnote: + case Pnotepg: + return (pfs_donote(curp, p, pfs, uio)); + + case Pregs: + return (pfs_doregs(curp, p, pfs, uio)); + + case Pctl: + return (pfs_doctl(curp, p, pfs, uio)); + + case Pstatus: + return (pfs_dostatus(curp, p, pfs, uio)); + + case Pmem: + return (pfs_domem(curp, p, pfs, uio)); + + default: + return (EOPNOTSUPP); + } +} + +/* + * 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 + */ +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; + + error = uiomove(buf, xlen, uio); + if (error) + 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, (char *) nm->nm_name, buflen+1) == 0) + return (nm); + + return (0); } -#endif diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c index e6ce7c446834..f2fe00d0c0b5 100644 --- a/sys/miscfs/procfs/procfs_vfsops.c +++ b/sys/miscfs/procfs/procfs_vfsops.c @@ -1,7 +1,11 @@ /* - * Copyright (c) 1993 Paul Kranenburg + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry * 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: @@ -12,26 +16,32 @@ * 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 Paul Kranenburg. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software withough specific prior written permission + * 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 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. + * 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. * - * $Id: procfs_vfsops.c,v 1.8 1993/12/18 03:58:11 mycroft Exp $ + * From: + * Id: procfs_vfsops.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: procfs_vfsops.c,v 1.9 1994/01/05 07:51:31 cgd Exp $ */ /* - * PROCFS VFS interface routines + * procfs VFS interface */ #include @@ -39,40 +49,12 @@ #include #include #include +#include #include #include #include - -#include - -extern struct vnodeops pfs_vnodeops; - -/* - * mfs vfs operations. - */ -int pfs_mount(); -int pfs_start(); -int pfs_unmount(); -int pfs_root(); -int pfs_quotactl(); -int pfs_statfs(); -int pfs_sync(); -int pfs_fhtovp(); -int pfs_vptofh(); -int pfs_init(); - -struct vfsops procfs_vfsops = { - pfs_mount, - pfs_start, - pfs_unmount, - pfs_root, - pfs_quotactl, - pfs_statfs, - pfs_sync, - pfs_fhtovp, - pfs_vptofh, - pfs_init, -}; +#include +#include /* for page_size */ /* * VFS Operations. @@ -80,28 +62,28 @@ struct vfsops procfs_vfsops = { * mount system call */ /* ARGSUSED */ -pfs_mount(mp, path, data, ndp, p) - register struct mount *mp; +procfs_mount(mp, path, data, ndp, p) + struct mount *mp; char *path; caddr_t data; struct nameidata *ndp; struct proc *p; { -#if 0 - struct pfs_args args; -#endif - struct vnode *pvp; u_int size; int error; - if (mp->mnt_flag & MNT_UPDATE) { - return (0); + if (UIO_MX & (UIO_MX-1)) { + log(LOG_ERR, "procfs: invalid directory entry size"); + return (EINVAL); } -#if 0 - if (error = copyin(data, (caddr_t)&args, sizeof (struct pfs_args))) - return (error); -#endif + if (mp->mnt_flag & MNT_UPDATE) + return (EOPNOTSUPP); + + mp->mnt_flag |= MNT_LOCAL; + mp->mnt_data = 0; + getnewfsid(mp, MOUNT_PROCFS); + (void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); @@ -109,128 +91,154 @@ pfs_mount(mp, path, data, ndp, p) bcopy("proc", mp->mnt_stat.f_mntfromname, size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void) pfs_statfs(mp, &mp->mnt_stat, p); return (0); } /* * unmount system call */ -pfs_unmount(mp, mntflags, p) +procfs_unmount(mp, mntflags, p) struct mount *mp; int mntflags; struct proc *p; { + int error; + extern int doforce; + int flags = 0; + + if (mntflags & MNT_FORCE) { + /* procfs can never be rootfs so don't check for it */ + if (!doforce) + return (EINVAL); + flags |= FORCECLOSE; + } + + /* + * Clear out buffer cache. I don't think we + * ever get anything cached at this level at the + * moment, but who knows... + */ + mntflushbuf(mp, 0); + + if (mntinvalbuf(mp, 1)) + return (EBUSY); + + if (error = vflush(mp, 0, flags)) + return (error); + return (0); } -pfs_root(mp, vpp) +procfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { + struct pfsnode *pfs; struct vnode *vp; - struct pfsnode *pfsp, **pp; int error; - /* Look in "cache" first */ - for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) { - if (pfsp->pfs_vnode->v_flag & VROOT) { - *vpp = pfsp->pfs_vnode; - vref(*vpp); - return 0; - } - } - - /* Not on list, allocate new vnode */ - error = getnewvnode(VT_PROCFS, mp, &pfs_vnodeops, &vp); + error = procfs_allocvp(mp, &vp, (pid_t) 0, Proot); if (error) - return error; + return (error); vp->v_type = VDIR; vp->v_flag = VROOT; - pfsp = VTOPFS(vp); - pfsp->pfs_next = NULL; - pfsp->pfs_pid = 0; - pfsp->pfs_vnode = vp; - pfsp->pfs_flags = 0; - pfsp->pfs_vflags = 0; - pfsp->pfs_uid = 0; - pfsp->pfs_gid = 0; - pfsp->pfs_mode = 0755; /* /proc = drwxr-xr-x */ - - /* Append to pfs node list */ - for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next); - *pp = pfsp; + pfs = VTOPFS(vp); *vpp = vp; - return 0; + return (0); } /* */ /* ARGSUSED */ -pfs_start(mp, flags, p) +procfs_start(mp, flags, p) struct mount *mp; int flags; struct proc *p; { - return 0; + + return (0); } /* * Get file system statistics. */ -pfs_statfs(mp, sbp, p) +procfs_statfs(mp, sbp, p) struct mount *mp; struct statfs *sbp; struct proc *p; { sbp->f_type = MOUNT_PROCFS; - sbp->f_fsize = 0; - sbp->f_bsize = 0; - sbp->f_blocks = 0; + sbp->f_fsize = page_size >> 2; + sbp->f_bsize = 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 + 3; - sbp->f_ffree = maxproc - nprocs; + sbp->f_files = maxproc; /* approx */ + sbp->f_ffree = maxproc - nprocs; /* approx */ - return 0; + if (sbp != &mp->mnt_stat) { + 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); } -pfs_quotactl(mp, cmds, uid, arg, p) +procfs_quotactl(mp, cmds, uid, arg, p) struct mount *mp; int cmds; uid_t uid; caddr_t arg; struct proc *p; { - return EOPNOTSUPP; + + return (EOPNOTSUPP); } -pfs_sync(mp, waitfor) +procfs_sync(mp, waitfor) struct mount *mp; int waitfor; { - return 0; + + return (0); } -pfs_fhtovp(mp, fhp, vpp) - register struct mount *mp; +procfs_fhtovp(mp, fhp, vpp) + struct mount *mp; struct fid *fhp; struct vnode **vpp; { - return EINVAL; + + return (EINVAL); } -pfs_vptofh(vp, fhp) +procfs_vptofh(vp, fhp) struct vnode *vp; struct fid *fhp; { + return EINVAL; } -pfs_init() +procfs_init() { - return 0; + + return (0); } + +struct vfsops procfs_vfsops = { + procfs_mount, + procfs_start, + procfs_unmount, + procfs_root, + procfs_quotactl, + procfs_statfs, + procfs_sync, + procfs_fhtovp, + procfs_vptofh, + procfs_init, +}; diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index 74953594a299..59d4375cea4f 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -1,7 +1,11 @@ /* - * Copyright (c) 1993 Paul Kranenburg + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry * 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: @@ -12,148 +16,148 @@ * 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 Paul Kranenburg. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software withough specific prior written permission + * 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 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. + * 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. * - * $Id: procfs_vnops.c,v 1.8 1993/12/18 03:58:14 mycroft Exp $ + * From: + * Id: procfs_vnops.c,v 4.2 1994/01/02 15:28:44 jsp Exp + * + * $Id: procfs_vnops.c,v 1.9 1994/01/05 07:51:34 cgd Exp $ */ /* - * PROCFS vnode interface routines + * procfs vnode interface */ #include #include #include #include -#include #include #include -#include #include #include +#include #include -#include -#include -#include - -#include -#include - -#include - -/* - * procfs vnode operations. - */ -struct vnodeops pfs_vnodeops = { - pfs_lookup, /* lookup */ - pfs_create, /* create */ - pfs_mknod, /* mknod */ - pfs_open, /* open */ - pfs_close, /* close */ - pfs_access, /* access */ - pfs_getattr, /* getattr */ - pfs_setattr, /* setattr */ - pfs_read, /* read */ - pfs_write, /* write */ - pfs_ioctl, /* ioctl */ - pfs_select, /* select */ - pfs_mmap, /* mmap */ - pfs_fsync, /* fsync */ - pfs_seek, /* seek */ - pfs_remove, /* remove */ - pfs_link, /* link */ - pfs_rename, /* rename */ - pfs_mkdir, /* mkdir */ - pfs_rmdir, /* rmdir */ - pfs_symlink, /* symlink */ - pfs_readdir, /* readdir */ - pfs_readlink, /* readlink */ - pfs_abortop, /* abortop */ - pfs_inactive, /* inactive */ - pfs_reclaim, /* reclaim */ - pfs_lock, /* lock */ - pfs_unlock, /* unlock */ - pfs_bmap, /* bmap */ - pfs_strategy, /* strategy */ - pfs_print, /* print */ - pfs_islocked, /* islocked */ - pfs_advlock, /* advlock */ -}; +#include +#include /* for page_size */ /* * Vnode Operations. * */ -/* ARGSUSED */ -int -pfs_open(vp, mode, cred, p) - register struct vnode *vp; + +/* + * 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 pfsnames { + u_short d_namlen; + char d_name[PROCFS_NAMELEN]; + pfstype d_pfstype; +} procent[] = { +#define N(s) sizeof(s)-1, s + /* namlen, nam, type */ + { N("file"), Pfile }, + { N("mem"), Pmem }, + { N("regs"), Pregs }, + { N("ctl"), Pctl }, + { N("status"), Pstatus }, + { N("note"), Pnote }, + { N("notepg"), Pnotepg }, +#undef N +}; +#define Nprocent (sizeof(procent)/sizeof(procent[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. + */ +procfs_open(vp, mode, cred, p) + struct vnode *vp; int mode; struct ucred *cred; struct proc *p; { - struct pfsnode *pfsp = VTOPFS(vp); + struct pfsnode *pfs = VTOPFS(vp); -#ifdef DEBUG - if (pfs_debug) - printf("pfs_open: vp 0x%x, proc %d\n", vp, p->p_pid); -#endif + switch (pfs->pfs_type) { + case Pmem: + if (PFIND(pfs->pfs_pid) == 0) + return (ENOENT); /* was ESRCH, jsp */ - if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL) - return ESRCH; - - if ( (pfsp->pfs_flags & FWRITE) && (mode & O_EXCL) || - (pfsp->pfs_flags & O_EXCL) && (mode & FWRITE) ) - return EBUSY; + if ((pfs->pfs_flags & FWRITE) && (mode & O_EXCL) || + (pfs->pfs_flags & O_EXCL) && (mode & FWRITE)) + return (EBUSY); - if (mode & FWRITE) - pfsp->pfs_flags = (mode & (FWRITE|O_EXCL)); - return 0; -} + if (mode & FWRITE) + pfs->pfs_flags = (mode & (FWRITE|O_EXCL)); -/* - * /proc filesystem close routine - */ -/* ARGSUSED */ -int -pfs_close(vp, flag, cred, p) - register struct vnode *vp; - int flag; - struct ucred *cred; - struct proc *p; -{ - struct pfsnode *pfsp = VTOPFS(vp); + return (0); -#ifdef DEBUG - if (pfs_debug) - printf("pfs_close: vp 0x%x proc %d\n", vp, p->p_pid); -#endif - if ((flag & FWRITE) && (pfsp->pfs_flags & O_EXCL)) - pfsp->pfs_flags &= ~(FWRITE|O_EXCL); + default: + break; + } return (0); } /* - * Ioctl operation. + * 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). */ -/* ARGSUSED */ -int -pfs_ioctl(vp, com, data, fflag, cred, p) +procfs_close(vp, flag, cred, p) + struct vnode *vp; + int flag; + struct ucred *cred; + struct proc *p; +{ + struct pfsnode *pfs = VTOPFS(vp); + + switch (pfs->pfs_type) { + case Pmem: + if ((flag & FWRITE) && (pfs->pfs_flags & O_EXCL)) + pfs->pfs_flags &= ~(FWRITE|O_EXCL); + break; + } + + return (0); +} + +/* + * do an ioctl operation on pfsnode (vp). + * (vp) is not locked on entry or exit. + */ +procfs_ioctl(vp, com, data, fflag, cred, p) struct vnode *vp; int com; caddr_t data; @@ -161,78 +165,21 @@ pfs_ioctl(vp, com, data, fflag, cred, p) struct ucred *cred; struct proc *p; { - int error = 0; - struct proc *procp; - struct pfsnode *pfsp = VTOPFS(vp); - procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0; - if (!procp) - return ESRCH; - - switch (com) { - - case PIOCGPINFO: { - int copysize = sizeof(struct kinfo_proc), needed; - kinfo_doproc(KINFO_PROC_PID, data, ©size, - pfsp->pfs_pid, &needed); - break; - } - -#ifdef notyet /* Changes to proc.h needed */ - case PIOCGSIGSET: - procp->p_psigset = *(sigset_t *)data; - break; - - case PIOCSSIGSET: - *(sigset_t *)data = procp->p_psigset; - break; - - case PIOCGFLTSET: - procp->p_pfltset = *(sigflt_t *)data; - break; - - case PIOCSFLTSET: - *(fltset_t *)data = procp->p_pfltset; - break; -#endif - - case PIOCGMAPFD: - error = pfs_vmfd(procp, pfsp, (struct vmfd *)data, p); - break; - - case PIOCGNMAP: - *(int *)data = pfs_vm_nentries(procp, pfsp); - break; - - case PIOCGMAP: - error = pfs_vmmap(procp, pfsp, *(struct procmap *)data); - break; - - default: - error = EIO; - break; - } - return error; + return (ENOTTY); } /* - * Pass I/O requests to the memory filesystem process. + * 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. */ -int -pfs_strategy(bp) - register struct buf *bp; -{ - struct vnode *vp; - struct proc *p = curproc; /* XXX */ - - return (0); -} - -/* - * This is a noop, simply returning what one has been given. - */ -int -pfs_bmap(vp, bn, vpp, bnp) +procfs_bmap(vp, bn, vpp, bnp) struct vnode *vp; daddr_t bn; struct vnode **vpp; @@ -247,283 +194,250 @@ pfs_bmap(vp, bn, vpp, bnp) } /* - * /proc filesystem inactive routine + * _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. + * + * for procfs, check if the process is still + * alive and if it isn't then just throw away + * the vnode by calling vgone(). this may + * be overkill and a waste of time since the + * chances are that the process will still be + * there and PFIND is not free. + * + * (vp) is not locked on entry or exit. */ -/* ARGSUSED */ -int -pfs_inactive(vp, p) +procfs_inactive(vp, p) struct vnode *vp; struct proc *p; { - struct pfsnode *pfsp = VTOPFS(vp); + struct pfsnode *pfs = VTOPFS(vp); - if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL - && vp->v_usecount == 0) + if (PFIND(pfs->pfs_pid) == 0) vgone(vp); - return 0; + return (0); } /* - * /proc filesystem reclaim routine + * _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. */ -/* ARGSUSED */ -int -pfs_reclaim(vp) +procfs_reclaim(vp) struct vnode *vp; { - struct pfsnode **pp, *pfsp = VTOPFS(vp); + int error; - for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) { - if (*pp == pfsp) { - *pp = pfsp->pfs_next; - break; - } - } - return 0; + error = procfs_freevp(vp); + return (error); } /* - * Print out the contents of an pfsnode. + * _print is used for debugging. + * just print a readable description + * of (vp). */ -void -pfs_print(vp) +procfs_print(vp) struct vnode *vp; { - struct pfsnode *pfsp = VTOPFS(vp); + struct pfsnode *pfs = VTOPFS(vp); - printf("tag VT_PROCFS, pid %d, uid %d, gid %d, mode %x, flags %x\n", - pfsp->pfs_pid, - pfsp->pfs_uid, pfsp->pfs_gid, - pfsp->pfs_mode, pfsp->pfs_flags); - - return; + printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", + pfs->pfs_pid, + pfs->pfs_mode, pfs->pfs_flags); } /* - * /proc bad operation + * _abortop is called when operations such as + * rename and create fail. this entry is responsible + * for undoing any side-effects caused by the lookup. + * this will always include freeing the pathname buffer. */ -int -pfs_badop() +procfs_abortop(ndp) + struct nameidata *ndp; { - printf("pfs_badop called\n"); - return EIO; + + if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF) + FREE(ndp->ni_pnbuf, M_NAMEI); + return (0); } -#if 0 /* Moved to pfs_subr.c */ /* - * Vnode op for reading/writing. + * generic entry point for unsupported operations */ -/* ARGSUSED */ -int -pfs_doio(vp, uio, ioflag, cred) +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. + */ +procfs_getattr(vp, vap, cred, p) struct vnode *vp; - register struct uio *uio; - int ioflag; + struct vattr *vap; struct ucred *cred; + struct proc *p; { - struct pfsnode *pfsp = VTOPFS(vp); - struct proc *procp; - int error = 0; - long n, off; - caddr_t kva; + struct pfsnode *pfs = VTOPFS(vp); + struct proc *procp; + int error; -#ifdef DEBUG - if (pfs_debug) - printf("pfs_doio(%s): vp 0x%x, proc %x\n", - uio->uio_rw==UIO_READ?"R":"W", vp, uio->uio_procp); -#endif + /* first check the process still exists */ + procp = PFIND(pfs->pfs_pid); + if (procp == 0) + return (ENOENT); -#ifdef DIAGNOSTIC - if (vp->v_type != VPROC) - panic("pfs_doio vtype"); -#endif - procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0; - if (!procp) - return ESRCH; + error = 0; - if (uio->uio_resid == 0) - return (0); - if (uio->uio_offset < 0) - return (EINVAL); + /* start by zeroing out the attributes */ + VATTR_NULL(vap); - do { /* One page at a time */ - off = uio->uio_offset - trunc_page(uio->uio_offset); - n = MIN(PAGE_SIZE-off, uio->uio_resid); + /* next do all the common fields */ + vap->va_type = 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; - /* Map page into kernel space */ - error = pfs_map(procp, &kva, uio->uio_rw, uio->uio_offset); - if (error) - return error; + /* + * 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. + */ + microtime(&vap->va_ctime); + vap->va_atime = vap->va_mtime = vap->va_ctime; - error = uiomove(kva + off, (int)n, uio); - pfs_unmap(procp, kva); + /* + * 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. + */ - } while (error == 0 && uio->uio_resid > 0); + switch (pfs->pfs_type) { + case Proot: + vap->va_nlink = 2; + vap->va_uid = 0; + vap->va_gid = 0; + break; + + case Pproc: + vap->va_nlink = 2; + vap->va_uid = procp->p_ucred->cr_uid; + vap->va_gid = procp->p_ucred->cr_gid; + break; + + case Pfile: + error = EOPNOTSUPP; + break; + + case Pmem: + vap->va_nlink = 1; + vap->va_bytes = vap->va_size = + ctob(procp->p_vmspace->vm_tsize + + procp->p_vmspace->vm_dsize + + procp->p_vmspace->vm_ssize); + vap->va_uid = procp->p_ucred->cr_uid; + vap->va_gid = procp->p_ucred->cr_gid; + break; + + case Pregs: + case Pctl: + case Pstatus: + case Pnote: + case Pnotepg: + vap->va_nlink = 1; + vap->va_uid = procp->p_ucred->cr_uid; + vap->va_gid = procp->p_ucred->cr_gid; + break; + + default: + panic("procfs_getattr"); + } return (error); } -#endif -/* - * Make up some attributes for a process file - */ -int -pfs_getattr (vp, vap, cred, p) +procfs_setattr(vp, vap, cred, p) struct vnode *vp; struct vattr *vap; struct ucred *cred; struct proc *p; { - struct pfsnode *pfsp = VTOPFS(vp); - struct proc *procp; - - VATTR_NULL(vap); - vap->va_type = vp->v_type; - vap->va_mode = pfsp->pfs_mode; - vap->va_flags = pfsp->pfs_vflags; - - if (vp->v_flag & VROOT) { - vap->va_nlink = 2; - vap->va_size = - roundup((2+nprocs)*sizeof(struct pfsdent), DIRBLKSIZ); - vap->va_size_rsv = 0; - vap->va_uid = pfsp->pfs_uid; - vap->va_gid = pfsp->pfs_gid; - vap->va_atime = vap->va_mtime = vap->va_ctime = time; /*XXX*/ - return 0; - } - - procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0; - if (!procp) - return ESRCH; - - vap->va_nlink = 1; - vap->va_size = ctob( procp->p_vmspace->vm_tsize + - procp->p_vmspace->vm_dsize + - procp->p_vmspace->vm_ssize); - vap->va_size_rsv = 0; - vap->va_blocksize = page_size; - vap->va_uid = procp->p_ucred->cr_uid; - vap->va_gid = procp->p_ucred->cr_gid; - if (vap->va_uid != procp->p_cred->p_ruid) - vap->va_mode |= VSUID; - if (vap->va_gid != procp->p_cred->p_rgid) - vap->va_mode |= VSGID; - if (procp->p_flag & SLOAD) { - vap->va_atime = vap->va_mtime = vap->va_ctime = - procp->p_stats->p_start; - } - - return 0; -} - -/* - * Set some attributes for a process file - */ -int -pfs_setattr (vp, vap, cred, p) - struct vnode *vp; - struct vattr *vap; - struct ucred *cred; - struct proc *p; -{ - struct pfsnode *pfsp = VTOPFS(vp); - struct proc *procp; - int error = 0; - - procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0; - if (!procp) - return ESRCH; - /* - * Check for unsetable attributes. + * 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. */ - if ((vap->va_type != VNON) || (vap->va_nlink != (short)VNOVAL) || - (vap->va_fsid != (long)VNOVAL) || - (vap->va_fileid != (long)VNOVAL) || - (vap->va_blocksize != (long)VNOVAL) || - (vap->va_rdev != (dev_t)VNOVAL) || - ((int)vap->va_bytes != (u_long)VNOVAL) || - ((int)vap->va_bytes_rsv != (u_long)VNOVAL) || - ((int)vap->va_size != (u_long)VNOVAL) || - ((int)vap->va_size_rsv != (u_long)VNOVAL) || - (vap->va_gen != (long)VNOVAL) || - ((int)vap->va_atime.tv_sec != (u_long)VNOVAL) || - ((int)vap->va_mtime.tv_sec != (u_long)VNOVAL) || - ((int)vap->va_ctime.tv_sec != (u_long)VNOVAL) || - (( (vap->va_uid != (uid_t)VNOVAL) || - (vap->va_gid != (gid_t)VNOVAL)) && !(vp->v_flag & VROOT)) ) { - return (EINVAL); - } - /* set mode bits, only rwx bits are modified */ - if (vap->va_mode != (u_short)VNOVAL) { - if (cred->cr_uid != pfsp->pfs_uid && - (error = suser(cred, &p->p_acflag))) - return (error); - pfsp->pfs_mode = vap->va_mode & 0777; - } - - /* For now, only allow to change ownership of "/proc" itself */ - if ((vp->v_flag & VROOT) && vap->va_uid != (uid_t)VNOVAL) { - if ((error = suser(cred, &p->p_acflag))) - return (error); - pfsp->pfs_uid = vap->va_uid; - } - - if ((vp->v_flag & VROOT) && vap->va_gid != (gid_t)VNOVAL) { - if ((cred->cr_uid != pfsp->pfs_uid || - !groupmember(vap->va_gid, cred)) && - (error = suser(cred, &p->p_acflag))) - return error; - - pfsp->pfs_gid = vap->va_gid; - } - - /* chflags() */ - if (vap->va_flags != (u_long)VNOVAL) { - if (cred->cr_uid != pfsp->pfs_uid && - (error = suser(cred, &p->p_acflag))) - return (error); - if (cred->cr_uid == 0) { - pfsp->pfs_vflags = vap->va_flags; - } else { - pfsp->pfs_vflags &= 0xffff0000; - pfsp->pfs_vflags |= (vap->va_flags & 0xffff); - } - } - return 0; + return (0); } -int -pfs_access (vp, mode, cred, p) +/* + * implement access checking. + * + * something very similar to this code is duplicated + * throughout the 4bsd kernel and should be moved + * into kern/vfs_subr.c sometime. + * + * 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. + */ +procfs_access(vp, mode, cred, p) struct vnode *vp; int mode; struct ucred *cred; struct proc *p; { - register struct vattr *vap; - register gid_t *gp; + struct vattr *vap; struct vattr vattr; - register int i; int error; /* * If you're the super-user, * you always get access. */ - if (cred->cr_uid == (uid_t)0) + if (cred->cr_uid == (uid_t) 0) return (0); vap = &vattr; - if (error = pfs_getattr(vp, vap, cred, p)) + if (error = VOP_GETATTR(vp, vap, cred, p)) return (error); + /* * Access check is based on only one of owner, group, public. * If not owner, then check group. If not a member of the * group, then check public access. */ if (cred->cr_uid != vap->va_uid) { + gid_t *gp; + int i; + mode >>= 3; gp = cred->cr_groups; for (i = 0; i < cred->cr_ngroups; i++, gp++) @@ -533,229 +447,336 @@ pfs_access (vp, mode, cred, p) found: ; } - if ((vap->va_mode & mode) != 0) + + if ((vap->va_mode & mode) == mode) return (0); + return (EACCES); } /* - * /proc lookup + * lookup. this is incredibly complicated in the + * general case, however for most pseudo-filesystems + * very little needs to be done. + * + * (dvp) is the directory in which the lookup takes place. + * (ndp) contains all the information about the type of + * lookup being done. + * + * (dvp) is locked on entry. + * the job of lookup is to set ndp->ni_dvp, and ndp->ni_vp. + * (this changes in 4.4 where all we want is the equivalent + * of ndp->ni_vp.) + * + * 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(). */ -int -pfs_lookup(vp, ndp, p) - register struct vnode *vp; - register struct nameidata *ndp; +procfs_lookup(dvp, ndp, p) + struct vnode *dvp; + struct nameidata *ndp; struct proc *p; { - int lockparent, wantparent, flag, error = 0; + char *pname = ndp->ni_ptr; + int error = 0; + int flag; pid_t pid; struct vnode *nvp; - struct pfsnode *pfsp; + struct pfsnode *pfs; struct proc *procp; + int mode; + pfstype pfs_type; + int i; -#ifdef DEBUG - if (pfs_debug) - printf("pfs_lookup: vp 0x%x name %s proc %d\n", - vp, ndp->ni_ptr, p->p_pid); -#endif + if (ndp->ni_namelen == 1 && *pname == '.') { + ndp->ni_vp = dvp; + ndp->ni_dvp = dvp; + VREF(dvp); + return (0); + } - ndp->ni_dvp = vp; + ndp->ni_dvp = dvp; ndp->ni_vp = NULL; - if (vp->v_type != VDIR) - return (ENOTDIR); - lockparent = ndp->ni_nameiop & LOCKPARENT; - flag = ndp->ni_nameiop & OPMASK; - wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); - if (flag != LOOKUP) - return EACCES; - if (ndp->ni_isdotdot) { - /* Should not happen */ - printf("pfs_lookup: vp 0x%x: dotdot\n", vp); - return EIO; - } - if (ndp->ni_namelen == 1 && *ndp->ni_ptr == '.') { - VREF(vp); - ndp->ni_vp = vp; - return 0; - } + pfs = VTOPFS(dvp); + switch (pfs->pfs_type) { + case Proot: + if (ndp->ni_isdotdot) + return (EIO); - pid = (pid_t)atoi(ndp->ni_ptr, ndp->ni_namelen); - if (pid == (pid_t)-1) - return ENOENT; + if (NDEQ(ndp, "curproc", 7)) + pid = p->p_pid; + else + pid = atopid(pname, ndp->ni_namelen); + if (pid == NO_PID) + return (ENOENT); - if ((procp = pid?pfind(pid):&proc0) == NULL) - return ENOENT; + procp = PFIND(pid); + if (procp == 0) + return (ENOENT); - /* Search pfs node list first */ - for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) { - if (pfsp->pfs_pid == pid) - break; - } - - if (pfsp == NULL) { - struct pfsnode **pp; - error = getnewvnode(VT_PROCFS, vp->v_mount, &pfs_vnodeops, &nvp); + error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); if (error) - return error; + return (error); - nvp->v_type = VPROC; - pfsp = VTOPFS(nvp); - pfsp->pfs_next = NULL; - pfsp->pfs_pid = pid; - pfsp->pfs_vnode = nvp; - pfsp->pfs_flags = 0; - pfsp->pfs_vflags = 0; - pfsp->pfs_uid = procp->p_ucred->cr_uid; - pfsp->pfs_gid = procp->p_ucred->cr_gid; - pfsp->pfs_mode = 0700; /* Initial access bits */ + nvp->v_type = VDIR; + pfs = VTOPFS(nvp); - /* Append to pfs node list */ - for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next); - *pp = pfsp; + ndp->ni_vp = nvp; + return (0); + case Pproc: + if (ndp->ni_isdotdot) { + ndp->ni_dvp = dvp; + error = procfs_root(dvp->v_mount, &ndp->ni_vp); + return (error); + } + + procp = PFIND(pfs->pfs_pid); + if (procp == 0) + return (ENOENT); + + for (i = 0; i < Nprocent; i++) { + struct pfsnames *dp = &procent[i]; + + if (ndp->ni_namelen == dp->d_namlen && + bcmp(pname, dp->d_name, dp->d_namlen) == 0) { + pfs_type = dp->d_pfstype; + goto found; + } + } + return (ENOENT); + + found: + if (pfs_type == Pfile) { + nvp = procfs_findtextvp(procp); + if (nvp) { + VREF(nvp); + VOP_LOCK(nvp); + } else { + error = ENXIO; + } + } else { + error = procfs_allocvp(dvp->v_mount, &nvp, + pfs->pfs_pid, pfs_type); + if (error) + return (error); + + nvp->v_type = VREG; + pfs = VTOPFS(nvp); + } + ndp->ni_vp = nvp; + return (error); + + default: + return (ENOTDIR); } - ndp->ni_vp = pfsp->pfs_vnode; - - return (error); } -int -pfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies) +/* + * readdir returns directory entries from pfsnode (vp). + * + * the strategy here with procfs is to generate a single + * directory entry at a time (struct pfsdent) and then + * copy that out to userland using uiomove. a more efficent + * though more complex implementation, would try to minimize + * the number of calls to uiomove(). for procfs, this is + * hardly worth the added code complexity. + * + * this should just be done through read() + */ +procfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies) struct vnode *vp; - register struct uio *uio; + struct uio *uio; struct ucred *cred; int *eofflagp; u_int *cookies; int ncookies; { - int error = 0; - int count, lost, pcnt, skipcnt, doingzomb = 0; - struct proc *p; - struct pfsdent dent; + struct pfsdent d; + struct pfsdent *dp = &d; + struct pfsnode *pfs; + int error; + int count; + int i; -#ifdef DEBUG - if (pfs_debug) - printf("pfs_readdir: vp 0x%x proc %d\n", - vp, uio->uio_procp->p_pid); -#endif - count = uio->uio_resid; - count &= ~(DIRBLKSIZ - 1); - lost = uio->uio_resid - count; - if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1))) + pfs = VTOPFS(vp); + + if (uio->uio_resid < UIO_MX) + return (EINVAL); + if (uio->uio_offset & (UIO_MX-1)) + return (EINVAL); + if (uio->uio_offset < 0) return (EINVAL); - uio->uio_resid = count; - uio->uio_iov->iov_len = count; - *eofflagp = 1; - skipcnt = uio->uio_offset / sizeof(struct pfsdent); + error = 0; count = 0; - if (skipcnt == 0) { - /* Fake "." and ".." entries? */ -#if 1 - dent.d_fileno = 2; /* XXX - Filesystem root */ - dent.d_reclen = sizeof(struct pfsdent); + i = uio->uio_offset / UIO_MX; - dent.d_namlen = 1; - dent.d_nam[0] = '.'; - dent.d_nam[1] = '\0'; - error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio); - if (error) - return error; - if (cookies) { - *cookies++ = sizeof(struct pfsdent); - ncookies--; - } - - dent.d_fileno = 2; - dent.d_namlen = 2; - dent.d_nam[1] = '.'; - dent.d_nam[2] = '\0'; - error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio); - if (error) - return error; - if (cookies) { - *cookies++ = 2 * sizeof(struct pfsdent); - ncookies--; - } -#endif - count += 2*dent.d_reclen; - } + 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: { + while (uio->uio_resid >= UIO_MX) { + struct pfsnames *dt; - p = (struct proc *)allproc; - for (pcnt = 0; p && uio->uio_resid && (!cookies || ncookies > 0); pcnt++) { - if (pcnt < skipcnt) { - p = p->p_nxt; - if (p == NULL && doingzomb == 0) { - doingzomb = 1; - p = zombproc; + if (i >= Nprocent) { + *eofflagp = 1; + break; } - continue; - } - *eofflagp = 0; - /* "inode" is process slot (actually position on list) */ - dent.d_fileno = (unsigned long)(pcnt+1); - dent.d_namlen = itos((unsigned int)p->p_pid, dent.d_nam); - dent.d_nam[dent.d_namlen] = '\0'; + dt = &procent[i]; + dp->d_reclen = UIO_MX; + dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); + dp->d_namlen = dt->d_namlen; + bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); + error = uiomove((caddr_t) dp, UIO_MX, uio); + if (error) + break; + count += UIO_MX; + i++; + } - p = p->p_nxt; - if (p == NULL && doingzomb == 0) { - doingzomb = 1; - p = zombproc; - } - if (p == NULL) { - /* Extend 'reclen' to end of block */; - dent.d_reclen = DIRBLKSIZ - (count & (DIRBLKSIZ - 1)); - } else - dent.d_reclen = sizeof(struct pfsdent); - count += dent.d_reclen; - error = uiomove((char *)&dent, dent.d_reclen, uio); - if (error) - break; - if (cookies) { - *cookies++ = count; - ncookies--; + 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: { + int pcnt; +#ifdef PROCFS_ZOMBIE + int doingzomb = 0; +#endif + struct proc *p; + + p = allproc; + +#define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ + pcnt = PROCFS_XFILES; + + while (p && uio->uio_resid >= UIO_MX) { + bzero((char *) dp, UIO_MX); + dp->d_reclen = UIO_MX; + + switch (i) { + case 0: + /* ship out entry for "curproc" */ + dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); + dp->d_namlen = 7; + bcopy("curproc", dp->d_name, dp->d_namlen+1); + break; + + default: + if (pcnt >= i) { + dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); + dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); + } + + p = p->p_nxt; + +#ifdef PROCFS_ZOMBIE + if (p == 0 && doingzomb == 0) { + doingzomb = 1; + p = zombproc; + } +#endif + + if (pcnt++ < i) + continue; + + break; + } + error = uiomove((caddr_t) dp, UIO_MX, uio); + if (error) + break; + count += UIO_MX; + i++; } + + break; + + } + + default: + error = ENOTDIR; + break; } + + uio->uio_offset = i * UIO_MX; if (count == 0) *eofflagp = 1; - uio->uio_resid += lost; - return error; + return (error); } /* - * convert n to decimal representation in character array b - * return number of decimal digits produced. + * convert decimal ascii to pid_t */ -int -itos(n, b) -unsigned int n; -char *b; +static pid_t +atopid(b, len) + const char *b; + u_int len; { -#define BASE 10 - int m = (n '9') - return -1; - n = 10 * n + (c - '0'); + return (NO_PID); + p = 10 * p + (c - '0'); + if (p > PID_MAX) + return (NO_PID); } - return n; + + return (p); } + +/* + * procfs vnode operations. + */ +struct vnodeops procfs_vnodeops = { + procfs_lookup, /* lookup */ + procfs_create, /* create */ + procfs_mknod, /* mknod */ + procfs_open, /* open */ + procfs_close, /* close */ + procfs_access, /* access */ + procfs_getattr, /* getattr */ + procfs_setattr, /* setattr */ + procfs_read, /* read */ + procfs_write, /* write */ + procfs_ioctl, /* ioctl */ + procfs_select, /* select */ + procfs_mmap, /* mmap */ + procfs_fsync, /* fsync */ + procfs_seek, /* seek */ + procfs_remove, /* remove */ + procfs_link, /* link */ + procfs_rename, /* rename */ + procfs_mkdir, /* mkdir */ + procfs_rmdir, /* rmdir */ + procfs_symlink, /* symlink */ + procfs_readdir, /* readdir */ + procfs_readlink, /* readlink */ + procfs_abortop, /* abortop */ + procfs_inactive, /* inactive */ + procfs_reclaim, /* reclaim */ + procfs_lock, /* lock */ + procfs_unlock, /* unlock */ + procfs_bmap, /* bmap */ + procfs_strategy, /* strategy */ + procfs_print, /* print */ + procfs_islocked, /* islocked */ + procfs_advlock, /* advlock */ +};