[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.177.2.1

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

CVSweb <webmaster@jp.NetBSD.org>