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

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