Annotation of kernel/bsd/miscfs/procfs/procfs_vnops.c, revision 1.1.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.