root/miscfs/procfs/procfs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. procfs_open
  2. procfs_close
  3. procfs_ioctl
  4. procfs_bmap
  5. procfs_inactive
  6. procfs_reclaim
  7. procfs_pathconf
  8. procfs_print
  9. procfs_link
  10. procfs_symlink
  11. procfs_badop
  12. procfs_getattr
  13. procfs_setattr
  14. procfs_access
  15. procfs_lookup
  16. procfs_validfile
  17. procfs_validfile_linux
  18. procfs_readdir
  19. procfs_readlink
  20. atopid
  21. procfs_poll

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

/* [<][>][^][v][top][bottom][index][help] */