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

Annotation of sys/miscfs/procfs/procfs_vnops.c, Revision 1.1

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

CVSweb