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

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

CVSweb <webmaster@jp.NetBSD.org>