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

Annotation of src/sys/miscfs/procfs/procfs_vnops.c, Revision 1.123.2.4

1.123.2.4! yamt        1: /*     $NetBSD: procfs_vnops.c,v 1.123.2.3 2007/02/26 09:11:31 yamt Exp $      */
1.123.2.3  yamt        2:
                      3: /*-
                      4:  * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Andrew Doran.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the NetBSD
                     21:  *     Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
1.24      cgd        38:
1.1       pk         39: /*
1.53      fvdl       40:  * Copyright (c) 1993, 1995
1.21      mycroft    41:  *     The Regents of the University of California.  All rights reserved.
1.2       pk         42:  *
1.9       cgd        43:  * This code is derived from software contributed to Berkeley by
                     44:  * Jan-Simon Pendry.
                     45:  *
1.2       pk         46:  * Redistribution and use in source and binary forms, with or without
                     47:  * modification, are permitted provided that the following conditions
                     48:  * are met:
                     49:  * 1. Redistributions of source code must retain the above copyright
                     50:  *    notice, this list of conditions and the following disclaimer.
                     51:  * 2. Redistributions in binary form must reproduce the above copyright
                     52:  *    notice, this list of conditions and the following disclaimer in the
                     53:  *    documentation and/or other materials provided with the distribution.
1.107     agc        54:  * 3. Neither the name of the University nor the names of its contributors
                     55:  *    may be used to endorse or promote products derived from this software
                     56:  *    without specific prior written permission.
                     57:  *
                     58:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     59:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     60:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     61:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     62:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     63:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     64:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     65:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     66:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     67:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     68:  * SUCH DAMAGE.
                     69:  *
                     70:  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
                     71:  */
                     72:
                     73: /*
                     74:  * Copyright (c) 1993 Jan-Simon Pendry
                     75:  *
                     76:  * This code is derived from software contributed to Berkeley by
                     77:  * Jan-Simon Pendry.
                     78:  *
                     79:  * Redistribution and use in source and binary forms, with or without
                     80:  * modification, are permitted provided that the following conditions
                     81:  * are met:
                     82:  * 1. Redistributions of source code must retain the above copyright
                     83:  *    notice, this list of conditions and the following disclaimer.
                     84:  * 2. Redistributions in binary form must reproduce the above copyright
                     85:  *    notice, this list of conditions and the following disclaimer in the
                     86:  *    documentation and/or other materials provided with the distribution.
1.2       pk         87:  * 3. All advertising materials mentioning features or use of this software
                     88:  *    must display the following acknowledgement:
1.9       cgd        89:  *     This product includes software developed by the University of
                     90:  *     California, Berkeley and its contributors.
                     91:  * 4. Neither the name of the University nor the names of its contributors
                     92:  *    may be used to endorse or promote products derived from this software
                     93:  *    without specific prior written permission.
                     94:  *
                     95:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     96:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     97:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     98:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     99:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                    100:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                    101:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                    102:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                    103:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                    104:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                    105:  * SUCH DAMAGE.
1.2       pk        106:  *
1.53      fvdl      107:  *     @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
1.2       pk        108:  */
                    109:
                    110: /*
1.9       cgd       111:  * procfs vnode interface
1.1       pk        112:  */
1.85      lukem     113:
                    114: #include <sys/cdefs.h>
1.123.2.4! yamt      115: __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.123.2.3 2007/02/26 09:11:31 yamt Exp $");
1.1       pk        116:
1.8       mycroft   117: #include <sys/param.h>
                    118: #include <sys/systm.h>
                    119: #include <sys/time.h>
                    120: #include <sys/kernel.h>
                    121: #include <sys/file.h>
1.91      christos  122: #include <sys/filedesc.h>
1.8       mycroft   123: #include <sys/proc.h>
                    124: #include <sys/vnode.h>
                    125: #include <sys/namei.h>
1.9       cgd       126: #include <sys/malloc.h>
1.76      fvdl      127: #include <sys/mount.h>
1.21      mycroft   128: #include <sys/dirent.h>
1.8       mycroft   129: #include <sys/resourcevar.h>
1.48      mycroft   130: #include <sys/stat.h>
1.89      thorpej   131: #include <sys/ptrace.h>
1.123.2.1  yamt      132: #include <sys/kauth.h>
1.48      mycroft   133:
1.71      mrg       134: #include <uvm/uvm_extern.h>    /* for PAGE_SIZE */
1.48      mycroft   135:
1.21      mycroft   136: #include <machine/reg.h>
1.41      mycroft   137:
                    138: #include <miscfs/genfs/genfs.h>
1.9       cgd       139: #include <miscfs/procfs/procfs.h>
1.11      cgd       140:
1.9       cgd       141: /*
                    142:  * Vnode Operations.
                    143:  *
                    144:  */
1.1       pk        145:
1.123.2.1  yamt      146: static int procfs_validfile_linux(struct lwp *, struct mount *);
1.117     yamt      147: static int procfs_root_readdir_callback(struct proc *, void *);
1.123.2.1  yamt      148: static struct vnode *procfs_dir(pfstype, struct lwp *, struct proc *,
                    149:                                char **, char *, int);
1.74      tv        150:
1.1       pk        151: /*
1.9       cgd       152:  * This is a list of the valid names in the
                    153:  * process-specific sub-directories.  It is
                    154:  * used in procfs_lookup and procfs_readdir
                    155:  */
1.97      jdolecek  156: static const struct proc_target {
1.32      mycroft   157:        u_char  pt_type;
                    158:        u_char  pt_namlen;
1.97      jdolecek  159:        const char      *pt_name;
1.32      mycroft   160:        pfstype pt_pfstype;
1.123.2.1  yamt      161:        int     (*pt_valid)(struct lwp *, struct mount *);
1.32      mycroft   162: } proc_targets[] = {
1.9       cgd       163: #define N(s) sizeof(s)-1, s
1.32      mycroft   164:        /*        name          type            validp */
1.123.2.2  yamt      165:        { DT_DIR, N("."),       PFSproc,        NULL },
                    166:        { DT_DIR, N(".."),      PFSroot,        NULL },
1.109     darcy     167:        { DT_DIR, N("fd"),      PFSfd,          NULL },
1.123.2.2  yamt      168:        { DT_REG, N("file"),    PFSfile,        procfs_validfile },
1.109     darcy     169:        { DT_REG, N("mem"),     PFSmem,         NULL },
1.123.2.2  yamt      170:        { DT_REG, N("regs"),    PFSregs,        procfs_validregs },
1.109     darcy     171:        { DT_REG, N("fpregs"),  PFSfpregs,      procfs_validfpregs },
                    172:        { DT_REG, N("ctl"),     PFSctl,         NULL },
1.123.2.2  yamt      173:        { DT_REG, N("stat"),    PFSstat,        procfs_validfile_linux },
1.109     darcy     174:        { DT_REG, N("status"),  PFSstatus,      NULL },
1.123.2.2  yamt      175:        { DT_REG, N("note"),    PFSnote,        NULL },
1.109     darcy     176:        { DT_REG, N("notepg"),  PFSnotepg,      NULL },
                    177:        { DT_REG, N("map"),     PFSmap,         procfs_validmap },
1.123.2.2  yamt      178:        { DT_REG, N("maps"),    PFSmaps,        procfs_validmap },
1.109     darcy     179:        { DT_REG, N("cmdline"), PFScmdline,     NULL },
1.123.2.2  yamt      180:        { DT_REG, N("exe"),     PFSexe,         procfs_validfile },
1.123.2.1  yamt      181:        { DT_LNK, N("cwd"),     PFScwd,         NULL },
                    182:        { DT_LNK, N("root"),    PFSchroot,      NULL },
1.123.2.2  yamt      183:        { DT_LNK, N("emul"),    PFSemul,        NULL },
1.123.2.4! yamt      184:        { DT_REG, N("statm"),   PFSstatm,       procfs_validfile_linux },
1.86      thorpej   185: #ifdef __HAVE_PROCFS_MACHDEP
                    186:        PROCFS_MACHDEP_NODETYPE_DEFNS
                    187: #endif
1.9       cgd       188: #undef N
1.1       pk        189: };
1.97      jdolecek  190: static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
1.1       pk        191:
1.76      fvdl      192: /*
                    193:  * List of files in the root directory. Note: the validate function will
                    194:  * be called with p == NULL for these ones.
                    195:  */
1.97      jdolecek  196: static const struct proc_target proc_root_targets[] = {
1.76      fvdl      197: #define N(s) sizeof(s)-1, s
                    198:        /*        name              type            validp */
1.109     darcy     199:        { DT_REG, N("meminfo"),     PFSmeminfo,        procfs_validfile_linux },
                    200:        { DT_REG, N("cpuinfo"),     PFScpuinfo,        procfs_validfile_linux },
                    201:        { DT_REG, N("uptime"),      PFSuptime,         procfs_validfile_linux },
1.114     jdolecek  202:        { DT_REG, N("mounts"),      PFSmounts,         procfs_validfile_linux },
1.123.2.2  yamt      203:        { DT_REG, N("devices"),     PFSdevices,        procfs_validfile_linux },
1.123.2.4! yamt      204:        { DT_REG, N("stat"),        PFScpustat,        procfs_validfile_linux },
        !           205:        { DT_REG, N("loadavg"),     PFSloadavg,        procfs_validfile_linux },
1.76      fvdl      206: #undef N
                    207: };
1.97      jdolecek  208: static const int nproc_root_targets =
1.76      fvdl      209:     sizeof(proc_root_targets) / sizeof(proc_root_targets[0]);
                    210:
1.123.2.1  yamt      211: int    procfs_lookup(void *);
1.96      jdolecek  212: #define        procfs_create   genfs_eopnotsupp
                    213: #define        procfs_mknod    genfs_eopnotsupp
1.123.2.1  yamt      214: int    procfs_open(void *);
                    215: int    procfs_close(void *);
                    216: int    procfs_access(void *);
                    217: int    procfs_getattr(void *);
                    218: int    procfs_setattr(void *);
1.37      christos  219: #define        procfs_read     procfs_rw
                    220: #define        procfs_write    procfs_rw
1.65      wrstuden  221: #define        procfs_fcntl    genfs_fcntl
1.57      matthias  222: #define        procfs_ioctl    genfs_enoioctl
1.42      mycroft   223: #define        procfs_poll     genfs_poll
1.53      fvdl      224: #define procfs_revoke  genfs_revoke
1.41      mycroft   225: #define        procfs_fsync    genfs_nullop
                    226: #define        procfs_seek     genfs_nullop
1.96      jdolecek  227: #define        procfs_remove   genfs_eopnotsupp
1.123.2.1  yamt      228: int    procfs_link(void *);
1.96      jdolecek  229: #define        procfs_rename   genfs_eopnotsupp
                    230: #define        procfs_mkdir    genfs_eopnotsupp
                    231: #define        procfs_rmdir    genfs_eopnotsupp
1.123.2.1  yamt      232: int    procfs_symlink(void *);
                    233: int    procfs_readdir(void *);
                    234: int    procfs_readlink(void *);
1.41      mycroft   235: #define        procfs_abortop  genfs_abortop
1.123.2.1  yamt      236: int    procfs_inactive(void *);
                    237: int    procfs_reclaim(void *);
1.62      wrstuden  238: #define        procfs_lock     genfs_lock
                    239: #define        procfs_unlock   genfs_unlock
1.82      chs       240: #define        procfs_bmap     genfs_badop
1.41      mycroft   241: #define        procfs_strategy genfs_badop
1.123.2.1  yamt      242: int    procfs_print(void *);
                    243: int    procfs_pathconf(void *);
1.62      wrstuden  244: #define        procfs_islocked genfs_islocked
1.58      kleink    245: #define        procfs_advlock  genfs_einval
1.41      mycroft   246: #define        procfs_bwrite   genfs_eopnotsupp
1.87      chs       247: #define procfs_putpages        genfs_null_putpages
1.37      christos  248:
1.123.2.1  yamt      249: static int atoi(const char *, size_t);
1.37      christos  250:
                    251: /*
                    252:  * procfs vnode operations.
                    253:  */
1.123.2.1  yamt      254: int (**procfs_vnodeop_p)(void *);
1.77      jdolecek  255: const struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
1.37      christos  256:        { &vop_default_desc, vn_default_error },
                    257:        { &vop_lookup_desc, procfs_lookup },            /* lookup */
                    258:        { &vop_create_desc, procfs_create },            /* create */
                    259:        { &vop_mknod_desc, procfs_mknod },              /* mknod */
                    260:        { &vop_open_desc, procfs_open },                /* open */
                    261:        { &vop_close_desc, procfs_close },              /* close */
                    262:        { &vop_access_desc, procfs_access },            /* access */
                    263:        { &vop_getattr_desc, procfs_getattr },          /* getattr */
                    264:        { &vop_setattr_desc, procfs_setattr },          /* setattr */
                    265:        { &vop_read_desc, procfs_read },                /* read */
                    266:        { &vop_write_desc, procfs_write },              /* write */
1.65      wrstuden  267:        { &vop_fcntl_desc, procfs_fcntl },              /* fcntl */
1.37      christos  268:        { &vop_ioctl_desc, procfs_ioctl },              /* ioctl */
1.42      mycroft   269:        { &vop_poll_desc, procfs_poll },                /* poll */
1.53      fvdl      270:        { &vop_revoke_desc, procfs_revoke },            /* revoke */
1.37      christos  271:        { &vop_fsync_desc, procfs_fsync },              /* fsync */
                    272:        { &vop_seek_desc, procfs_seek },                /* seek */
                    273:        { &vop_remove_desc, procfs_remove },            /* remove */
                    274:        { &vop_link_desc, procfs_link },                /* link */
                    275:        { &vop_rename_desc, procfs_rename },            /* rename */
                    276:        { &vop_mkdir_desc, procfs_mkdir },              /* mkdir */
                    277:        { &vop_rmdir_desc, procfs_rmdir },              /* rmdir */
                    278:        { &vop_symlink_desc, procfs_symlink },          /* symlink */
                    279:        { &vop_readdir_desc, procfs_readdir },          /* readdir */
                    280:        { &vop_readlink_desc, procfs_readlink },        /* readlink */
                    281:        { &vop_abortop_desc, procfs_abortop },          /* abortop */
                    282:        { &vop_inactive_desc, procfs_inactive },        /* inactive */
                    283:        { &vop_reclaim_desc, procfs_reclaim },          /* reclaim */
                    284:        { &vop_lock_desc, procfs_lock },                /* lock */
                    285:        { &vop_unlock_desc, procfs_unlock },            /* unlock */
                    286:        { &vop_bmap_desc, procfs_bmap },                /* bmap */
                    287:        { &vop_strategy_desc, procfs_strategy },        /* strategy */
                    288:        { &vop_print_desc, procfs_print },              /* print */
                    289:        { &vop_islocked_desc, procfs_islocked },        /* islocked */
                    290:        { &vop_pathconf_desc, procfs_pathconf },        /* pathconf */
                    291:        { &vop_advlock_desc, procfs_advlock },          /* advlock */
1.87      chs       292:        { &vop_putpages_desc, procfs_putpages },        /* putpages */
1.82      chs       293:        { NULL, NULL }
1.37      christos  294: };
1.77      jdolecek  295: const struct vnodeopv_desc procfs_vnodeop_opv_desc =
1.37      christos  296:        { &procfs_vnodeop_p, procfs_vnodeop_entries };
                    297: /*
1.9       cgd       298:  * set things up for doing i/o on
                    299:  * the pfsnode (vp).  (vp) is locked
                    300:  * on entry, and should be left locked
                    301:  * on exit.
1.1       pk        302:  *
1.9       cgd       303:  * for procfs we don't need to do anything
                    304:  * in particular for i/o.  all that is done
                    305:  * is to support exclusive open on process
                    306:  * memory images.
1.1       pk        307:  */
1.37      christos  308: int
                    309: procfs_open(v)
                    310:        void *v;
                    311: {
1.22      mycroft   312:        struct vop_open_args /* {
                    313:                struct vnode *a_vp;
                    314:                int  a_mode;
1.123.2.1  yamt      315:                kauth_cred_t a_cred;
                    316:                struct lwp *a_l;
1.37      christos  317:        } */ *ap = v;
1.21      mycroft   318:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.123.2.1  yamt      319:        struct lwp *l1;
                    320:        struct proc *p2;
1.88      christos  321:        int error;
1.50      thorpej   322:
1.123.2.3  yamt      323:        if ((error = procfs_proc_lock(pfs->pfs_pid, &p2, ENOENT)) != 0)
                    324:                return error;
1.9       cgd       325:
1.123.2.3  yamt      326:        l1 = ap->a_l;                           /* tracer */
1.123.2.2  yamt      327:
                    328: #define        M2K(m)  (((m) & FREAD) && ((m) & FWRITE) ? \
                    329:                 KAUTH_REQ_PROCESS_CANPROCFS_RW : \
                    330:                 (m) & FWRITE ? KAUTH_REQ_PROCESS_CANPROCFS_WRITE : \
                    331:                 KAUTH_REQ_PROCESS_CANPROCFS_READ)
                    332:
1.123.2.3  yamt      333:        mutex_enter(&p2->p_mutex);
1.123.2.2  yamt      334:        error = kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_CANPROCFS,
                    335:            p2, pfs, KAUTH_ARG(M2K(ap->a_mode)), NULL);
1.123.2.3  yamt      336:        mutex_exit(&p2->p_mutex);
1.123.2.2  yamt      337:        if (error)
                    338:                return (error);
                    339:
                    340: #undef M2K
                    341:
1.9       cgd       342:        switch (pfs->pfs_type) {
1.109     darcy     343:        case PFSmem:
1.37      christos  344:                if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
1.123.2.3  yamt      345:                    ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) {
                    346:                        error = EBUSY;
                    347:                        break;
                    348:                }
1.50      thorpej   349:
1.123.2.2  yamt      350:                if (!proc_isunder(p2, l1))
                    351:                        return (EPERM);
1.1       pk        352:
1.21      mycroft   353:                if (ap->a_mode & FWRITE)
                    354:                        pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
1.1       pk        355:
1.123.2.2  yamt      356:                break;
                    357:
                    358:        case PFSregs:
                    359:        case PFSfpregs:
                    360:                if (!proc_isunder(p2, l1))
                    361:                        return (EPERM);
                    362:
                    363:                break;
1.1       pk        364:
1.9       cgd       365:        default:
                    366:                break;
                    367:        }
1.1       pk        368:
1.123.2.3  yamt      369:        procfs_proc_unlock(p2);
                    370:        return (error);
1.1       pk        371: }
                    372:
                    373: /*
1.9       cgd       374:  * close the pfsnode (vp) after doing i/o.
                    375:  * (vp) is not locked on entry or exit.
                    376:  *
                    377:  * nothing to do for procfs other than undo
                    378:  * any exclusive open flag (see _open above).
1.1       pk        379:  */
1.37      christos  380: int
                    381: procfs_close(v)
                    382:        void *v;
                    383: {
1.22      mycroft   384:        struct vop_close_args /* {
                    385:                struct vnode *a_vp;
                    386:                int  a_fflag;
1.123.2.1  yamt      387:                kauth_cred_t a_cred;
                    388:                struct lwp *a_l;
1.37      christos  389:        } */ *ap = v;
1.21      mycroft   390:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.1       pk        391:
1.9       cgd       392:        switch (pfs->pfs_type) {
1.109     darcy     393:        case PFSmem:
1.21      mycroft   394:                if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
1.9       cgd       395:                        pfs->pfs_flags &= ~(FWRITE|O_EXCL);
                    396:                break;
1.46      mycroft   397:
                    398:        default:
1.37      christos  399:                break;
1.9       cgd       400:        }
1.1       pk        401:
                    402:        return (0);
                    403: }
                    404:
                    405: /*
1.9       cgd       406:  * _inactive is called when the pfsnode
                    407:  * is vrele'd and the reference count goes
                    408:  * to zero.  (vp) will be on the vnode free
                    409:  * list, so to get it back vget() must be
                    410:  * used.
                    411:  *
                    412:  * for procfs, check if the process is still
                    413:  * alive and if it isn't then just throw away
                    414:  * the vnode by calling vgone().  this may
                    415:  * be overkill and a waste of time since the
                    416:  * chances are that the process will still be
1.123.2.3  yamt      417:  * there.
1.9       cgd       418:  *
1.62      wrstuden  419:  * (vp) is locked on entry, but must be unlocked on exit.
1.1       pk        420:  */
1.37      christos  421: int
                    422: procfs_inactive(v)
                    423:        void *v;
                    424: {
1.22      mycroft   425:        struct vop_inactive_args /* {
                    426:                struct vnode *a_vp;
1.53      fvdl      427:                struct proc *a_p;
1.37      christos  428:        } */ *ap = v;
1.122     christos  429:        struct vnode *vp = ap->a_vp;
                    430:        struct pfsnode *pfs = VTOPFS(vp);
1.123.2.3  yamt      431:        struct proc *p;
                    432:        int error;
1.1       pk        433:
1.122     christos  434:        VOP_UNLOCK(vp, 0);
1.123.2.3  yamt      435:
                    436:        error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH);
                    437:        if (error != 0 && (vp->v_flag & VXLOCK) == 0)
1.122     christos  438:                vgone(vp);
1.123.2.3  yamt      439:        else
                    440:                procfs_proc_unlock(p);
1.5       pk        441:
1.9       cgd       442:        return (0);
1.1       pk        443: }
                    444:
                    445: /*
1.9       cgd       446:  * _reclaim is called when getnewvnode()
                    447:  * wants to make use of an entry on the vnode
                    448:  * free list.  at this time the filesystem needs
                    449:  * to free any private data and remove the node
                    450:  * from any private lists.
1.1       pk        451:  */
1.37      christos  452: int
                    453: procfs_reclaim(v)
                    454:        void *v;
                    455: {
1.22      mycroft   456:        struct vop_reclaim_args /* {
                    457:                struct vnode *a_vp;
1.37      christos  458:        } */ *ap = v;
1.21      mycroft   459:
                    460:        return (procfs_freevp(ap->a_vp));
                    461: }
                    462:
                    463: /*
                    464:  * Return POSIX pathconf information applicable to special devices.
                    465:  */
1.37      christos  466: int
                    467: procfs_pathconf(v)
                    468:        void *v;
                    469: {
1.21      mycroft   470:        struct vop_pathconf_args /* {
                    471:                struct vnode *a_vp;
                    472:                int a_name;
1.26      cgd       473:                register_t *a_retval;
1.37      christos  474:        } */ *ap = v;
1.1       pk        475:
1.21      mycroft   476:        switch (ap->a_name) {
                    477:        case _PC_LINK_MAX:
                    478:                *ap->a_retval = LINK_MAX;
                    479:                return (0);
                    480:        case _PC_MAX_CANON:
                    481:                *ap->a_retval = MAX_CANON;
                    482:                return (0);
                    483:        case _PC_MAX_INPUT:
                    484:                *ap->a_retval = MAX_INPUT;
                    485:                return (0);
                    486:        case _PC_PIPE_BUF:
                    487:                *ap->a_retval = PIPE_BUF;
                    488:                return (0);
                    489:        case _PC_CHOWN_RESTRICTED:
                    490:                *ap->a_retval = 1;
                    491:                return (0);
                    492:        case _PC_VDISABLE:
                    493:                *ap->a_retval = _POSIX_VDISABLE;
1.55      kleink    494:                return (0);
                    495:        case _PC_SYNC_IO:
                    496:                *ap->a_retval = 1;
1.21      mycroft   497:                return (0);
                    498:        default:
                    499:                return (EINVAL);
                    500:        }
                    501:        /* NOTREACHED */
1.1       pk        502: }
                    503:
                    504: /*
1.9       cgd       505:  * _print is used for debugging.
                    506:  * just print a readable description
                    507:  * of (vp).
1.1       pk        508:  */
1.37      christos  509: int
                    510: procfs_print(v)
                    511:        void *v;
                    512: {
1.22      mycroft   513:        struct vop_print_args /* {
                    514:                struct vnode *a_vp;
1.37      christos  515:        } */ *ap = v;
1.21      mycroft   516:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.5       pk        517:
1.44      christos  518:        printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n",
1.21      mycroft   519:            pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
1.37      christos  520:        return 0;
1.36      mycroft   521: }
                    522:
                    523: int
1.121     perry     524: procfs_link(v)
1.37      christos  525:        void *v;
                    526: {
1.36      mycroft   527:        struct vop_link_args /* {
                    528:                struct vnode *a_dvp;
1.121     perry     529:                struct vnode *a_vp;
1.36      mycroft   530:                struct componentname *a_cnp;
1.37      christos  531:        } */ *ap = v;
1.121     perry     532:
1.36      mycroft   533:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                    534:        vput(ap->a_dvp);
                    535:        return (EROFS);
                    536: }
                    537:
                    538: int
1.37      christos  539: procfs_symlink(v)
                    540:        void *v;
                    541: {
1.36      mycroft   542:        struct vop_symlink_args /* {
                    543:                struct vnode *a_dvp;
                    544:                struct vnode **a_vpp;
                    545:                struct componentname *a_cnp;
                    546:                struct vattr *a_vap;
                    547:                char *a_target;
1.37      christos  548:        } */ *ap = v;
1.121     perry     549:
1.36      mycroft   550:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                    551:        vput(ap->a_dvp);
                    552:        return (EROFS);
1.1       pk        553: }
                    554:
                    555: /*
1.123.2.1  yamt      556:  * Works out the path to (and vnode of) the target process's current
                    557:  * working directory or chroot.  If the caller is in a chroot and
                    558:  * can't "reach" the target's cwd or root (or some other error
                    559:  * occurs), a "/" is returned for the path and a NULL pointer is
                    560:  * returned for the vnode.
                    561:  */
                    562: static struct vnode *
                    563: procfs_dir(pfstype t, struct lwp *caller, struct proc *target,
                    564:           char **bpp, char *path, int len)
                    565: {
                    566:        struct vnode *vp, *rvp = caller->l_proc->p_cwdi->cwdi_rdir;
                    567:        char *bp;
                    568:
1.123.2.3  yamt      569:        LOCK_ASSERT(mutex_owned(&target->p_mutex));
                    570:
1.123.2.1  yamt      571:        bp = bpp ? *bpp : NULL;
                    572:
                    573:        switch (t) {
                    574:        case PFScwd:
                    575:                vp = target->p_cwdi->cwdi_cdir;
                    576:                break;
                    577:        case PFSchroot:
                    578:                vp = target->p_cwdi->cwdi_rdir;
                    579:                break;
1.123.2.2  yamt      580:        case PFSexe:
                    581:                vp = target->p_textvp;
                    582:                break;
1.123.2.1  yamt      583:        default:
                    584:                return (NULL);
                    585:        }
                    586:
1.123.2.4! yamt      587:        /*
        !           588:         * XXX: this horrible kludge avoids locking panics when
        !           589:         * attempting to lookup links that point to within procfs
        !           590:         */
        !           591:        if (vp != NULL && vp->v_tag == VT_PROCFS) {
        !           592:                if (bpp) {
        !           593:                        *--bp = '/';
        !           594:                        *bpp = bp;
        !           595:                }
        !           596:                return vp;
        !           597:        }
        !           598:
1.123.2.1  yamt      599:        if (rvp == NULL)
                    600:                rvp = rootvnode;
1.123.2.3  yamt      601:        mutex_exit(&target->p_mutex);   /* XXXSMP */
1.123.2.1  yamt      602:        if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
                    603:            len / 2, 0, caller) != 0) {
                    604:                vp = NULL;
                    605:                if (bpp) {
1.123.2.4! yamt      606: /*
        !           607:                        if (t == PFSexe) {
        !           608:                                snprintf(path, len, "%s/%d/file"
        !           609:                                    mp->mnt_stat.f_mntonname, pfs->pfs_pid);
        !           610:                        } else */ {
        !           611:                                bp = *bpp;
        !           612:                                *--bp = '/';
        !           613:                        }
1.123.2.1  yamt      614:                }
                    615:        }
1.123.2.3  yamt      616:        mutex_enter(&target->p_mutex);  /* XXXSMP */
1.123.2.1  yamt      617:
                    618:        if (bpp)
                    619:                *bpp = bp;
                    620:
                    621:        return (vp);
                    622: }
                    623:
                    624: /*
1.9       cgd       625:  * Invent attributes for pfsnode (vp) and store
                    626:  * them in (vap).
                    627:  * Directories lengths are returned as zero since
                    628:  * any real length would require the genuine size
                    629:  * to be computed, and nothing cares anyway.
                    630:  *
                    631:  * this is relatively minimal for procfs.
1.1       pk        632:  */
1.37      christos  633: int
                    634: procfs_getattr(v)
                    635:        void *v;
                    636: {
1.22      mycroft   637:        struct vop_getattr_args /* {
                    638:                struct vnode *a_vp;
                    639:                struct vattr *a_vap;
1.123.2.1  yamt      640:                kauth_cred_t a_cred;
                    641:                struct lwp *a_l;
1.37      christos  642:        } */ *ap = v;
1.21      mycroft   643:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
                    644:        struct vattr *vap = ap->a_vap;
1.1       pk        645:        struct proc *procp;
1.123.2.3  yamt      646:        char *path;
1.9       cgd       647:        int error;
1.1       pk        648:
1.21      mycroft   649:        /* first check the process still exists */
                    650:        switch (pfs->pfs_type) {
1.109     darcy     651:        case PFSroot:
                    652:        case PFScurproc:
                    653:        case PFSself:
1.123.2.3  yamt      654:                procp = NULL;
1.21      mycroft   655:                break;
                    656:
                    657:        default:
1.123.2.3  yamt      658:                error = procfs_proc_lock(pfs->pfs_pid, &procp, ENOENT);
                    659:                if (error != 0)
                    660:                        return (error);
                    661:                break;
                    662:        }
                    663:
                    664:        switch (pfs->pfs_type) {
                    665:        case PFScwd:
                    666:        case PFSchroot:
                    667:        case PFSexe:
                    668:                MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
                    669:                    M_WAITOK|M_CANFAIL);
                    670:                if (path == NULL && procp != NULL) {
                    671:                        procfs_proc_unlock(procp);
                    672:                        return (ENOMEM);
                    673:                }
                    674:                break;
                    675:
                    676:        default:
                    677:                path = NULL;
1.46      mycroft   678:                break;
1.21      mycroft   679:        }
                    680:
1.123.2.1  yamt      681:        if (procp != NULL) {
1.123.2.3  yamt      682:                mutex_enter(&procp->p_mutex);
                    683:                error = kauth_authorize_process(kauth_cred_get(),
                    684:                    KAUTH_PROCESS_CANSEE, procp, NULL, NULL, NULL);
                    685:                mutex_exit(&procp->p_mutex);
                    686:                if (error != 0) {
                    687:                        procfs_proc_unlock(procp);
                    688:                        if (path != NULL)
                    689:                                free(path, M_TEMP);
1.123.2.1  yamt      690:                        return (ENOENT);
1.123.2.3  yamt      691:                }
1.123.2.1  yamt      692:        }
                    693:
1.21      mycroft   694:        error = 0;
                    695:
1.9       cgd       696:        /* start by zeroing out the attributes */
1.1       pk        697:        VATTR_NULL(vap);
1.9       cgd       698:
                    699:        /* next do all the common fields */
1.21      mycroft   700:        vap->va_type = ap->a_vp->v_type;
1.9       cgd       701:        vap->va_mode = pfs->pfs_mode;
                    702:        vap->va_fileid = pfs->pfs_fileno;
                    703:        vap->va_flags = 0;
1.19      cgd       704:        vap->va_blocksize = PAGE_SIZE;
1.9       cgd       705:
                    706:        /*
1.123.2.1  yamt      707:         * Make all times be current TOD.
1.90      simonb    708:         *
1.9       cgd       709:         * It would be possible to get the process start
1.123.2.1  yamt      710:         * time from the p_stats structure, but there's
1.9       cgd       711:         * no "file creation" time stamp anyway, and the
1.123.2.1  yamt      712:         * p_stats structure is not addressable if u. gets
1.9       cgd       713:         * swapped out for that process.
                    714:         */
1.123.2.1  yamt      715:        getnanotime(&vap->va_ctime);
1.9       cgd       716:        vap->va_atime = vap->va_mtime = vap->va_ctime;
1.123.2.1  yamt      717:        if (procp)
                    718:                TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start,
                    719:                    &vap->va_birthtime);
                    720:        else
                    721:                getnanotime(&vap->va_birthtime);
1.9       cgd       722:
1.21      mycroft   723:        switch (pfs->pfs_type) {
1.109     darcy     724:        case PFSmem:
                    725:        case PFSregs:
                    726:        case PFSfpregs:
1.86      thorpej   727: #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES)
                    728:        PROCFS_MACHDEP_PROTECT_CASES
                    729: #endif
1.47      mycroft   730:                /*
                    731:                 * If the process has exercised some setuid or setgid
                    732:                 * privilege, then rip away read/write permission so
                    733:                 * that only root can gain access.
                    734:                 */
1.123.2.3  yamt      735:                if (procp->p_flag & PK_SUGID)
1.47      mycroft   736:                        vap->va_mode &= ~(S_IRUSR|S_IWUSR);
1.46      mycroft   737:                /* FALLTHROUGH */
1.109     darcy     738:        case PFSctl:
                    739:        case PFSstatus:
                    740:        case PFSstat:
                    741:        case PFSnote:
                    742:        case PFSnotepg:
                    743:        case PFSmap:
                    744:        case PFSmaps:
                    745:        case PFScmdline:
1.123.2.2  yamt      746:        case PFSemul:
1.123.2.4! yamt      747:        case PFSstatm:
1.12      ws        748:                vap->va_nlink = 1;
1.123.2.1  yamt      749:                vap->va_uid = kauth_cred_geteuid(procp->p_cred);
                    750:                vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.21      mycroft   751:                break;
1.109     darcy     752:        case PFSmeminfo:
1.123.2.2  yamt      753:        case PFSdevices:
1.109     darcy     754:        case PFScpuinfo:
                    755:        case PFSuptime:
1.114     jdolecek  756:        case PFSmounts:
1.123.2.4! yamt      757:        case PFScpustat:
        !           758:        case PFSloadavg:
1.76      fvdl      759:                vap->va_nlink = 1;
                    760:                vap->va_uid = vap->va_gid = 0;
                    761:                break;
1.46      mycroft   762:
                    763:        default:
1.37      christos  764:                break;
1.12      ws        765:        }
                    766:
1.9       cgd       767:        /*
                    768:         * now do the object specific fields
                    769:         *
                    770:         * The size could be set from struct reg, but it's hardly
                    771:         * worth the trouble, and it puts some (potentially) machine
                    772:         * dependent data into this machine-independent code.  If it
                    773:         * becomes important then this function should break out into
                    774:         * a per-file stat function in the corresponding .c file.
                    775:         */
1.1       pk        776:
1.9       cgd       777:        switch (pfs->pfs_type) {
1.109     darcy     778:        case PFSroot:
1.21      mycroft   779:                /*
                    780:                 * Set nlink to 1 to tell fts(3) we don't actually know.
                    781:                 */
                    782:                vap->va_nlink = 1;
                    783:                vap->va_uid = 0;
                    784:                vap->va_gid = 0;
1.46      mycroft   785:                vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21      mycroft   786:                break;
                    787:
1.123.2.1  yamt      788:        case PFSself:
1.109     darcy     789:        case PFScurproc: {
1.123     christos  790:                char bf[16];            /* should be enough */
1.21      mycroft   791:                vap->va_nlink = 1;
                    792:                vap->va_uid = 0;
                    793:                vap->va_gid = 0;
1.46      mycroft   794:                vap->va_bytes = vap->va_size =
1.123     christos  795:                    snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.9       cgd       796:                break;
1.21      mycroft   797:        }
1.9       cgd       798:
1.109     darcy     799:        case PFSfd:
1.91      christos  800:                if (pfs->pfs_fd != -1) {
                    801:                        struct file *fp;
1.98      jdolecek  802:
1.123.2.3  yamt      803:                        fp = fd_getfile(procp->p_fd, pfs->pfs_fd);
                    804:                        if (fp == NULL) {
                    805:                                error = EBADF;
                    806:                                break;
                    807:                        }
1.98      jdolecek  808:                        FILE_USE(fp);
1.91      christos  809:                        vap->va_nlink = 1;
1.123.2.1  yamt      810:                        vap->va_uid = kauth_cred_geteuid(fp->f_cred);
                    811:                        vap->va_gid = kauth_cred_getegid(fp->f_cred);
1.91      christos  812:                        switch (fp->f_type) {
                    813:                        case DTYPE_VNODE:
                    814:                                vap->va_bytes = vap->va_size =
                    815:                                    ((struct vnode *)fp->f_data)->v_size;
                    816:                                break;
                    817:                        default:
                    818:                                vap->va_bytes = vap->va_size = 0;
                    819:                                break;
                    820:                        }
1.123.2.3  yamt      821:                        FILE_UNUSE(fp, curlwp);
1.91      christos  822:                        break;
                    823:                }
                    824:                /*FALLTHROUGH*/
1.109     darcy     825:        case PFSproc:
1.9       cgd       826:                vap->va_nlink = 2;
1.123.2.1  yamt      827:                vap->va_uid = kauth_cred_geteuid(procp->p_cred);
                    828:                vap->va_gid = kauth_cred_getegid(procp->p_cred);
1.46      mycroft   829:                vap->va_bytes = vap->va_size = DEV_BSIZE;
1.21      mycroft   830:                break;
                    831:
1.109     darcy     832:        case PFSfile:
1.21      mycroft   833:                error = EOPNOTSUPP;
1.9       cgd       834:                break;
                    835:
1.109     darcy     836:        case PFSmem:
1.9       cgd       837:                vap->va_bytes = vap->va_size =
                    838:                        ctob(procp->p_vmspace->vm_tsize +
                    839:                                    procp->p_vmspace->vm_dsize +
                    840:                                    procp->p_vmspace->vm_ssize);
                    841:                break;
                    842:
1.18      cgd       843: #if defined(PT_GETREGS) || defined(PT_SETREGS)
1.109     darcy     844:        case PFSregs:
1.11      cgd       845:                vap->va_bytes = vap->va_size = sizeof(struct reg);
1.18      cgd       846:                break;
1.14      cgd       847: #endif
                    848:
1.18      cgd       849: #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
1.109     darcy     850:        case PFSfpregs:
1.14      cgd       851:                vap->va_bytes = vap->va_size = sizeof(struct fpreg);
1.18      cgd       852:                break;
1.14      cgd       853: #endif
1.12      ws        854:
1.109     darcy     855:        case PFSctl:
                    856:        case PFSstatus:
                    857:        case PFSstat:
                    858:        case PFSnote:
                    859:        case PFSnotepg:
                    860:        case PFScmdline:
                    861:        case PFSmeminfo:
1.123.2.2  yamt      862:        case PFSdevices:
1.109     darcy     863:        case PFScpuinfo:
                    864:        case PFSuptime:
1.114     jdolecek  865:        case PFSmounts:
1.123.2.4! yamt      866:        case PFScpustat:
        !           867:        case PFSloadavg:
        !           868:        case PFSstatm:
1.46      mycroft   869:                vap->va_bytes = vap->va_size = 0;
1.79      fvdl      870:                break;
1.109     darcy     871:        case PFSmap:
                    872:        case PFSmaps:
1.79      fvdl      873:                /*
                    874:                 * Advise a larger blocksize for the map files, so that
                    875:                 * they may be read in one pass.
                    876:                 */
1.80      fvdl      877:                vap->va_blocksize = 4 * PAGE_SIZE;
1.83      chs       878:                vap->va_bytes = vap->va_size = 0;
1.9       cgd       879:                break;
1.86      thorpej   880:
1.123.2.1  yamt      881:        case PFScwd:
1.123.2.2  yamt      882:        case PFSchroot:
                    883:        case PFSexe: {
1.123.2.3  yamt      884:                char *bp;
1.123.2.1  yamt      885:
                    886:                vap->va_nlink = 1;
                    887:                vap->va_uid = 0;
                    888:                vap->va_gid = 0;
                    889:                bp = path + MAXPATHLEN;
                    890:                *--bp = '\0';
1.123.2.3  yamt      891:                mutex_enter(&procp->p_mutex);
1.123.2.1  yamt      892:                (void)procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path,
                    893:                     MAXPATHLEN);
1.123.2.3  yamt      894:                mutex_exit(&procp->p_mutex);
1.123.2.1  yamt      895:                vap->va_bytes = vap->va_size = strlen(bp);
                    896:                break;
                    897:        }
                    898:
1.123.2.2  yamt      899:        case PFSemul:
                    900:                vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name);
                    901:                break;
                    902:
1.86      thorpej   903: #ifdef __HAVE_PROCFS_MACHDEP
                    904:        PROCFS_MACHDEP_NODETYPE_CASES
                    905:                error = procfs_machdep_getattr(ap->a_vp, vap, procp);
                    906:                break;
                    907: #endif
1.1       pk        908:
1.9       cgd       909:        default:
1.21      mycroft   910:                panic("procfs_getattr");
1.1       pk        911:        }
                    912:
1.123.2.3  yamt      913:        if (procp != NULL)
                    914:                procfs_proc_unlock(procp);
                    915:        if (path != NULL)
                    916:                free(path, M_TEMP);
                    917:
1.9       cgd       918:        return (error);
1.1       pk        919: }
                    920:
1.37      christos  921: /*ARGSUSED*/
                    922: int
1.123.2.2  yamt      923: procfs_setattr(void *v)
1.5       pk        924: {
                    925:        /*
1.9       cgd       926:         * just fake out attribute setting
                    927:         * it's not good to generate an error
                    928:         * return, otherwise things like creat()
                    929:         * will fail when they try to set the
                    930:         * file length to 0.  worse, this means
                    931:         * that echo $note > /proc/$pid/note will fail.
1.5       pk        932:         */
                    933:
1.9       cgd       934:        return (0);
1.5       pk        935: }
                    936:
1.9       cgd       937: /*
                    938:  * implement access checking.
                    939:  *
                    940:  * actually, the check for super-user is slightly
                    941:  * broken since it will allow read access to write-only
                    942:  * objects.  this doesn't cause any particular trouble
                    943:  * but does mean that the i/o entry points need to check
                    944:  * that the operation really does make sense.
                    945:  */
1.37      christos  946: int
                    947: procfs_access(v)
                    948:        void *v;
                    949: {
1.22      mycroft   950:        struct vop_access_args /* {
                    951:                struct vnode *a_vp;
                    952:                int a_mode;
1.123.2.1  yamt      953:                kauth_cred_t a_cred;
                    954:                struct lwp *a_l;
1.37      christos  955:        } */ *ap = v;
1.31      mycroft   956:        struct vattr va;
1.1       pk        957:        int error;
                    958:
1.123.2.1  yamt      959:        if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1       pk        960:                return (error);
1.9       cgd       961:
1.49      mycroft   962:        return (vaccess(va.va_type, va.va_mode,
                    963:            va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
1.1       pk        964: }
                    965:
                    966: /*
1.9       cgd       967:  * lookup.  this is incredibly complicated in the
                    968:  * general case, however for most pseudo-filesystems
                    969:  * very little needs to be done.
                    970:  *
1.62      wrstuden  971:  * Locking isn't hard here, just poorly documented.
                    972:  *
1.121     perry     973:  * If we're looking up ".", just vref the parent & return it.
1.62      wrstuden  974:  *
                    975:  * If we're looking up "..", unlock the parent, and lock "..". If everything
                    976:  * went ok, and we're on the last component and the caller requested the
                    977:  * parent locked, try to re-lock the parent. We do this to prevent lock
                    978:  * races.
                    979:  *
                    980:  * For anything else, get the needed node. Then unlock the parent if not
                    981:  * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
                    982:  * parent in the .. case).
                    983:  *
                    984:  * We try to exit with the parent locked in error cases.
1.9       cgd       985:  */
1.37      christos  986: int
                    987: procfs_lookup(v)
                    988:        void *v;
                    989: {
1.22      mycroft   990:        struct vop_lookup_args /* {
                    991:                struct vnode * a_dvp;
                    992:                struct vnode ** a_vpp;
                    993:                struct componentname * a_cnp;
1.37      christos  994:        } */ *ap = v;
1.21      mycroft   995:        struct componentname *cnp = ap->a_cnp;
                    996:        struct vnode **vpp = ap->a_vpp;
                    997:        struct vnode *dvp = ap->a_dvp;
1.45      cgd       998:        const char *pname = cnp->cn_nameptr;
1.78      jdolecek  999:        const struct proc_target *pt = NULL;
1.32      mycroft  1000:        struct vnode *fvp;
1.123.2.3  yamt     1001:        pid_t pid, vnpid;
1.9       cgd      1002:        struct pfsnode *pfs;
1.76      fvdl     1003:        struct proc *p = NULL;
1.123.2.1  yamt     1004:        struct lwp *l = NULL;
1.123.2.3  yamt     1005:        int i, error;
                   1006:        pfstype type;
1.1       pk       1007:
1.32      mycroft  1008:        *vpp = NULL;
                   1009:
                   1010:        if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
                   1011:                return (EROFS);
                   1012:
1.21      mycroft  1013:        if (cnp->cn_namelen == 1 && *pname == '.') {
                   1014:                *vpp = dvp;
1.9       cgd      1015:                VREF(dvp);
                   1016:                return (0);
                   1017:        }
1.1       pk       1018:
1.9       cgd      1019:        pfs = VTOPFS(dvp);
                   1020:        switch (pfs->pfs_type) {
1.109     darcy    1021:        case PFSroot:
1.62      wrstuden 1022:                /*
                   1023:                 * Shouldn't get here with .. in the root node.
                   1024:                 */
1.121     perry    1025:                if (cnp->cn_flags & ISDOTDOT)
1.9       cgd      1026:                        return (EIO);
                   1027:
1.76      fvdl     1028:                for (i = 0; i < nproc_root_targets; i++) {
                   1029:                        pt = &proc_root_targets[i];
1.123.2.3  yamt     1030:                        /*
                   1031:                         * check for node match.  proc is always NULL here,
                   1032:                         * so call pt_valid with constant NULL lwp.
                   1033:                         */
1.76      fvdl     1034:                        if (cnp->cn_namelen == pt->pt_namlen &&
                   1035:                            memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
                   1036:                            (pt->pt_valid == NULL ||
1.123.2.3  yamt     1037:                             (*pt->pt_valid)(NULL, dvp->v_mount)))
1.76      fvdl     1038:                                break;
                   1039:                }
                   1040:
                   1041:                if (i != nproc_root_targets) {
                   1042:                        error = procfs_allocvp(dvp->v_mount, vpp, 0,
1.123.2.3  yamt     1043:                            pt->pt_pfstype, -1, NULL);
1.76      fvdl     1044:                        return (error);
                   1045:                }
                   1046:
1.123.2.3  yamt     1047:                if (CNEQ(cnp, "curproc", 7)) {
                   1048:                        pid = curproc->p_pid;
                   1049:                        vnpid = 0;
                   1050:                        type = PFScurproc;
                   1051:                } else if (CNEQ(cnp, "self", 4)) {
                   1052:                        pid = curproc->p_pid;
                   1053:                        vnpid = 0;
                   1054:                        type = PFSself;
                   1055:                } else {
                   1056:                        pid = (pid_t)atoi(pname, cnp->cn_namelen);
                   1057:                        vnpid = pid;
                   1058:                        type = PFSproc;
                   1059:                }
1.9       cgd      1060:
1.123.2.3  yamt     1061:                if (procfs_proc_lock(pid, &p, ESRCH) != 0)
1.32      mycroft  1062:                        break;
1.123.2.3  yamt     1063:                error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1, p);
                   1064:                procfs_proc_unlock(p);
1.62      wrstuden 1065:                return (error);
1.9       cgd      1066:
1.109     darcy    1067:        case PFSproc:
1.62      wrstuden 1068:                /*
                   1069:                 * do the .. dance. We unlock the directory, and then
                   1070:                 * get the root dir. That will automatically return ..
                   1071:                 * locked. Then if the caller wanted dvp locked, we
                   1072:                 * re-lock.
                   1073:                 */
                   1074:                if (cnp->cn_flags & ISDOTDOT) {
                   1075:                        VOP_UNLOCK(dvp, 0);
1.105     thorpej  1076:                        error = procfs_root(dvp->v_mount, vpp);
1.123.2.2  yamt     1077:                        vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.62      wrstuden 1078:                        return (error);
                   1079:                }
1.1       pk       1080:
1.123.2.3  yamt     1081:                if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32      mycroft  1082:                        break;
                   1083:
                   1084:                for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
1.123.2.3  yamt     1085:                        struct lwp *plwp;
                   1086:                        int found;
                   1087:
                   1088:                        mutex_enter(&p->p_smutex);
                   1089:                        plwp = proc_representative_lwp(p, NULL, 1);
                   1090:                        lwp_addref(plwp);
                   1091:                        mutex_exit(&p->p_smutex);
                   1092:                        found = cnp->cn_namelen == pt->pt_namlen &&
1.56      perry    1093:                            memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
1.123.2.3  yamt     1094:                            (pt->pt_valid == NULL
                   1095:                              || (*pt->pt_valid)(plwp, dvp->v_mount));
                   1096:                        lwp_delref(plwp);
                   1097:                        if (found)
                   1098:                                break;
                   1099:                }
                   1100:                if (i == nproc_targets) {
                   1101:                        procfs_proc_unlock(p);
                   1102:                        break;
1.9       cgd      1103:                }
1.109     darcy    1104:                if (pt->pt_pfstype == PFSfile) {
1.75      chs      1105:                        fvp = p->p_textvp;
1.23      mycroft  1106:                        /* We already checked that it exists. */
1.32      mycroft  1107:                        VREF(fvp);
1.53      fvdl     1108:                        vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1.32      mycroft  1109:                        *vpp = fvp;
1.123.2.3  yamt     1110:                        procfs_proc_unlock(p);
1.21      mycroft  1111:                        return (0);
                   1112:                }
1.1       pk       1113:
1.62      wrstuden 1114:                error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3  yamt     1115:                    pt->pt_pfstype, -1, p);
                   1116:                procfs_proc_unlock(p);
1.62      wrstuden 1117:                return (error);
1.1       pk       1118:
1.109     darcy    1119:        case PFSfd: {
1.91      christos 1120:                int fd;
                   1121:                struct file *fp;
1.123.2.3  yamt     1122:
                   1123:                if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ENOENT)) != 0)
                   1124:                        return error;
                   1125:
1.91      christos 1126:                /*
                   1127:                 * do the .. dance. We unlock the directory, and then
                   1128:                 * get the proc dir. That will automatically return ..
1.123.2.2  yamt     1129:                 * locked. Then re-lock the directory.
1.91      christos 1130:                 */
                   1131:                if (cnp->cn_flags & ISDOTDOT) {
                   1132:                        VOP_UNLOCK(dvp, 0);
                   1133:                        error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3  yamt     1134:                            PFSproc, -1, p);
1.123.2.2  yamt     1135:                        vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.123.2.3  yamt     1136:                        procfs_proc_unlock(p);
1.91      christos 1137:                        return (error);
                   1138:                }
                   1139:                fd = atoi(pname, cnp->cn_namelen);
1.123.2.3  yamt     1140:
                   1141:                mutex_enter(&p->p_mutex);
                   1142:                fp = fd_getfile(p->p_fd, fd);
                   1143:                mutex_exit(&p->p_mutex);
                   1144:                if (fp == NULL) {
                   1145:                        procfs_proc_unlock(p);
1.91      christos 1146:                        return ENOENT;
1.123.2.3  yamt     1147:                }
                   1148:
1.99      jdolecek 1149:                FILE_USE(fp);
                   1150:
1.91      christos 1151:                switch (fp->f_type) {
                   1152:                case DTYPE_VNODE:
                   1153:                        fvp = (struct vnode *)fp->f_data;
1.101     jdolecek 1154:
                   1155:                        /* Don't show directories */
1.102     christos 1156:                        if (fvp->v_type == VDIR)
                   1157:                                goto symlink;
1.101     jdolecek 1158:
1.91      christos 1159:                        VREF(fvp);
1.123.2.1  yamt     1160:                        FILE_UNUSE(fp, l);
1.121     perry    1161:                        vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY |
1.92      christos 1162:                            (p == curproc ? LK_CANRECURSE : 0));
1.91      christos 1163:                        *vpp = fvp;
                   1164:                        error = 0;
                   1165:                        break;
                   1166:                default:
1.102     christos 1167:                symlink:
1.123.2.1  yamt     1168:                        FILE_UNUSE(fp, l);
1.91      christos 1169:                        error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
1.123.2.3  yamt     1170:                            PFSfd, fd, p);
1.91      christos 1171:                        break;
                   1172:                }
1.123.2.3  yamt     1173:                procfs_proc_unlock(p);
1.91      christos 1174:                return error;
                   1175:        }
1.9       cgd      1176:        default:
                   1177:                return (ENOTDIR);
1.1       pk       1178:        }
1.32      mycroft  1179:
                   1180:        return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
1.1       pk       1181: }
                   1182:
1.18      cgd      1183: int
1.123.2.2  yamt     1184: procfs_validfile(struct lwp *l, struct mount *mp)
1.18      cgd      1185: {
1.123.2.2  yamt     1186:        return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL;
1.74      tv       1187: }
1.21      mycroft  1188:
1.74      tv       1189: static int
1.123.2.1  yamt     1190: procfs_validfile_linux(l, mp)
                   1191:        struct lwp *l;
1.76      fvdl     1192:        struct mount *mp;
1.74      tv       1193: {
1.76      fvdl     1194:        int flags;
                   1195:
                   1196:        flags = VFSTOPROC(mp)->pmnt_flags;
1.123.2.2  yamt     1197:        return (flags & PROCFSMNT_LINUXCOMPAT) &&
                   1198:            (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp));
1.18      cgd      1199: }
                   1200:
1.117     yamt     1201: struct procfs_root_readdir_ctx {
                   1202:        struct uio *uiop;
                   1203:        off_t *cookies;
                   1204:        int ncookies;
1.120     yamt     1205:        off_t off;
                   1206:        off_t startoff;
1.117     yamt     1207:        int error;
                   1208: };
                   1209:
                   1210: static int
                   1211: procfs_root_readdir_callback(struct proc *p, void *arg)
                   1212: {
                   1213:        struct procfs_root_readdir_ctx *ctxp = arg;
                   1214:        struct dirent d;
                   1215:        struct uio *uiop;
                   1216:        int error;
                   1217:
                   1218:        uiop = ctxp->uiop;
                   1219:        if (uiop->uio_resid < UIO_MX)
                   1220:                return -1; /* no space */
                   1221:
1.120     yamt     1222:        if (ctxp->off < ctxp->startoff) {
                   1223:                ctxp->off++;
1.117     yamt     1224:                return 0;
                   1225:        }
                   1226:
1.123.2.1  yamt     1227:        if (kauth_authorize_process(kauth_cred_get(),
                   1228:            KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0)
                   1229:                return 0;
                   1230:
1.117     yamt     1231:        memset(&d, 0, UIO_MX);
                   1232:        d.d_reclen = UIO_MX;
                   1233:        d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1);
                   1234:        d.d_namlen = snprintf(d.d_name,
                   1235:            UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid);
                   1236:        d.d_type = DT_DIR;
                   1237:
1.123.2.4! yamt     1238:        mutex_exit(&proclist_lock);
1.117     yamt     1239:        error = uiomove(&d, UIO_MX, uiop);
1.123.2.4! yamt     1240:        mutex_enter(&proclist_lock);
1.117     yamt     1241:        if (error) {
                   1242:                ctxp->error = error;
                   1243:                return -1;
                   1244:        }
                   1245:
                   1246:        ctxp->ncookies++;
                   1247:        if (ctxp->cookies)
1.120     yamt     1248:                *(ctxp->cookies)++ = ctxp->off + 1;
                   1249:        ctxp->off++;
1.117     yamt     1250:
                   1251:        return 0;
                   1252: }
                   1253:
1.9       cgd      1254: /*
                   1255:  * readdir returns directory entries from pfsnode (vp).
                   1256:  *
                   1257:  * the strategy here with procfs is to generate a single
1.34      mycroft  1258:  * directory entry at a time (struct dirent) and then
1.9       cgd      1259:  * copy that out to userland using uiomove.  a more efficent
                   1260:  * though more complex implementation, would try to minimize
                   1261:  * the number of calls to uiomove().  for procfs, this is
                   1262:  * hardly worth the added code complexity.
                   1263:  *
                   1264:  * this should just be done through read()
                   1265:  */
1.37      christos 1266: int
                   1267: procfs_readdir(v)
                   1268:        void *v;
                   1269: {
1.22      mycroft  1270:        struct vop_readdir_args /* {
                   1271:                struct vnode *a_vp;
                   1272:                struct uio *a_uio;
1.123.2.1  yamt     1273:                kauth_cred_t a_cred;
1.22      mycroft  1274:                int *a_eofflag;
1.53      fvdl     1275:                off_t **a_cookies;
                   1276:                int *a_ncookies;
1.37      christos 1277:        } */ *ap = v;
1.21      mycroft  1278:        struct uio *uio = ap->a_uio;
1.34      mycroft  1279:        struct dirent d;
1.9       cgd      1280:        struct pfsnode *pfs;
1.68      sommerfe 1281:        off_t i;
1.9       cgd      1282:        int error;
1.53      fvdl     1283:        off_t *cookies = NULL;
1.117     yamt     1284:        int ncookies;
1.76      fvdl     1285:        struct vnode *vp;
1.78      jdolecek 1286:        const struct proc_target *pt;
1.117     yamt     1287:        struct procfs_root_readdir_ctx ctx;
1.123.2.3  yamt     1288:        struct lwp *l;
1.9       cgd      1289:
1.76      fvdl     1290:        vp = ap->a_vp;
                   1291:        pfs = VTOPFS(vp);
1.1       pk       1292:
1.9       cgd      1293:        if (uio->uio_resid < UIO_MX)
                   1294:                return (EINVAL);
1.35      mycroft  1295:        if (uio->uio_offset < 0)
1.1       pk       1296:                return (EINVAL);
                   1297:
1.9       cgd      1298:        error = 0;
1.35      mycroft  1299:        i = uio->uio_offset;
1.113     jrf      1300:        memset(&d, 0, UIO_MX);
1.34      mycroft  1301:        d.d_reclen = UIO_MX;
1.53      fvdl     1302:        ncookies = uio->uio_resid / UIO_MX;
1.9       cgd      1303:
                   1304:        switch (pfs->pfs_type) {
                   1305:        /*
                   1306:         * this is for the process-specific sub-directories.
                   1307:         * all that is needed to is copy out all the entries
                   1308:         * from the procent[] table (top of this file).
                   1309:         */
1.109     darcy    1310:        case PFSproc: {
1.32      mycroft  1311:                struct proc *p;
1.66      christos 1312:
                   1313:                if (i >= nproc_targets)
1.67      sommerfe 1314:                        return 0;
1.9       cgd      1315:
1.123.2.3  yamt     1316:                if (procfs_proc_lock(pfs->pfs_pid, &p, ESRCH) != 0)
1.32      mycroft  1317:                        break;
                   1318:
1.53      fvdl     1319:                if (ap->a_ncookies) {
                   1320:                        ncookies = min(ncookies, (nproc_targets - i));
1.72      thorpej  1321:                        cookies = malloc(ncookies * sizeof (off_t),
1.53      fvdl     1322:                            M_TEMP, M_WAITOK);
                   1323:                        *ap->a_cookies = cookies;
                   1324:                }
                   1325:
1.32      mycroft  1326:                for (pt = &proc_targets[i];
                   1327:                     uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
1.123.2.3  yamt     1328:                        if (pt->pt_valid) {
                   1329:                                /* XXXSMP locking */
                   1330:                                mutex_enter(&p->p_smutex);
                   1331:                                l = proc_representative_lwp(p, NULL, 1);
                   1332:                                mutex_exit(&p->p_smutex);
                   1333:                                if ((*pt->pt_valid)(l, vp->v_mount) == 0)
                   1334:                                        continue;
                   1335:                        }
1.121     perry    1336:
1.91      christos 1337:                        d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
                   1338:                            pt->pt_pfstype, -1);
1.34      mycroft  1339:                        d.d_namlen = pt->pt_namlen;
1.56      perry    1340:                        memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
1.34      mycroft  1341:                        d.d_type = pt->pt_type;
1.15      ws       1342:
1.113     jrf      1343:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9       cgd      1344:                                break;
1.53      fvdl     1345:                        if (cookies)
1.35      mycroft  1346:                                *cookies++ = i + 1;
1.6       ws       1347:                }
1.9       cgd      1348:
1.123.2.3  yamt     1349:                procfs_proc_unlock(p);
1.9       cgd      1350:                break;
1.34      mycroft  1351:        }
1.109     darcy    1352:        case PFSfd: {
1.91      christos 1353:                struct proc *p;
                   1354:                struct filedesc *fdp;
1.111     jdolecek 1355:                struct file *fp;
1.110     simonb   1356:                int lim, nc = 0;
1.91      christos 1357:
1.123.2.3  yamt     1358:                if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
                   1359:                        return error;
1.91      christos 1360:
1.123.2.1  yamt     1361:                if (kauth_authorize_process(kauth_cred_get(),
1.123.2.3  yamt     1362:                    KAUTH_PROCESS_CANSEE, p, NULL, NULL, NULL) != 0) {
                   1363:                        procfs_proc_unlock(p);
1.123.2.1  yamt     1364:                        return ESRCH;
1.123.2.3  yamt     1365:                }
1.123.2.1  yamt     1366:
1.123.2.3  yamt     1367:                fdp = p->p_fd;  /* XXXSMP */
1.91      christos 1368:
                   1369:                lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
1.123.2.3  yamt     1370:                if (i >= lim) {
                   1371:                        procfs_proc_unlock(p);
1.91      christos 1372:                        return 0;
1.123.2.3  yamt     1373:                }
1.91      christos 1374:
                   1375:                if (ap->a_ncookies) {
                   1376:                        ncookies = min(ncookies, (fdp->fd_nfiles + 2 - i));
                   1377:                        cookies = malloc(ncookies * sizeof (off_t),
                   1378:                            M_TEMP, M_WAITOK);
                   1379:                        *ap->a_cookies = cookies;
                   1380:                }
                   1381:
                   1382:                for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
                   1383:                        pt = &proc_targets[i];
                   1384:                        d.d_namlen = pt->pt_namlen;
                   1385:                        d.d_fileno = PROCFS_FILENO(pfs->pfs_pid,
                   1386:                            pt->pt_pfstype, -1);
                   1387:                        (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
                   1388:                        d.d_type = pt->pt_type;
1.113     jrf      1389:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91      christos 1390:                                break;
                   1391:                        if (cookies)
                   1392:                                *cookies++ = i + 1;
                   1393:                        nc++;
                   1394:                }
                   1395:                if (error) {
                   1396:                        ncookies = nc;
                   1397:                        break;
                   1398:                }
                   1399:                for (; uio->uio_resid >= UIO_MX && i < fdp->fd_nfiles; i++) {
1.111     jdolecek 1400:                        /* check the descriptor exists */
                   1401:                        if ((fp = fd_getfile(fdp, i - 2)) == NULL)
1.100     jdolecek 1402:                                continue;
1.111     jdolecek 1403:                        simple_unlock(&fp->f_slock);
                   1404:
1.109     darcy    1405:                        d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2);
1.91      christos 1406:                        d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
1.93      martin   1407:                            "%lld", (long long)(i - 2));
1.91      christos 1408:                        d.d_type = VREG;
1.113     jrf      1409:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.91      christos 1410:                                break;
                   1411:                        if (cookies)
                   1412:                                *cookies++ = i + 1;
                   1413:                        nc++;
                   1414:                }
                   1415:                ncookies = nc;
1.123.2.3  yamt     1416:                procfs_proc_unlock(p);
1.91      christos 1417:                break;
                   1418:        }
1.9       cgd      1419:
                   1420:        /*
                   1421:         * this is for the root of the procfs filesystem
1.69      thorpej  1422:         * what is needed are special entries for "curproc"
                   1423:         * and "self" followed by an entry for each process
1.117     yamt     1424:         * on allproc.
1.9       cgd      1425:         */
                   1426:
1.109     darcy    1427:        case PFSroot: {
1.117     yamt     1428:                int nc = 0;
1.9       cgd      1429:
1.53      fvdl     1430:                if (ap->a_ncookies) {
                   1431:                        /*
                   1432:                         * XXX Potentially allocating too much space here,
                   1433:                         * but I'm lazy. This loop needs some work.
                   1434:                         */
1.72      thorpej  1435:                        cookies = malloc(ncookies * sizeof (off_t),
1.53      fvdl     1436:                            M_TEMP, M_WAITOK);
                   1437:                        *ap->a_cookies = cookies;
                   1438:                }
1.117     yamt     1439:                error = 0;
                   1440:                /* 0 ... 3 are static entries. */
                   1441:                for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) {
1.9       cgd      1442:                        switch (i) {
1.12      ws       1443:                        case 0:         /* `.' */
                   1444:                        case 1:         /* `..' */
1.109     darcy    1445:                                d.d_fileno = PROCFS_FILENO(0, PFSroot, -1);
1.34      mycroft  1446:                                d.d_namlen = i + 1;
1.56      perry    1447:                                memcpy(d.d_name, "..", d.d_namlen);
1.34      mycroft  1448:                                d.d_name[i + 1] = '\0';
                   1449:                                d.d_type = DT_DIR;
1.12      ws       1450:                                break;
1.21      mycroft  1451:
1.12      ws       1452:                        case 2:
1.109     darcy    1453:                                d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1);
1.69      thorpej  1454:                                d.d_namlen = sizeof("curproc") - 1;
                   1455:                                memcpy(d.d_name, "curproc", sizeof("curproc"));
                   1456:                                d.d_type = DT_LNK;
                   1457:                                break;
                   1458:
                   1459:                        case 3:
1.109     darcy    1460:                                d.d_fileno = PROCFS_FILENO(0, PFSself, -1);
1.69      thorpej  1461:                                d.d_namlen = sizeof("self") - 1;
                   1462:                                memcpy(d.d_name, "self", sizeof("self"));
1.34      mycroft  1463:                                d.d_type = DT_LNK;
1.9       cgd      1464:                                break;
1.1       pk       1465:                        }
1.21      mycroft  1466:
1.113     jrf      1467:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.9       cgd      1468:                                break;
1.53      fvdl     1469:                        nc++;
                   1470:                        if (cookies)
1.35      mycroft  1471:                                *cookies++ = i + 1;
1.1       pk       1472:                }
1.117     yamt     1473:                /* 4 ... are process entries. */
                   1474:                ctx.uiop = uio;
                   1475:                ctx.error = 0;
1.120     yamt     1476:                ctx.off = 4;
                   1477:                ctx.startoff = i;
1.117     yamt     1478:                ctx.cookies = cookies;
                   1479:                ctx.ncookies = nc;
                   1480:                proclist_foreach_call(&allproc,
                   1481:                    procfs_root_readdir_callback, &ctx);
                   1482:                cookies = ctx.cookies;
                   1483:                nc = ctx.ncookies;
                   1484:                error = ctx.error;
                   1485:                if (error)
                   1486:                        break;
1.76      fvdl     1487:
1.117     yamt     1488:                /* misc entries. */
1.120     yamt     1489:                if (i < ctx.off)
                   1490:                        i = ctx.off;
                   1491:                if (i >= ctx.off + nproc_root_targets)
1.76      fvdl     1492:                        break;
1.120     yamt     1493:                for (pt = &proc_root_targets[i - ctx.off];
1.117     yamt     1494:                    uio->uio_resid >= UIO_MX &&
                   1495:                    pt < &proc_root_targets[nproc_root_targets];
                   1496:                    pt++, i++) {
1.76      fvdl     1497:                        if (pt->pt_valid &&
                   1498:                            (*pt->pt_valid)(NULL, vp->v_mount) == 0)
                   1499:                                continue;
1.91      christos 1500:                        d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1);
1.76      fvdl     1501:                        d.d_namlen = pt->pt_namlen;
                   1502:                        memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1);
                   1503:                        d.d_type = pt->pt_type;
                   1504:
1.113     jrf      1505:                        if ((error = uiomove(&d, UIO_MX, uio)) != 0)
1.76      fvdl     1506:                                break;
                   1507:                        nc++;
                   1508:                        if (cookies)
                   1509:                                *cookies++ = i + 1;
                   1510:                }
                   1511:
1.53      fvdl     1512:                ncookies = nc;
1.9       cgd      1513:                break;
1.34      mycroft  1514:        }
1.9       cgd      1515:
                   1516:        default:
                   1517:                error = ENOTDIR;
                   1518:                break;
1.1       pk       1519:        }
1.9       cgd      1520:
1.53      fvdl     1521:        if (ap->a_ncookies) {
                   1522:                if (error) {
1.54      fvdl     1523:                        if (cookies)
1.72      thorpej  1524:                                free(*ap->a_cookies, M_TEMP);
1.53      fvdl     1525:                        *ap->a_ncookies = 0;
                   1526:                        *ap->a_cookies = NULL;
                   1527:                } else
                   1528:                        *ap->a_ncookies = ncookies;
                   1529:        }
1.35      mycroft  1530:        uio->uio_offset = i;
1.9       cgd      1531:        return (error);
1.12      ws       1532: }
                   1533:
                   1534: /*
1.123.2.1  yamt     1535:  * readlink reads the link of `curproc' and others
1.12      ws       1536:  */
1.37      christos 1537: int
                   1538: procfs_readlink(v)
                   1539:        void *v;
1.12      ws       1540: {
1.37      christos 1541:        struct vop_readlink_args *ap = v;
1.123     christos 1542:        char bf[16];            /* should be enough */
                   1543:        char *bp = bf;
1.102     christos 1544:        char *path = NULL;
1.12      ws       1545:        int len;
1.102     christos 1546:        int error = 0;
                   1547:        struct pfsnode *pfs = VTOPFS(ap->a_vp);
1.123.2.1  yamt     1548:        struct proc *pown;
1.12      ws       1549:
1.109     darcy    1550:        if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1))
1.123     christos 1551:                len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid);
1.109     darcy    1552:        else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1))
1.123     christos 1553:                len = snprintf(bf, sizeof(bf), "%s", "curproc");
1.123.2.2  yamt     1554:        else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) ||
                   1555:            pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1) ||
                   1556:            pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) {
1.123.2.3  yamt     1557:                if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
                   1558:                        return error;
1.123.2.1  yamt     1559:                MALLOC(path, char *, MAXPATHLEN + 4, M_TEMP,
                   1560:                    M_WAITOK|M_CANFAIL);
1.123.2.3  yamt     1561:                if (path == NULL) {
                   1562:                        procfs_proc_unlock(pown);
1.123.2.1  yamt     1563:                        return (ENOMEM);
1.123.2.3  yamt     1564:                }
1.123.2.1  yamt     1565:                bp = path + MAXPATHLEN;
                   1566:                *--bp = '\0';
1.123.2.3  yamt     1567:                mutex_enter(&pown->p_mutex);
1.123.2.2  yamt     1568:                (void)procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown,
                   1569:                    &bp, path, MAXPATHLEN);
1.123.2.3  yamt     1570:                mutex_exit(&pown->p_mutex);
                   1571:                procfs_proc_unlock(pown);
1.123.2.1  yamt     1572:                len = strlen(bp);
1.123.2.2  yamt     1573:        } else {
1.102     christos 1574:                struct file *fp;
                   1575:                struct vnode *vxp, *vp;
                   1576:
1.123.2.3  yamt     1577:                if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
1.102     christos 1578:                        return error;
1.123.2.4! yamt     1579:
1.123.2.3  yamt     1580:                mutex_enter(&pown->p_mutex);
                   1581:                fp = fd_getfile(pown->p_fd, pfs->pfs_fd);
                   1582:                mutex_exit(&pown->p_mutex);
1.123.2.4! yamt     1583:                if (fp == NULL) {
1.123.2.3  yamt     1584:                        procfs_proc_unlock(pown);
1.123.2.4! yamt     1585:                        return EBADF;
1.123.2.3  yamt     1586:                }
1.123.2.4! yamt     1587:
1.102     christos 1588:                FILE_USE(fp);
                   1589:                switch (fp->f_type) {
                   1590:                case DTYPE_VNODE:
                   1591:                        vxp = (struct vnode *)fp->f_data;
                   1592:                        if (vxp->v_type != VDIR) {
1.123.2.3  yamt     1593:                                FILE_UNUSE(fp, curlwp);
                   1594:                                error = EINVAL;
                   1595:                                break;
1.102     christos 1596:                        }
                   1597:                        if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK))
                   1598:                            == NULL) {
1.123.2.3  yamt     1599:                                FILE_UNUSE(fp, curlwp);
                   1600:                                error = ENOMEM;
                   1601:                                break;
1.102     christos 1602:                        }
                   1603:                        bp = path + MAXPATHLEN;
                   1604:                        *--bp = '\0';
1.123.2.4! yamt     1605:
        !          1606:                        /*
        !          1607:                         * XXX: kludge to avoid locking against ourselves
        !          1608:                         * in getcwd()
        !          1609:                         */
        !          1610:                        if (vxp->v_tag == VT_PROCFS) {
        !          1611:                                *--bp = '/';
        !          1612:                        } else {
        !          1613:                                vp = curproc->p_cwdi->cwdi_rdir; /* XXXSMP */
        !          1614:                                if (vp == NULL)
        !          1615:                                        vp = rootvnode;
        !          1616:                                error = getcwd_common(vxp, vp, &bp, path,
        !          1617:                                    MAXPATHLEN / 2, 0, curlwp);
        !          1618:                        }
1.123.2.3  yamt     1619:                        FILE_UNUSE(fp, curlwp);
                   1620:                        if (error)
                   1621:                                break;
1.102     christos 1622:                        len = strlen(bp);
                   1623:                        break;
                   1624:
                   1625:                case DTYPE_MISC:
1.123     christos 1626:                        len = snprintf(bf, sizeof(bf), "%s", "[misc]");
1.102     christos 1627:                        break;
                   1628:
                   1629:                case DTYPE_KQUEUE:
1.123     christos 1630:                        len = snprintf(bf, sizeof(bf), "%s", "[kqueue]");
1.102     christos 1631:                        break;
                   1632:
                   1633:                default:
1.123.2.3  yamt     1634:                        error = EINVAL;
                   1635:                        break;
                   1636:                }
                   1637:                procfs_proc_unlock(pown);
1.102     christos 1638:        }
1.12      ws       1639:
1.123.2.3  yamt     1640:        if (error == 0)
                   1641:                error = uiomove(bp, len, ap->a_uio);
1.102     christos 1642:        if (path)
                   1643:                free(path, M_TEMP);
                   1644:        return error;
1.1       pk       1645: }
                   1646:
                   1647: /*
1.91      christos 1648:  * convert decimal ascii to int
1.1       pk       1649:  */
1.91      christos 1650: static int
                   1651: atoi(b, len)
1.9       cgd      1652:        const char *b;
1.91      christos 1653:        size_t len;
1.1       pk       1654: {
1.91      christos 1655:        int p = 0;
1.1       pk       1656:
                   1657:        while (len--) {
1.9       cgd      1658:                char c = *b++;
1.1       pk       1659:                if (c < '0' || c > '9')
1.91      christos 1660:                        return -1;
1.9       cgd      1661:                p = 10 * p + (c - '0');
1.1       pk       1662:        }
1.9       cgd      1663:
1.91      christos 1664:        return p;
1.1       pk       1665: }

CVSweb <webmaster@jp.NetBSD.org>