root/miscfs/procfs/procfs_subr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TAILQ_HEAD
  2. procfs_allocvp
  3. procfs_freevp
  4. procfs_rw
  5. vfs_getuserstr
  6. vfs_findname

    1 /*      $OpenBSD: procfs_subr.c,v 1.27 2007/06/22 09:38:53 jasper Exp $ */
    2 /*      $NetBSD: procfs_subr.c,v 1.15 1996/02/12 15:01:42 christos Exp $        */
    3 
    4 /*
    5  * Copyright (c) 1993 Jan-Simon Pendry
    6  * Copyright (c) 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  *
    9  * This code is derived from software contributed to Berkeley by
   10  * Jan-Simon Pendry.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)procfs_subr.c       8.5 (Berkeley) 6/15/94
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/time.h>
   42 #include <sys/kernel.h>
   43 #include <sys/proc.h>
   44 #include <sys/vnode.h>
   45 #include <sys/malloc.h>
   46 #include <sys/stat.h>
   47 #include <sys/ptrace.h>
   48 
   49 #include <miscfs/procfs/procfs.h>
   50 
   51 static TAILQ_HEAD(, pfsnode)    pfshead;
   52 struct lock pfs_vlock;
   53 
   54 /*ARGSUSED*/
   55 int
   56 procfs_init(struct vfsconf *vfsp)
   57 {
   58         lockinit(&pfs_vlock, PVFS, "procfsl", 0, 0);
   59         TAILQ_INIT(&pfshead);
   60         return (0);
   61 }
   62 
   63 /*
   64  * allocate a pfsnode/vnode pair.  the vnode is
   65  * referenced, but not locked.
   66  *
   67  * the pid, pfs_type, and mount point uniquely
   68  * identify a pfsnode.  the mount point is needed
   69  * because someone might mount this filesystem
   70  * twice.
   71  *
   72  * all pfsnodes are maintained on a singly-linked
   73  * list.  new nodes are only allocated when they cannot
   74  * be found on this list.  entries on the list are
   75  * removed when the vfs reclaim entry is called.
   76  *
   77  * a single lock is kept for the entire list.  this is
   78  * needed because the getnewvnode() function can block
   79  * waiting for a vnode to become free, in which case there
   80  * may be more than one process trying to get the same
   81  * vnode.  this lock is only taken if we are going to
   82  * call getnewvnode, since the kernel itself is single-threaded.
   83  *
   84  * if an entry is found on the list, then call vget() to
   85  * take a reference.  this is done because there may be
   86  * zero references to it and so it needs to removed from
   87  * the vnode free list.
   88  */
   89 int
   90 procfs_allocvp(struct mount *mp, struct vnode **vpp, pid_t pid, pfstype pfs_type)
   91 {
   92         struct proc *p = curproc;
   93         struct pfsnode *pfs;
   94         struct vnode *vp;
   95         int error;
   96 
   97         /*
   98          * Lock the vp list, getnewvnode can sleep.
   99          */
  100         error = lockmgr(&pfs_vlock, LK_EXCLUSIVE, NULL);
  101         if (error)
  102                 return (error);
  103 loop:
  104         TAILQ_FOREACH(pfs, &pfshead, list) {
  105                 vp = PFSTOV(pfs);
  106                 if (pfs->pfs_pid == pid &&
  107                     pfs->pfs_type == pfs_type &&
  108                     vp->v_mount == mp) {
  109                         if (vget(vp, 0, p))
  110                                 goto loop;
  111                         *vpp = vp;
  112                         goto out;
  113                 }
  114         }
  115 
  116         if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0)
  117                 goto out;
  118         vp = *vpp;
  119 
  120         MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
  121         vp->v_data = pfs;
  122 
  123         pfs->pfs_pid = pid;
  124         pfs->pfs_type = pfs_type;
  125         pfs->pfs_vnode = vp;
  126         pfs->pfs_flags = 0;
  127         pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
  128 
  129         switch (pfs_type) {
  130         case Proot:     /* /proc = dr-xr-xr-x */
  131                 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  132                 vp->v_type = VDIR;
  133                 vp->v_flag = VROOT;
  134                 break;
  135 
  136         case Pcurproc:  /* /proc/curproc = lr--r--r-- */
  137         case Pself:     /* /proc/self = lr--r--r-- */
  138                 pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
  139                 vp->v_type = VLNK;
  140                 break;
  141 
  142         case Pproc:     /* /proc/N = dr-xr-xr-x */
  143                 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  144                 vp->v_type = VDIR;
  145                 break;
  146 
  147         case Pfile:     /* /proc/N/file = -rw------- */
  148         case Pmem:      /* /proc/N/mem = -rw------- */
  149         case Pregs:     /* /proc/N/regs = -rw------- */
  150         case Pfpregs:   /* /proc/N/fpregs = -rw------- */
  151                 pfs->pfs_mode = S_IRUSR|S_IWUSR;
  152                 vp->v_type = VREG;
  153                 break;
  154 
  155         case Pctl:      /* /proc/N/ctl = --w------ */
  156         case Pnote:     /* /proc/N/note = --w------ */
  157         case Pnotepg:   /* /proc/N/notepg = --w------ */
  158                 pfs->pfs_mode = S_IWUSR;
  159                 vp->v_type = VREG;
  160                 break;
  161 
  162         case Pstatus:   /* /proc/N/status = -r--r--r-- */
  163         case Pcmdline:  /* /proc/N/cmdline = -r--r--r-- */
  164         case Pmeminfo:  /* /proc/meminfo = -r--r--r-- */
  165         case Pcpuinfo:  /* /proc/cpuinfo = -r--r--r-- */
  166                 pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
  167                 vp->v_type = VREG;
  168                 break;
  169 
  170         default:
  171                 panic("procfs_allocvp");
  172         }
  173 
  174         /* add to procfs vnode list */
  175         TAILQ_INSERT_TAIL(&pfshead, pfs, list);
  176         uvm_vnp_setsize(vp, 0);
  177 out:
  178         lockmgr(&pfs_vlock, LK_RELEASE, NULL);
  179 
  180         return (error);
  181 }
  182 
  183 int
  184 procfs_freevp(struct vnode *vp)
  185 {
  186         struct pfsnode *pfs = VTOPFS(vp);
  187 
  188         TAILQ_REMOVE(&pfshead, pfs, list);
  189         FREE(vp->v_data, M_TEMP);
  190         vp->v_data = 0;
  191         return (0);
  192 }
  193 
  194 int
  195 procfs_rw(void *v)
  196 {
  197         struct vop_read_args *ap = v;
  198         struct vnode *vp = ap->a_vp;
  199         struct uio *uio = ap->a_uio;
  200         struct proc *curp = uio->uio_procp;
  201         struct pfsnode *pfs = VTOPFS(vp);
  202         struct proc *p;
  203 
  204         p = pfind(pfs->pfs_pid);
  205         if (p == 0)
  206                 return (EINVAL);
  207         /* Do not permit games to be played with init(8) */
  208         if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE)
  209                 return (EPERM);
  210         if (uio->uio_offset < 0)
  211                 return (EINVAL);
  212 
  213         switch (pfs->pfs_type) {
  214         case Pnote:
  215         case Pnotepg:
  216                 return (procfs_donote(curp, p, pfs, uio));
  217 
  218         case Pctl:
  219                 return (procfs_doctl(curp, p, pfs, uio));
  220 
  221         case Pstatus:
  222                 return (procfs_dostatus(curp, p, pfs, uio));
  223 
  224         case Pmem:
  225                 return (process_domem(curp, p, uio, PT_WRITE_I));
  226 
  227         case Pcmdline:
  228                 return (procfs_docmdline(curp, p, pfs, uio));
  229 
  230         case Pmeminfo:
  231                 return (procfs_domeminfo(curp, p, pfs, uio));
  232 
  233         case Pcpuinfo:
  234                 return (procfs_docpuinfo(curp, p, pfs, uio));
  235 
  236         default:
  237                 return (EOPNOTSUPP);
  238         }
  239 }
  240 
  241 /*
  242  * Get a string from userland into (buf).  Strip a trailing
  243  * nl character (to allow easy access from the shell).
  244  * The buffer should be *buflenp + 1 chars long.  vfs_getuserstr
  245  * will automatically add a nul char at the end.
  246  *
  247  * Returns 0 on success or the following errors
  248  *
  249  * EINVAL:    file offset is non-zero.
  250  * EMSGSIZE:  message is longer than kernel buffer
  251  * EFAULT:    user i/o buffer is not addressable
  252  */
  253 int
  254 vfs_getuserstr(struct uio *uio, char *buf, int *buflenp)
  255 {
  256         int xlen;
  257         int error;
  258 
  259         if (uio->uio_offset != 0)
  260                 return (EINVAL);
  261 
  262         xlen = *buflenp;
  263 
  264         /* must be able to read the whole string in one go */
  265         if (xlen < uio->uio_resid)
  266                 return (EMSGSIZE);
  267         xlen = uio->uio_resid;
  268 
  269         if ((error = uiomove(buf, xlen, uio)) != 0)
  270                 return (error);
  271 
  272         /* allow multiple writes without seeks */
  273         uio->uio_offset = 0;
  274 
  275         /* cleanup string and remove trailing newline */
  276         buf[xlen] = '\0';
  277         xlen = strlen(buf);
  278         if (xlen > 0 && buf[xlen-1] == '\n')
  279                 buf[--xlen] = '\0';
  280         *buflenp = xlen;
  281 
  282         return (0);
  283 }
  284 
  285 const vfs_namemap_t *
  286 vfs_findname(const vfs_namemap_t *nm, char *buf, int buflen)
  287 {
  288         for (; nm->nm_name; nm++)
  289                 if (bcmp(buf, nm->nm_name, buflen + 1) == 0)
  290                         return (nm);
  291 
  292         return (0);
  293 }

/* [<][>][^][v][top][bottom][index][help] */