[BACK]Return to procfs_subr.c CVS log [TXT][DIR] Up to [local] / sys / miscfs / procfs

Annotation of sys/miscfs/procfs/procfs_subr.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb