Annotation of XNU/bsd/miscfs/procfs/procfs_vnops.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*     $NetBSD: procfs_vnops.c,v 1.32 1995/02/03 16:18:55 mycroft Exp $        */
        !            23: 
        !            24: /*
        !            25:  * Copyright (c) 1993 Jan-Simon Pendry
        !            26:  * Copyright (c) 1993
        !            27:  *     The Regents of the University of California.  All rights reserved.
        !            28:  *
        !            29:  * This code is derived from software contributed to Berkeley by
        !            30:  * Jan-Simon Pendry.
        !            31:  *
        !            32:  * Redistribution and use in source and binary forms, with or without
        !            33:  * modification, are permitted provided that the following conditions
        !            34:  * are met:
        !            35:  * 1. Redistributions of source code must retain the above copyright
        !            36:  *    notice, this list of conditions and the following disclaimer.
        !            37:  * 2. Redistributions in binary form must reproduce the above copyright
        !            38:  *    notice, this list of conditions and the following disclaimer in the
        !            39:  *    documentation and/or other materials provided with the distribution.
        !            40:  * 3. All advertising materials mentioning features or use of this software
        !            41:  *    must display the following acknowledgement:
        !            42:  *     This product includes software developed by the University of
        !            43:  *     California, Berkeley and its contributors.
        !            44:  * 4. Neither the name of the University nor the names of its contributors
        !            45:  *    may be used to endorse or promote products derived from this software
        !            46:  *    without specific prior written permission.
        !            47:  *
        !            48:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            49:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            50:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            51:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            52:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            53:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            54:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            55:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            56:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            57:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            58:  * SUCH DAMAGE.
        !            59:  *
        !            60:  *     @(#)procfs_vnops.c      8.8 (Berkeley) 6/15/94
        !            61:  */
        !            62: 
        !            63: /*
        !            64:  * procfs vnode interface
        !            65:  */
        !            66: 
        !            67: #include <sys/param.h>
        !            68: #include <sys/systm.h>
        !            69: #include <sys/time.h>
        !            70: #include <sys/kernel.h>
        !            71: #include <sys/file.h>
        !            72: #include <sys/proc.h>
        !            73: #include <sys/vnode.h>
        !            74: #include <sys/namei.h>
        !            75: #include <sys/malloc.h>
        !            76: #include <sys/dirent.h>
        !            77: #include <sys/resourcevar.h>
        !            78: #include <sys/ptrace.h>
        !            79: #include <vm/vm.h>     /* for PAGE_SIZE */
        !            80: #include <machine/reg.h>
        !            81: #include <vfs/vfs_support.h>
        !            82: #include <miscfs/procfs/procfs.h>
        !            83: 
        !            84: /*
        !            85:  * Vnode Operations.
        !            86:  *
        !            87:  */
        !            88: 
        !            89: /*
        !            90:  * This is a list of the valid names in the
        !            91:  * process-specific sub-directories.  It is
        !            92:  * used in procfs_lookup and procfs_readdir
        !            93:  */
        !            94: struct proc_target {
        !            95:        u_char  pt_type;
        !            96:        u_char  pt_namlen;
        !            97:        char    *pt_name;
        !            98:        pfstype pt_pfstype;
        !            99:        int     (*pt_valid) __P((struct proc *p));
        !           100: } proc_targets[] = {
        !           101: #define N(s) sizeof(s)-1, s
        !           102:        /*        name          type            validp */
        !           103:        { DT_DIR, N("."),       Pproc,          NULL },
        !           104:        { DT_DIR, N(".."),      Proot,          NULL },
        !           105:        { DT_REG, N("file"),    Pfile,          procfs_validfile },
        !           106:        { DT_REG, N("mem"),     Pmem,           NULL },
        !           107:        { DT_REG, N("regs"),    Pregs,          procfs_validregs },
        !           108:        { DT_REG, N("fpregs"),  Pfpregs,        procfs_validfpregs },
        !           109:        { DT_REG, N("ctl"),     Pctl,           NULL },
        !           110:        { DT_REG, N("status"),  Pstatus,        NULL },
        !           111:        { DT_REG, N("note"),    Pnote,          NULL },
        !           112:        { DT_REG, N("notepg"),  Pnotepg,        NULL },
        !           113: #undef N
        !           114: };
        !           115: static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
        !           116: 
        !           117: static pid_t atopid __P((const char *, u_int));
        !           118: 
        !           119: /*
        !           120:  * set things up for doing i/o on
        !           121:  * the pfsnode (vp).  (vp) is locked
        !           122:  * on entry, and should be left locked
        !           123:  * on exit.
        !           124:  *
        !           125:  * for procfs we don't need to do anything
        !           126:  * in particular for i/o.  all that is done
        !           127:  * is to support exclusive open on process
        !           128:  * memory images.
        !           129:  */
        !           130: procfs_open(ap)
        !           131:        struct vop_open_args /* {
        !           132:                struct vnode *a_vp;
        !           133:                int  a_mode;
        !           134:                struct ucred *a_cred;
        !           135:                struct proc *a_p;
        !           136:        } */ *ap;
        !           137: {
        !           138:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        !           139: 
        !           140:        switch (pfs->pfs_type) {
        !           141:        case Pmem:
        !           142:                if (PFIND(pfs->pfs_pid) == 0)
        !           143:                        return (ENOENT);        /* was ESRCH, jsp */
        !           144: 
        !           145:                if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
        !           146:                    (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
        !           147:                        return (EBUSY);
        !           148: 
        !           149:                if (ap->a_mode & FWRITE)
        !           150:                        pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
        !           151: 
        !           152:                return (0);
        !           153: 
        !           154:        default:
        !           155:                break;
        !           156:        }
        !           157: 
        !           158:        return (0);
        !           159: }
        !           160: 
        !           161: /*
        !           162:  * close the pfsnode (vp) after doing i/o.
        !           163:  * (vp) is not locked on entry or exit.
        !           164:  *
        !           165:  * nothing to do for procfs other than undo
        !           166:  * any exclusive open flag (see _open above).
        !           167:  */
        !           168: procfs_close(ap)
        !           169:        struct vop_close_args /* {
        !           170:                struct vnode *a_vp;
        !           171:                int  a_fflag;
        !           172:                struct ucred *a_cred;
        !           173:                struct proc *a_p;
        !           174:        } */ *ap;
        !           175: {
        !           176:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        !           177: 
        !           178:        switch (pfs->pfs_type) {
        !           179:        case Pmem:
        !           180:                if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
        !           181:                        pfs->pfs_flags &= ~(FWRITE|O_EXCL);
        !           182:                break;
        !           183:        }
        !           184: 
        !           185:        return (0);
        !           186: }
        !           187: 
        !           188: /*
        !           189:  * do an ioctl operation on pfsnode (vp).
        !           190:  * (vp) is not locked on entry or exit.
        !           191:  */
        !           192: procfs_ioctl(ap)
        !           193:        struct vop_ioctl_args /* {
        !           194:                struct vnode *a_vp;
        !           195:                u_long a_command;
        !           196:                caddr_t a_data;
        !           197:                int a_fflag;
        !           198:                struct ucred *a_cred;
        !           199:                struct proc *a_p;
        !           200:        } */ *ap;
        !           201: {
        !           202: 
        !           203:        return (ENOTTY);
        !           204: }
        !           205: 
        !           206: /*
        !           207:  * do block mapping for pfsnode (vp).
        !           208:  * since we don't use the buffer cache
        !           209:  * for procfs this function should never
        !           210:  * be called.  in any case, it's not clear
        !           211:  * what part of the kernel ever makes use
        !           212:  * of this function.  for sanity, this is the
        !           213:  * usual no-op bmap, although returning
        !           214:  * (EIO) would be a reasonable alternative.
        !           215:  */
        !           216: procfs_bmap(ap)
        !           217:        struct vop_bmap_args /* {
        !           218:                struct vnode *a_vp;
        !           219:                daddr_t  a_bn;
        !           220:                struct vnode **a_vpp;
        !           221:                daddr_t *a_bnp;
        !           222:        } */ *ap;
        !           223: {
        !           224: 
        !           225:        if (ap->a_vpp != NULL)
        !           226:                *ap->a_vpp = ap->a_vp;
        !           227:        if (ap->a_bnp != NULL)
        !           228:                *ap->a_bnp = ap->a_bn;
        !           229:        return (0);
        !           230: }
        !           231: 
        !           232: /*
        !           233:  * _inactive is called when the pfsnode
        !           234:  * is vrele'd and the reference count goes
        !           235:  * to zero.  (vp) will be on the vnode free
        !           236:  * list, so to get it back vget() must be
        !           237:  * used.
        !           238:  *
        !           239:  * for procfs, check if the process is still
        !           240:  * alive and if it isn't then just throw away
        !           241:  * the vnode by calling vgone().  this may
        !           242:  * be overkill and a waste of time since the
        !           243:  * chances are that the process will still be
        !           244:  * there and PFIND is not free.
        !           245:  *
        !           246:  * (vp) is not locked on entry or exit.
        !           247:  */
        !           248: procfs_inactive(ap)
        !           249:        struct vop_inactive_args /* {
        !           250:                struct vnode *a_vp;
        !           251:        } */ *ap;
        !           252: {
        !           253:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        !           254: 
        !           255:        if (PFIND(pfs->pfs_pid) == 0)
        !           256:                vgone(ap->a_vp);
        !           257: 
        !           258:        return (0);
        !           259: }
        !           260: 
        !           261: /*
        !           262:  * _reclaim is called when getnewvnode()
        !           263:  * wants to make use of an entry on the vnode
        !           264:  * free list.  at this time the filesystem needs
        !           265:  * to free any private data and remove the node
        !           266:  * from any private lists.
        !           267:  */
        !           268: procfs_reclaim(ap)
        !           269:        struct vop_reclaim_args /* {
        !           270:                struct vnode *a_vp;
        !           271:        } */ *ap;
        !           272: {
        !           273: 
        !           274:        return (procfs_freevp(ap->a_vp));
        !           275: }
        !           276: 
        !           277: /*
        !           278:  * Return POSIX pathconf information applicable to special devices.
        !           279:  */
        !           280: procfs_pathconf(ap)
        !           281:        struct vop_pathconf_args /* {
        !           282:                struct vnode *a_vp;
        !           283:                int a_name;
        !           284:                register_t *a_retval;
        !           285:        } */ *ap;
        !           286: {
        !           287: 
        !           288:        switch (ap->a_name) {
        !           289:        case _PC_LINK_MAX:
        !           290:                *ap->a_retval = LINK_MAX;
        !           291:                return (0);
        !           292:        case _PC_MAX_CANON:
        !           293:                *ap->a_retval = MAX_CANON;
        !           294:                return (0);
        !           295:        case _PC_MAX_INPUT:
        !           296:                *ap->a_retval = MAX_INPUT;
        !           297:                return (0);
        !           298:        case _PC_PIPE_BUF:
        !           299:                *ap->a_retval = PIPE_BUF;
        !           300:                return (0);
        !           301:        case _PC_CHOWN_RESTRICTED:
        !           302:                *ap->a_retval = 1;
        !           303:                return (0);
        !           304:        case _PC_VDISABLE:
        !           305:                *ap->a_retval = _POSIX_VDISABLE;
        !           306:                return (0);
        !           307:        default:
        !           308:                return (EINVAL);
        !           309:        }
        !           310:        /* NOTREACHED */
        !           311: }
        !           312: 
        !           313: /*
        !           314:  * _print is used for debugging.
        !           315:  * just print a readable description
        !           316:  * of (vp).
        !           317:  */
        !           318: procfs_print(ap)
        !           319:        struct vop_print_args /* {
        !           320:                struct vnode *a_vp;
        !           321:        } */ *ap;
        !           322: {
        !           323:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        !           324: 
        !           325:        printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n",
        !           326:            pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
        !           327: }
        !           328: 
        !           329: /*
        !           330:  * _abortop is called when operations such as
        !           331:  * rename and create fail.  this entry is responsible
        !           332:  * for undoing any side-effects caused by the lookup.
        !           333:  * this will always include freeing the pathname buffer.
        !           334:  */
        !           335: procfs_abortop(ap)
        !           336:        struct vop_abortop_args /* {
        !           337:                struct vnode *a_dvp;
        !           338:                struct componentname *a_cnp;
        !           339:        } */ *ap;
        !           340: {
        !           341: 
        !           342:        if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
        !           343:                FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
        !           344:        return (0);
        !           345: }
        !           346: 
        !           347: /*
        !           348:  * generic entry point for unsupported operations
        !           349:  */
        !           350: procfs_badop()
        !           351: {
        !           352: 
        !           353:        return (EIO);
        !           354: }
        !           355: 
        !           356: /*
        !           357:  * Invent attributes for pfsnode (vp) and store
        !           358:  * them in (vap).
        !           359:  * Directories lengths are returned as zero since
        !           360:  * any real length would require the genuine size
        !           361:  * to be computed, and nothing cares anyway.
        !           362:  *
        !           363:  * this is relatively minimal for procfs.
        !           364:  */
        !           365: procfs_getattr(ap)
        !           366:        struct vop_getattr_args /* {
        !           367:                struct vnode *a_vp;
        !           368:                struct vattr *a_vap;
        !           369:                struct ucred *a_cred;
        !           370:                struct proc *a_p;
        !           371:        } */ *ap;
        !           372: {
        !           373:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        !           374:        struct vattr *vap = ap->a_vap;
        !           375:        struct proc *procp;
        !           376:        int error;
        !           377: 
        !           378:        /* first check the process still exists */
        !           379:        switch (pfs->pfs_type) {
        !           380:        case Proot:
        !           381:        case Pcurproc:
        !           382:                procp = 0;
        !           383:                break;
        !           384: 
        !           385:        default:
        !           386:                procp = PFIND(pfs->pfs_pid);
        !           387:                if (procp == 0)
        !           388:                        return (ENOENT);
        !           389:        }
        !           390: 
        !           391:        error = 0;
        !           392: 
        !           393:        /* start by zeroing out the attributes */
        !           394:        VATTR_NULL(vap);
        !           395: 
        !           396:        /* next do all the common fields */
        !           397:        vap->va_type = ap->a_vp->v_type;
        !           398:        vap->va_mode = pfs->pfs_mode;
        !           399:        vap->va_fileid = pfs->pfs_fileno;
        !           400:        vap->va_flags = 0;
        !           401:        vap->va_blocksize = PAGE_SIZE;
        !           402:        vap->va_bytes = vap->va_size = 0;
        !           403: 
        !           404:        /*
        !           405:         * Make all times be current TOD.
        !           406:         * It would be possible to get the process start
        !           407:         * time from the p_stat structure, but there's
        !           408:         * no "file creation" time stamp anyway, and the
        !           409:         * p_stat structure is not addressible if u. gets
        !           410:         * swapped out for that process.
        !           411:         *
        !           412:         * XXX
        !           413:         * Note that microtime() returns a timeval, not a timespec.
        !           414:         */
        !           415:        microtime(&vap->va_ctime);
        !           416:        vap->va_atime = vap->va_mtime = vap->va_ctime;
        !           417: 
        !           418:        /*
        !           419:         * If the process has exercised some setuid or setgid
        !           420:         * privilege, then rip away read/write permission so
        !           421:         * that only root can gain access.
        !           422:         */
        !           423:        switch (pfs->pfs_type) {
        !           424:        case Pmem:
        !           425:        case Pregs:
        !           426:        case Pfpregs:
        !           427:                if (procp->p_flag & P_SUGID)
        !           428:                        vap->va_mode &= ~((VREAD|VWRITE)|
        !           429:                                          ((VREAD|VWRITE)>>3)|
        !           430:                                          ((VREAD|VWRITE)>>6));
        !           431:        case Pctl:
        !           432:        case Pstatus:
        !           433:        case Pnote:
        !           434:        case Pnotepg:
        !           435:                vap->va_nlink = 1;
        !           436:                vap->va_uid = procp->p_ucred->cr_uid;
        !           437:                vap->va_gid = procp->p_ucred->cr_gid;
        !           438:                break;
        !           439:        }
        !           440: 
        !           441:        /*
        !           442:         * now do the object specific fields
        !           443:         *
        !           444:         * The size could be set from struct reg, but it's hardly
        !           445:         * worth the trouble, and it puts some (potentially) machine
        !           446:         * dependent data into this machine-independent code.  If it
        !           447:         * becomes important then this function should break out into
        !           448:         * a per-file stat function in the corresponding .c file.
        !           449:         */
        !           450: 
        !           451:        switch (pfs->pfs_type) {
        !           452:        case Proot:
        !           453:                /*
        !           454:                 * Set nlink to 1 to tell fts(3) we don't actually know.
        !           455:                 */
        !           456:                vap->va_nlink = 1;
        !           457:                vap->va_uid = 0;
        !           458:                vap->va_gid = 0;
        !           459:                vap->va_size = vap->va_bytes = DEV_BSIZE;
        !           460:                break;
        !           461: 
        !           462:        case Pcurproc: {
        !           463:                char buf[16];           /* should be enough */
        !           464:                vap->va_nlink = 1;
        !           465:                vap->va_uid = 0;
        !           466:                vap->va_gid = 0;
        !           467:                vap->va_size = vap->va_bytes =
        !           468:                    sprintf(buf, "%ld", (long)curproc->p_pid);
        !           469:                break;
        !           470:        }
        !           471: 
        !           472:        case Pproc:
        !           473:                vap->va_nlink = 2;
        !           474:                vap->va_uid = procp->p_ucred->cr_uid;
        !           475:                vap->va_gid = procp->p_ucred->cr_gid;
        !           476:                vap->va_size = vap->va_bytes = DEV_BSIZE;
        !           477:                break;
        !           478: 
        !           479:        case Pfile:
        !           480:                error = EOPNOTSUPP;
        !           481:                break;
        !           482: 
        !           483:        case Pmem:
        !           484:                vap->va_bytes = vap->va_size =
        !           485:                        ctob(procp->p_vmspace->vm_tsize +
        !           486:                                    procp->p_vmspace->vm_dsize +
        !           487:                                    procp->p_vmspace->vm_ssize);
        !           488:                break;
        !           489: 
        !           490: #if defined(PT_GETREGS) || defined(PT_SETREGS)
        !           491:        case Pregs:
        !           492:                vap->va_bytes = vap->va_size = sizeof(struct reg);
        !           493:                break;
        !           494: #endif
        !           495: 
        !           496: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
        !           497:        case Pfpregs:
        !           498:                vap->va_bytes = vap->va_size = sizeof(struct fpreg);
        !           499:                break;
        !           500: #endif
        !           501: 
        !           502:        case Pctl:
        !           503:        case Pstatus:
        !           504:        case Pnote:
        !           505:        case Pnotepg:
        !           506:                break;
        !           507: 
        !           508:        default:
        !           509:                panic("procfs_getattr");
        !           510:        }
        !           511: 
        !           512:        return (error);
        !           513: }
        !           514: 
        !           515: procfs_setattr(ap)
        !           516:        struct vop_setattr_args /* {
        !           517:                struct vnode *a_vp;
        !           518:                struct vattr *a_vap;
        !           519:                struct ucred *a_cred;
        !           520:                struct proc *a_p;
        !           521:        } */ *ap;
        !           522: {
        !           523:        /*
        !           524:         * just fake out attribute setting
        !           525:         * it's not good to generate an error
        !           526:         * return, otherwise things like creat()
        !           527:         * will fail when they try to set the
        !           528:         * file length to 0.  worse, this means
        !           529:         * that echo $note > /proc/$pid/note will fail.
        !           530:         */
        !           531: 
        !           532:        return (0);
        !           533: }
        !           534: 
        !           535: /*
        !           536:  * implement access checking.
        !           537:  *
        !           538:  * actually, the check for super-user is slightly
        !           539:  * broken since it will allow read access to write-only
        !           540:  * objects.  this doesn't cause any particular trouble
        !           541:  * but does mean that the i/o entry points need to check
        !           542:  * that the operation really does make sense.
        !           543:  */
        !           544: procfs_access(ap)
        !           545:        struct vop_access_args /* {
        !           546:                struct vnode *a_vp;
        !           547:                int a_mode;
        !           548:                struct ucred *a_cred;
        !           549:                struct proc *a_p;
        !           550:        } */ *ap;
        !           551: {
        !           552:        struct vattr va;
        !           553:        int error;
        !           554: 
        !           555:        if (error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p))
        !           556:                return (error);
        !           557: 
        !           558:        return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode,
        !           559:            ap->a_cred));
        !           560: }
        !           561: 
        !           562: /*
        !           563:  * lookup.  this is incredibly complicated in the
        !           564:  * general case, however for most pseudo-filesystems
        !           565:  * very little needs to be done.
        !           566:  *
        !           567:  * unless you want to get a migraine, just make sure your
        !           568:  * filesystem doesn't do any locking of its own.  otherwise
        !           569:  * read and inwardly digest ufs_lookup().
        !           570:  */
        !           571: procfs_lookup(ap)
        !           572:        struct vop_lookup_args /* {
        !           573:                struct vnode * a_dvp;
        !           574:                struct vnode ** a_vpp;
        !           575:                struct componentname * a_cnp;
        !           576:        } */ *ap;
        !           577: {
        !           578:        struct componentname *cnp = ap->a_cnp;
        !           579:        struct vnode **vpp = ap->a_vpp;
        !           580:        struct vnode *dvp = ap->a_dvp;
        !           581:        char *pname = cnp->cn_nameptr;
        !           582:        struct proc_target *pt;
        !           583:        struct vnode *fvp;
        !           584:        pid_t pid;
        !           585:        struct pfsnode *pfs;
        !           586:        struct proc *p;
        !           587:        int i;
        !           588: 
        !           589:        *vpp = NULL;
        !           590: 
        !           591:        if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
        !           592:                return (EROFS);
        !           593: 
        !           594:        if (cnp->cn_namelen == 1 && *pname == '.') {
        !           595:                *vpp = dvp;
        !           596:                VREF(dvp);
        !           597:                /*VOP_LOCK(dvp);*/
        !           598:                return (0);
        !           599:        }
        !           600: 
        !           601:        pfs = VTOPFS(dvp);
        !           602:        switch (pfs->pfs_type) {
        !           603:        case Proot:
        !           604:                if (cnp->cn_flags & ISDOTDOT)
        !           605:                        return (EIO);
        !           606: 
        !           607:                if (CNEQ(cnp, "curproc", 7))
        !           608:                        return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc));
        !           609: 
        !           610:                pid = atopid(pname, cnp->cn_namelen);
        !           611:                if (pid == NO_PID)
        !           612:                        break;
        !           613: 
        !           614:                p = PFIND(pid);
        !           615:                if (p == 0)
        !           616:                        break;
        !           617: 
        !           618:                return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
        !           619: 
        !           620:        case Pproc:
        !           621:                if (cnp->cn_flags & ISDOTDOT)
        !           622:                        return (procfs_root(dvp->v_mount, vpp));
        !           623: 
        !           624:                p = PFIND(pfs->pfs_pid);
        !           625:                if (p == 0)
        !           626:                        break;
        !           627: 
        !           628:                for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
        !           629:                        if (cnp->cn_namelen == pt->pt_namlen &&
        !           630:                            bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
        !           631:                            (pt->pt_valid == NULL || (*pt->pt_valid)(p)))
        !           632:                                goto found;
        !           633:                }
        !           634:                break;
        !           635: 
        !           636:        found:
        !           637:                if (pt->pt_pfstype == Pfile) {
        !           638:                        fvp = procfs_findtextvp(p);
        !           639:                        /* We already checked that it exists. */
        !           640:                        VREF(fvp);
        !           641:                        VOP_LOCK(fvp);
        !           642:                        *vpp = fvp;
        !           643:                        return (0);
        !           644:                }
        !           645: 
        !           646:                return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
        !           647:                    pt->pt_pfstype));
        !           648: 
        !           649:        default:
        !           650:                return (ENOTDIR);
        !           651:        }
        !           652: 
        !           653:        return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
        !           654: }
        !           655: 
        !           656: int
        !           657: procfs_validfile(p)
        !           658:        struct proc *p;
        !           659: {
        !           660: 
        !           661:        return (procfs_findtextvp(p) != NULLVP);
        !           662: }
        !           663: 
        !           664: /*
        !           665:  * readdir returns directory entries from pfsnode (vp).
        !           666:  *
        !           667:  * the strategy here with procfs is to generate a single
        !           668:  * directory entry at a time (struct pfsdent) and then
        !           669:  * copy that out to userland using uiomove.  a more efficent
        !           670:  * though more complex implementation, would try to minimize
        !           671:  * the number of calls to uiomove().  for procfs, this is
        !           672:  * hardly worth the added code complexity.
        !           673:  *
        !           674:  * this should just be done through read()
        !           675:  */
        !           676: procfs_readdir(ap)
        !           677:        struct vop_readdir_args /* {
        !           678:                struct vnode *a_vp;
        !           679:                struct uio *a_uio;
        !           680:                struct ucred *a_cred;
        !           681:                int *a_eofflag;
        !           682:                u_long *a_cookies;
        !           683:                int a_ncookies;
        !           684:        } */ *ap;
        !           685: {
        !           686:        struct uio *uio = ap->a_uio;
        !           687:        struct pfsdent d;
        !           688:        struct pfsdent *dp = &d;
        !           689:        struct pfsnode *pfs;
        !           690:        int error;
        !           691:        int count;
        !           692:        int i;
        !           693: 
        !           694:        /*
        !           695:         * We don't allow exporting procfs mounts, and currently local
        !           696:         * requests do not need cookies.
        !           697:         */
        !           698:        if (ap->a_ncookies)
        !           699:                panic("procfs_readdir: not hungry");
        !           700: 
        !           701:        pfs = VTOPFS(ap->a_vp);
        !           702: 
        !           703:        if (uio->uio_resid < UIO_MX)
        !           704:                return (EINVAL);
        !           705:        if (uio->uio_offset & (UIO_MX-1))
        !           706:                return (EINVAL);
        !           707:        if (uio->uio_offset < 0)
        !           708:                return (EINVAL);
        !           709: 
        !           710:        error = 0;
        !           711:        count = 0;
        !           712:        i = uio->uio_offset / UIO_MX;
        !           713: 
        !           714:        switch (pfs->pfs_type) {
        !           715:        /*
        !           716:         * this is for the process-specific sub-directories.
        !           717:         * all that is needed to is copy out all the entries
        !           718:         * from the procent[] table (top of this file).
        !           719:         */
        !           720:        case Pproc: {
        !           721:                struct proc *p;
        !           722:                struct proc_target *pt;
        !           723: 
        !           724:                p = PFIND(pfs->pfs_pid);
        !           725:                if (p == NULL)
        !           726:                        break;
        !           727: 
        !           728:                for (pt = &proc_targets[i];
        !           729:                     uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
        !           730:                        if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
        !           731:                                continue;
        !           732:                        
        !           733:                        dp->d_reclen = UIO_MX;
        !           734:                        dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
        !           735:                        dp->d_namlen = pt->pt_namlen;
        !           736:                        bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1);
        !           737:                        dp->d_type = pt->pt_type;
        !           738: 
        !           739:                        if (error = uiomove((caddr_t)dp, UIO_MX, uio))
        !           740:                                break;
        !           741:                }
        !           742: 
        !           743:                break;
        !           744:            }
        !           745: 
        !           746:        /*
        !           747:         * this is for the root of the procfs filesystem
        !           748:         * what is needed is a special entry for "curproc"
        !           749:         * followed by an entry for each process on allproc
        !           750: #ifdef PROCFS_ZOMBIE
        !           751:         * and zombproc.
        !           752: #endif
        !           753:         */
        !           754: 
        !           755:        case Proot: {
        !           756: #ifdef PROCFS_ZOMBIE
        !           757:                int doingzomb = 0;
        !           758: #endif
        !           759:                int pcnt = 0;
        !           760:                volatile struct proc *p = allproc.lh_first;
        !           761: 
        !           762:        again:
        !           763:                for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
        !           764:                        bzero((char *) dp, UIO_MX);
        !           765:                        dp->d_reclen = UIO_MX;
        !           766: 
        !           767:                        switch (i) {
        !           768:                        case 0:         /* `.' */
        !           769:                        case 1:         /* `..' */
        !           770:                                dp->d_fileno = PROCFS_FILENO(0, Proot);
        !           771:                                dp->d_namlen = i + 1;
        !           772:                                bcopy("..", dp->d_name, dp->d_namlen);
        !           773:                                dp->d_name[i + 1] = '\0';
        !           774:                                dp->d_type = DT_DIR;
        !           775:                                break;
        !           776: 
        !           777:                        case 2:
        !           778:                                dp->d_fileno = PROCFS_FILENO(0, Pcurproc);
        !           779:                                dp->d_namlen = 7;
        !           780:                                bcopy("curproc", dp->d_name, 8);
        !           781:                                dp->d_type = DT_LNK;
        !           782:                                break;
        !           783: 
        !           784:                        default:
        !           785:                                while (pcnt < i) {
        !           786:                                        pcnt++;
        !           787:                                        p = p->p_list.le_next;
        !           788:                                        if (!p)
        !           789:                                                goto done;
        !           790:                                }
        !           791:                                dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
        !           792:                                dp->d_namlen = sprintf(dp->d_name, "%ld",
        !           793:                                    (long)p->p_pid);
        !           794:                                dp->d_type = DT_REG;
        !           795:                                p = p->p_list.le_next;
        !           796:                                break;
        !           797:                        }
        !           798: 
        !           799:                        if (error = uiomove((caddr_t)dp, UIO_MX, uio))
        !           800:                                break;
        !           801:                }
        !           802:        done:
        !           803: 
        !           804: #ifdef PROCFS_ZOMBIE
        !           805:                if (p == 0 && doingzomb == 0) {
        !           806:                        doingzomb = 1;
        !           807:                        p = zombproc.lh_first;
        !           808:                        goto again;
        !           809:                }
        !           810: #endif
        !           811: 
        !           812:                break;
        !           813: 
        !           814:            }
        !           815: 
        !           816:        default:
        !           817:                error = ENOTDIR;
        !           818:                break;
        !           819:        }
        !           820: 
        !           821:        uio->uio_offset = i * UIO_MX;
        !           822: 
        !           823:        return (error);
        !           824: }
        !           825: 
        !           826: /*
        !           827:  * readlink reads the link of `curproc'
        !           828:  */
        !           829: procfs_readlink(ap)
        !           830:        struct vop_readlink_args *ap;
        !           831: {
        !           832:        struct uio *uio = ap->a_uio;
        !           833:        char buf[16];           /* should be enough */
        !           834:        int len;
        !           835: 
        !           836:        if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc))
        !           837:                return (EINVAL);
        !           838: 
        !           839:        len = sprintf(buf, "%ld", (long)curproc->p_pid);
        !           840: 
        !           841:        return (uiomove((caddr_t)buf, len, ap->a_uio));
        !           842: }
        !           843: 
        !           844: /*
        !           845:  * convert decimal ascii to pid_t
        !           846:  */
        !           847: static pid_t
        !           848: atopid(b, len)
        !           849:        const char *b;
        !           850:        u_int len;
        !           851: {
        !           852:        pid_t p = 0;
        !           853: 
        !           854:        while (len--) {
        !           855:                char c = *b++;
        !           856:                if (c < '0' || c > '9')
        !           857:                        return (NO_PID);
        !           858:                p = 10 * p + (c - '0');
        !           859:                if (p > PID_MAX)
        !           860:                        return (NO_PID);
        !           861:        }
        !           862: 
        !           863:        return (p);
        !           864: }
        !           865: 
        !           866: /*
        !           867:  * procfs vnode operations.
        !           868:  */
        !           869: int (**procfs_vnodeop_p)();
        !           870: struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
        !           871:        { &vop_default_desc, vn_default_error },
        !           872:        { &vop_lookup_desc, procfs_lookup },            /* lookup */
        !           873:        { &vop_create_desc, procfs_create },            /* create */
        !           874:        { &vop_mknod_desc, procfs_mknod },              /* mknod */
        !           875:        { &vop_open_desc, procfs_open },                /* open */
        !           876:        { &vop_close_desc, procfs_close },              /* close */
        !           877:        { &vop_access_desc, procfs_access },            /* access */
        !           878:        { &vop_getattr_desc, procfs_getattr },          /* getattr */
        !           879:        { &vop_setattr_desc, procfs_setattr },          /* setattr */
        !           880:        { &vop_read_desc, procfs_read },                /* read */
        !           881:        { &vop_write_desc, procfs_write },              /* write */
        !           882:        { &vop_ioctl_desc, procfs_ioctl },              /* ioctl */
        !           883:        { &vop_select_desc, procfs_select },            /* select */
        !           884:        { &vop_mmap_desc, procfs_mmap },                /* mmap */
        !           885:        { &vop_fsync_desc, procfs_fsync },              /* fsync */
        !           886:        { &vop_seek_desc, procfs_seek },                /* seek */
        !           887:        { &vop_remove_desc, procfs_remove },            /* remove */
        !           888:        { &vop_link_desc, procfs_link },                /* link */
        !           889:        { &vop_rename_desc, procfs_rename },            /* rename */
        !           890:        { &vop_mkdir_desc, procfs_mkdir },              /* mkdir */
        !           891:        { &vop_rmdir_desc, procfs_rmdir },              /* rmdir */
        !           892:        { &vop_symlink_desc, procfs_symlink },          /* symlink */
        !           893:        { &vop_readdir_desc, procfs_readdir },          /* readdir */
        !           894:        { &vop_readlink_desc, procfs_readlink },        /* readlink */
        !           895:        { &vop_abortop_desc, procfs_abortop },          /* abortop */
        !           896:        { &vop_inactive_desc, procfs_inactive },        /* inactive */
        !           897:        { &vop_reclaim_desc, procfs_reclaim },          /* reclaim */
        !           898:        { &vop_lock_desc, procfs_lock },                /* lock */
        !           899:        { &vop_unlock_desc, procfs_unlock },            /* unlock */
        !           900:        { &vop_bmap_desc, procfs_bmap },                /* bmap */
        !           901:        { &vop_strategy_desc, procfs_strategy },        /* strategy */
        !           902:        { &vop_print_desc, procfs_print },              /* print */
        !           903:        { &vop_islocked_desc, procfs_islocked },        /* islocked */
        !           904:        { &vop_pathconf_desc, procfs_pathconf },        /* pathconf */
        !           905:        { &vop_advlock_desc, procfs_advlock },          /* advlock */
        !           906:        { &vop_blkatoff_desc, procfs_blkatoff },        /* blkatoff */
        !           907:        { &vop_valloc_desc, procfs_valloc },            /* valloc */
        !           908:        { &vop_vfree_desc, procfs_vfree },              /* vfree */
        !           909:        { &vop_truncate_desc, procfs_truncate },        /* truncate */
        !           910:        { &vop_update_desc, procfs_update },            /* update */
        !           911:         { &vop_copyfile_desc, err_copyfile },                /* Copyfile */
        !           912: { (struct vnodeop_desc*)NULL, (int(*)())NULL }
        !           913: };
        !           914: struct vnodeopv_desc procfs_vnodeop_opv_desc =
        !           915:        { &procfs_vnodeop_p, procfs_vnodeop_entries };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.