[BACK]Return to procfs_subr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / miscfs / procfs

Annotation of src/sys/miscfs/procfs/procfs_subr.c, Revision 1.32

1.32    ! ad          1: /*     $NetBSD: procfs_subr.c,v 1.31 2000/03/16 18:08:26 jdolecek Exp $        */
1.13      cgd         2:
1.1       pk          3: /*
1.20      thorpej     4:  * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
1.5       cgd         5:  * Copyright (c) 1993 Jan-Simon Pendry
1.11      mycroft     6:  * Copyright (c) 1993
                      7:  *     The Regents of the University of California.  All rights reserved.
1.2       pk          8:  *
1.5       cgd         9:  * This code is derived from software contributed to Berkeley by
                     10:  * Jan-Simon Pendry.
                     11:  *
1.2       pk         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. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
1.5       cgd        22:  *     This product includes software developed by the University of
                     23:  *     California, Berkeley and its contributors.
                     24:  * 4. Neither the name of the University nor the names of its contributors
                     25:  *    may be used to endorse or promote products derived from this software
                     26:  *    without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     29:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     31:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     32:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     33:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     34:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     35:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     36:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     37:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     38:  * SUCH DAMAGE.
1.2       pk         39:  *
1.23      fvdl       40:  *     @(#)procfs_subr.c       8.6 (Berkeley) 5/14/95
1.1       pk         41:  */
1.5       cgd        42:
1.4       mycroft    43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/time.h>
                     46: #include <sys/kernel.h>
                     47: #include <sys/proc.h>
                     48: #include <sys/vnode.h>
1.11      mycroft    49: #include <sys/malloc.h>
1.18      mycroft    50: #include <sys/stat.h>
                     51:
1.5       cgd        52: #include <miscfs/procfs/procfs.h>
1.1       pk         53:
1.29      fvdl       54: void procfs_hashins __P((struct pfsnode *));
                     55: void procfs_hashrem __P((struct pfsnode *));
                     56: struct vnode *procfs_hashget __P((pid_t, pfstype, struct mount *));
                     57:
                     58: LIST_HEAD(pfs_hashhead, pfsnode) *pfs_hashtbl;
1.30      fvdl       59: u_long pfs_ihash;      /* size of hash table - 1 */
                     60: #define PFSPIDHASH(pid)        (&pfs_hashtbl[(pid) & pfs_ihash])
1.29      fvdl       61:
                     62: struct lock pfs_hashlock;
                     63: struct simplelock pfs_hash_slock;
1.1       pk         64:
1.20      thorpej    65: #define        ISSET(t, f)     ((t) & (f))
                     66:
1.1       pk         67: /*
1.5       cgd        68:  * allocate a pfsnode/vnode pair.  the vnode is
1.27      wrstuden   69:  * referenced, and locked.
1.5       cgd        70:  *
                     71:  * the pid, pfs_type, and mount point uniquely
                     72:  * identify a pfsnode.  the mount point is needed
                     73:  * because someone might mount this filesystem
                     74:  * twice.
                     75:  *
                     76:  * all pfsnodes are maintained on a singly-linked
                     77:  * list.  new nodes are only allocated when they cannot
                     78:  * be found on this list.  entries on the list are
                     79:  * removed when the vfs reclaim entry is called.
                     80:  *
                     81:  * a single lock is kept for the entire list.  this is
                     82:  * needed because the getnewvnode() function can block
                     83:  * waiting for a vnode to become free, in which case there
                     84:  * may be more than one process trying to get the same
                     85:  * vnode.  this lock is only taken if we are going to
                     86:  * call getnewvnode, since the kernel itself is single-threaded.
                     87:  *
                     88:  * if an entry is found on the list, then call vget() to
                     89:  * take a reference.  this is done because there may be
                     90:  * zero references to it and so it needs to removed from
                     91:  * the vnode free list.
1.1       pk         92:  */
1.11      mycroft    93: int
1.5       cgd        94: procfs_allocvp(mp, vpp, pid, pfs_type)
                     95:        struct mount *mp;
                     96:        struct vnode **vpp;
                     97:        long pid;
                     98:        pfstype pfs_type;
1.1       pk         99: {
1.12      mycroft   100:        struct pfsnode *pfs;
                    101:        struct vnode *vp;
1.5       cgd       102:        int error;
                    103:
1.29      fvdl      104:        do {
                    105:                if ((*vpp = procfs_hashget(pid, pfs_type, mp)) != NULL)
1.5       cgd       106:                        return (0);
1.29      fvdl      107:        } while (lockmgr(&pfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
1.1       pk        108:
1.29      fvdl      109:        if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0) {
                    110:                *vpp = NULL;
                    111:                lockmgr(&pfs_hashlock, LK_RELEASE, 0);
                    112:                return (error);
1.5       cgd       113:        }
1.11      mycroft   114:        vp = *vpp;
1.5       cgd       115:
1.11      mycroft   116:        MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
                    117:        vp->v_data = pfs;
1.5       cgd       118:
                    119:        pfs->pfs_pid = (pid_t) pid;
                    120:        pfs->pfs_type = pfs_type;
1.11      mycroft   121:        pfs->pfs_vnode = vp;
1.5       cgd       122:        pfs->pfs_flags = 0;
                    123:        pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
                    124:
                    125:        switch (pfs_type) {
1.11      mycroft   126:        case Proot:     /* /proc = dr-xr-xr-x */
1.17      mycroft   127:                pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.11      mycroft   128:                vp->v_type = VDIR;
                    129:                vp->v_flag = VROOT;
                    130:                break;
                    131:
1.22      mycroft   132:        case Pcurproc:  /* /proc/curproc = lr-xr-xr-x */
1.28      thorpej   133:        case Pself:     /* /proc/self    = lr-xr-xr-x */
1.22      mycroft   134:                pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.11      mycroft   135:                vp->v_type = VLNK;
1.5       cgd       136:                break;
                    137:
1.17      mycroft   138:        case Pproc:     /* /proc/N = dr-xr-xr-x */
                    139:                pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
1.6       ws        140:                vp->v_type = VDIR;
1.5       cgd       141:                break;
                    142:
1.17      mycroft   143:        case Pfile:     /* /proc/N/file = -rw------- */
                    144:        case Pmem:      /* /proc/N/mem = -rw------- */
                    145:        case Pregs:     /* /proc/N/regs = -rw------- */
                    146:        case Pfpregs:   /* /proc/N/fpregs = -rw------- */
                    147:                pfs->pfs_mode = S_IRUSR|S_IWUSR;
1.9       cgd       148:                vp->v_type = VREG;
                    149:                break;
                    150:
1.17      mycroft   151:        case Pctl:      /* /proc/N/ctl = --w------ */
                    152:        case Pnote:     /* /proc/N/note = --w------ */
                    153:        case Pnotepg:   /* /proc/N/notepg = --w------ */
                    154:                pfs->pfs_mode = S_IWUSR;
1.6       ws        155:                vp->v_type = VREG;
1.5       cgd       156:                break;
                    157:
1.25      msaitoh   158:        case Pmap:      /* /proc/N/map = -r--r--r-- */
1.17      mycroft   159:        case Pstatus:   /* /proc/N/status = -r--r--r-- */
1.26      christos  160:        case Pcmdline:  /* /proc/N/cmdline = -r--r--r-- */
1.17      mycroft   161:                pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
1.6       ws        162:                vp->v_type = VREG;
1.5       cgd       163:                break;
                    164:
                    165:        default:
1.11      mycroft   166:                panic("procfs_allocvp");
1.5       cgd       167:        }
1.27      wrstuden  168:
1.29      fvdl      169:        procfs_hashins(pfs);
                    170:        lockmgr(&pfs_hashlock, LK_RELEASE, 0);
1.1       pk        171:
1.5       cgd       172:        return (error);
1.1       pk        173: }
                    174:
1.11      mycroft   175: int
1.5       cgd       176: procfs_freevp(vp)
                    177:        struct vnode *vp;
1.1       pk        178: {
1.5       cgd       179:        struct pfsnode *pfs = VTOPFS(vp);
                    180:
1.29      fvdl      181:        procfs_hashrem(pfs);
1.1       pk        182:
1.11      mycroft   183:        FREE(vp->v_data, M_TEMP);
                    184:        vp->v_data = 0;
1.5       cgd       185:        return (0);
1.1       pk        186: }
                    187:
1.11      mycroft   188: int
1.15      christos  189: procfs_rw(v)
                    190:        void *v;
1.1       pk        191: {
1.15      christos  192:        struct vop_read_args *ap = v;
1.11      mycroft   193:        struct vnode *vp = ap->a_vp;
                    194:        struct uio *uio = ap->a_uio;
1.5       cgd       195:        struct proc *curp = uio->uio_procp;
                    196:        struct pfsnode *pfs = VTOPFS(vp);
                    197:        struct proc *p;
                    198:
                    199:        p = PFIND(pfs->pfs_pid);
                    200:        if (p == 0)
1.1       pk        201:                return (EINVAL);
1.19      mycroft   202:
                    203:        switch (pfs->pfs_type) {
                    204:        case Pregs:
                    205:        case Pfpregs:
                    206:        case Pmem:
                    207:                /*
                    208:                 * Do not allow init to be modified while in secure mode; it
                    209:                 * could be duped into changing the security level.
                    210:                 */
                    211:                if (uio->uio_rw == UIO_WRITE &&
                    212:                    p == initproc && securelevel > -1)
                    213:                        return (EPERM);
                    214:                break;
                    215:
                    216:        default:
                    217:                break;
                    218:        }
1.1       pk        219:
1.5       cgd       220:        switch (pfs->pfs_type) {
                    221:        case Pnote:
                    222:        case Pnotepg:
1.11      mycroft   223:                return (procfs_donote(curp, p, pfs, uio));
1.5       cgd       224:
                    225:        case Pregs:
1.11      mycroft   226:                return (procfs_doregs(curp, p, pfs, uio));
1.9       cgd       227:
                    228:        case Pfpregs:
1.11      mycroft   229:                return (procfs_dofpregs(curp, p, pfs, uio));
1.5       cgd       230:
                    231:        case Pctl:
1.11      mycroft   232:                return (procfs_doctl(curp, p, pfs, uio));
1.5       cgd       233:
                    234:        case Pstatus:
1.11      mycroft   235:                return (procfs_dostatus(curp, p, pfs, uio));
1.25      msaitoh   236:
                    237:        case Pmap:
                    238:                return (procfs_domap(curp, p, pfs, uio));
1.1       pk        239:
1.5       cgd       240:        case Pmem:
1.11      mycroft   241:                return (procfs_domem(curp, p, pfs, uio));
1.26      christos  242:
                    243:        case Pcmdline:
                    244:                return (procfs_docmdline(curp, p, pfs, uio));
1.1       pk        245:
1.5       cgd       246:        default:
                    247:                return (EOPNOTSUPP);
                    248:        }
1.1       pk        249: }
                    250:
1.5       cgd       251: /*
                    252:  * Get a string from userland into (buf).  Strip a trailing
                    253:  * nl character (to allow easy access from the shell).
1.11      mycroft   254:  * The buffer should be *buflenp + 1 chars long.  vfs_getuserstr
1.5       cgd       255:  * will automatically add a nul char at the end.
                    256:  *
                    257:  * Returns 0 on success or the following errors
                    258:  *
                    259:  * EINVAL:    file offset is non-zero.
                    260:  * EMSGSIZE:  message is longer than kernel buffer
                    261:  * EFAULT:    user i/o buffer is not addressable
                    262:  */
1.11      mycroft   263: int
                    264: vfs_getuserstr(uio, buf, buflenp)
1.5       cgd       265:        struct uio *uio;
                    266:        char *buf;
                    267:        int *buflenp;
1.1       pk        268: {
1.5       cgd       269:        int xlen;
                    270:        int error;
                    271:
1.11      mycroft   272:        if (uio->uio_offset != 0)
                    273:                return (EINVAL);
                    274:
1.5       cgd       275:        xlen = *buflenp;
1.1       pk        276:
1.5       cgd       277:        /* must be able to read the whole string in one go */
                    278:        if (xlen < uio->uio_resid)
                    279:                return (EMSGSIZE);
                    280:        xlen = uio->uio_resid;
                    281:
1.14      christos  282:        if ((error = uiomove(buf, xlen, uio)) != 0)
1.5       cgd       283:                return (error);
                    284:
1.11      mycroft   285:        /* allow multiple writes without seeks */
                    286:        uio->uio_offset = 0;
                    287:
1.5       cgd       288:        /* cleanup string and remove trailing newline */
                    289:        buf[xlen] = '\0';
                    290:        xlen = strlen(buf);
                    291:        if (xlen > 0 && buf[xlen-1] == '\n')
                    292:                buf[--xlen] = '\0';
                    293:        *buflenp = xlen;
1.1       pk        294:
1.5       cgd       295:        return (0);
1.1       pk        296: }
                    297:
1.11      mycroft   298: vfs_namemap_t *
                    299: vfs_findname(nm, buf, buflen)
                    300:        vfs_namemap_t *nm;
1.5       cgd       301:        char *buf;
                    302:        int buflen;
1.1       pk        303: {
1.11      mycroft   304:
1.5       cgd       305:        for (; nm->nm_name; nm++)
1.24      perry     306:                if (memcmp(buf, nm->nm_name, buflen+1) == 0)
1.5       cgd       307:                        return (nm);
                    308:
                    309:        return (0);
1.29      fvdl      310: }
                    311:
                    312: /*
                    313:  * Initialize pfsnode hash table.
                    314:  */
                    315: void
                    316: procfs_hashinit()
                    317: {
                    318:        lockinit(&pfs_hashlock, PINOD, "pfs_hashlock", 0, 0);
1.32    ! ad        319:        pfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT,
        !           320:            M_WAITOK, &pfs_ihash);
1.29      fvdl      321:        simple_lock_init(&pfs_hash_slock);
1.31      jdolecek  322: }
                    323:
                    324: /*
                    325:  * Free pfsnode hash table.
                    326:  */
                    327: void
                    328: procfs_hashdone()
                    329: {
                    330:        hashdone(pfs_hashtbl, M_UFSMNT);
1.29      fvdl      331: }
                    332:
                    333: struct vnode *
                    334: procfs_hashget(pid, type, mp)
                    335:        pid_t pid;
                    336:        pfstype type;
                    337:        struct mount *mp;
                    338: {
                    339:        struct pfsnode *pp;
                    340:        struct vnode *vp;
                    341:
                    342: loop:
                    343:        simple_lock(&pfs_hash_slock);
                    344:        for (pp = PFSPIDHASH(pid)->lh_first; pp; pp = pp->pfs_hash.le_next) {
                    345:                vp = PFSTOV(pp);
                    346:                if (pid == pp->pfs_pid && pp->pfs_type == type &&
                    347:                    vp->v_mount == mp) {
                    348:                        simple_lock(&vp->v_interlock);
                    349:                        simple_unlock(&pfs_hash_slock);
                    350:                        if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
                    351:                                goto loop;
                    352:                        return (vp);
                    353:                }
                    354:        }
                    355:        simple_unlock(&pfs_hash_slock);
                    356:        return (NULL);
                    357: }
                    358:
                    359: /*
                    360:  * Insert the pfsnode into the hash table and lock it.
                    361:  */
                    362: void
                    363: procfs_hashins(pp)
                    364:        struct pfsnode *pp;
                    365: {
                    366:        struct pfs_hashhead *ppp;
                    367:
                    368:        /* lock the pfsnode, then put it on the appropriate hash list */
                    369:        lockmgr(&pp->pfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
                    370:
                    371:        simple_lock(&pfs_hash_slock);
                    372:        ppp = PFSPIDHASH(pp->pfs_pid);
                    373:        LIST_INSERT_HEAD(ppp, pp, pfs_hash);
                    374:        simple_unlock(&pfs_hash_slock);
                    375: }
                    376:
                    377: /*
                    378:  * Remove the pfsnode from the hash table.
                    379:  */
                    380: void
                    381: procfs_hashrem(pp)
                    382:        struct pfsnode *pp;
                    383: {
                    384:        simple_lock(&pfs_hash_slock);
                    385:        LIST_REMOVE(pp, pfs_hash);
                    386:        simple_unlock(&pfs_hash_slock);
                    387: }
                    388:
                    389: void
                    390: procfs_revoke_vnodes(p, arg)
                    391:        struct proc *p;
                    392:        void *arg;
                    393: {
                    394:        struct pfsnode *pfs, *pnext;
                    395:        struct vnode *vp;
                    396:        struct mount *mp = (struct mount *)arg;
                    397:
                    398:        if (!(p->p_flag & P_SUGID))
                    399:                return;
                    400:
                    401:        for (pfs = PFSPIDHASH(p->p_pid)->lh_first; pfs; pfs = pnext) {
                    402:                vp = PFSTOV(pfs);
                    403:                pnext = pfs->pfs_hash.le_next;
                    404:                if (vp->v_usecount > 0 && pfs->pfs_pid == p->p_pid &&
                    405:                    vp->v_mount == mp)
                    406:                        VOP_REVOKE(vp, REVOKEALL);
                    407:        }
1.1       pk        408: }

CVSweb <webmaster@jp.NetBSD.org>