The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/ptyfs/ptyfs_vnops.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ptyfs_vnops.c,v 1.18.2.1 2007/02/17 23:27:45 tron Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1993, 1995
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Jan-Simon Pendry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
   35  */
   36 
   37 /*
   38  * Copyright (c) 1993 Jan-Simon Pendry
   39  *
   40  * This code is derived from software contributed to Berkeley by
   41  * Jan-Simon Pendry.
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  * 3. All advertising materials mentioning features or use of this software
   52  *    must display the following acknowledgement:
   53  *      This product includes software developed by the University of
   54  *      California, Berkeley and its contributors.
   55  * 4. Neither the name of the University nor the names of its contributors
   56  *    may be used to endorse or promote products derived from this software
   57  *    without specific prior written permission.
   58  *
   59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   69  * SUCH DAMAGE.
   70  *
   71  *      @(#)procfs_vnops.c      8.18 (Berkeley) 5/21/95
   72  */
   73 
   74 /*
   75  * ptyfs vnode interface
   76  */
   77 
   78 #include <sys/cdefs.h>
   79 __KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.18.2.1 2007/02/17 23:27:45 tron Exp $");
   80 
   81 #include <sys/param.h>
   82 #include <sys/systm.h>
   83 #include <sys/time.h>
   84 #include <sys/kernel.h>
   85 #include <sys/file.h>
   86 #include <sys/filedesc.h>
   87 #include <sys/proc.h>
   88 #include <sys/vnode.h>
   89 #include <sys/namei.h>
   90 #include <sys/malloc.h>
   91 #include <sys/mount.h>
   92 #include <sys/select.h>
   93 #include <sys/dirent.h>
   94 #include <sys/resourcevar.h>
   95 #include <sys/stat.h>
   96 #include <sys/conf.h>
   97 #include <sys/tty.h>
   98 #include <sys/pty.h>
   99 #include <sys/kauth.h>
  100 
  101 #include <uvm/uvm_extern.h>     /* for PAGE_SIZE */
  102 
  103 #include <machine/reg.h>
  104 
  105 #include <fs/ptyfs/ptyfs.h>
  106 #include <miscfs/genfs/genfs.h>
  107 #include <miscfs/specfs/specdev.h>
  108 
  109 /*
  110  * Vnode Operations.
  111  *
  112  */
  113 
  114 int     ptyfs_lookup    (void *);
  115 #define ptyfs_create    genfs_eopnotsupp
  116 #define ptyfs_mknod     genfs_eopnotsupp
  117 int     ptyfs_open      (void *);
  118 int     ptyfs_close     (void *);
  119 int     ptyfs_access    (void *);
  120 int     ptyfs_getattr   (void *);
  121 int     ptyfs_setattr   (void *);
  122 int     ptyfs_read      (void *);
  123 int     ptyfs_write     (void *);
  124 #define ptyfs_fcntl     genfs_fcntl
  125 int     ptyfs_ioctl     (void *);
  126 int     ptyfs_poll      (void *);
  127 int     ptyfs_kqfilter  (void *);
  128 #define ptyfs_revoke    genfs_revoke
  129 #define ptyfs_mmap      genfs_eopnotsupp
  130 #define ptyfs_fsync     genfs_nullop
  131 #define ptyfs_seek      genfs_nullop
  132 #define ptyfs_remove    genfs_eopnotsupp
  133 #define ptyfs_link      genfs_abortop
  134 #define ptyfs_rename    genfs_eopnotsupp
  135 #define ptyfs_mkdir     genfs_eopnotsupp
  136 #define ptyfs_rmdir     genfs_eopnotsupp
  137 #define ptyfs_symlink   genfs_abortop
  138 int     ptyfs_readdir   (void *);
  139 #define ptyfs_readlink  genfs_eopnotsupp
  140 #define ptyfs_abortop   genfs_abortop
  141 int     ptyfs_reclaim   (void *);
  142 #define ptyfs_lock      genfs_lock
  143 #define ptyfs_unlock    genfs_unlock
  144 #define ptyfs_bmap      genfs_badop
  145 #define ptyfs_strategy  genfs_badop
  146 int     ptyfs_print     (void *);
  147 int     ptyfs_pathconf  (void *);
  148 #define ptyfs_islocked  genfs_islocked
  149 #define ptyfs_advlock   genfs_einval
  150 #define ptyfs_bwrite    genfs_eopnotsupp
  151 #define ptyfs_putpages  genfs_null_putpages
  152 
  153 static int ptyfs_update(struct vnode *, const struct timespec *,
  154     const struct timespec *, int);
  155 static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
  156     struct lwp *);
  157 static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
  158 static int atoi(const char *, size_t);
  159 
  160 extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
  161 
  162 /*
  163  * ptyfs vnode operations.
  164  */
  165 int (**ptyfs_vnodeop_p)(void *);
  166 const struct vnodeopv_entry_desc ptyfs_vnodeop_entries[] = {
  167         { &vop_default_desc, vn_default_error },
  168         { &vop_lookup_desc, ptyfs_lookup },             /* lookup */
  169         { &vop_create_desc, ptyfs_create },             /* create */
  170         { &vop_mknod_desc, ptyfs_mknod },               /* mknod */
  171         { &vop_open_desc, ptyfs_open },                 /* open */
  172         { &vop_close_desc, ptyfs_close },               /* close */
  173         { &vop_access_desc, ptyfs_access },             /* access */
  174         { &vop_getattr_desc, ptyfs_getattr },           /* getattr */
  175         { &vop_setattr_desc, ptyfs_setattr },           /* setattr */
  176         { &vop_read_desc, ptyfs_read },                 /* read */
  177         { &vop_write_desc, ptyfs_write },               /* write */
  178         { &vop_ioctl_desc, ptyfs_ioctl },               /* ioctl */
  179         { &vop_fcntl_desc, ptyfs_fcntl },               /* fcntl */
  180         { &vop_poll_desc, ptyfs_poll },                 /* poll */
  181         { &vop_kqfilter_desc, ptyfs_kqfilter },         /* kqfilter */
  182         { &vop_revoke_desc, ptyfs_revoke },             /* revoke */
  183         { &vop_mmap_desc, ptyfs_mmap },                 /* mmap */
  184         { &vop_fsync_desc, ptyfs_fsync },               /* fsync */
  185         { &vop_seek_desc, ptyfs_seek },                 /* seek */
  186         { &vop_remove_desc, ptyfs_remove },             /* remove */
  187         { &vop_link_desc, ptyfs_link },                 /* link */
  188         { &vop_rename_desc, ptyfs_rename },             /* rename */
  189         { &vop_mkdir_desc, ptyfs_mkdir },               /* mkdir */
  190         { &vop_rmdir_desc, ptyfs_rmdir },               /* rmdir */
  191         { &vop_symlink_desc, ptyfs_symlink },           /* symlink */
  192         { &vop_readdir_desc, ptyfs_readdir },           /* readdir */
  193         { &vop_readlink_desc, ptyfs_readlink },         /* readlink */
  194         { &vop_abortop_desc, ptyfs_abortop },           /* abortop */
  195         { &vop_inactive_desc, spec_inactive },          /* inactive */
  196         { &vop_reclaim_desc, ptyfs_reclaim },           /* reclaim */
  197         { &vop_lock_desc, ptyfs_lock },                 /* lock */
  198         { &vop_unlock_desc, ptyfs_unlock },             /* unlock */
  199         { &vop_bmap_desc, ptyfs_bmap },                 /* bmap */
  200         { &vop_strategy_desc, ptyfs_strategy },         /* strategy */
  201         { &vop_print_desc, ptyfs_print },               /* print */
  202         { &vop_islocked_desc, ptyfs_islocked },         /* islocked */
  203         { &vop_pathconf_desc, ptyfs_pathconf },         /* pathconf */
  204         { &vop_advlock_desc, ptyfs_advlock },           /* advlock */
  205         { &vop_bwrite_desc, ptyfs_bwrite },             /* bwrite */
  206         { &vop_putpages_desc, ptyfs_putpages },         /* putpages */
  207         { NULL, NULL }
  208 };
  209 const struct vnodeopv_desc ptyfs_vnodeop_opv_desc =
  210         { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries };
  211 
  212 /*
  213  * _reclaim is called when getnewvnode()
  214  * wants to make use of an entry on the vnode
  215  * free list.  at this time the filesystem needs
  216  * to free any private data and remove the node
  217  * from any private lists.
  218  */
  219 int
  220 ptyfs_reclaim(void *v)
  221 {
  222         struct vop_reclaim_args /* {
  223                 struct vnode *a_vp;
  224         } */ *ap = v;
  225         return ptyfs_freevp(ap->a_vp);
  226 }
  227 
  228 /*
  229  * Return POSIX pathconf information applicable to special devices.
  230  */
  231 int
  232 ptyfs_pathconf(void *v)
  233 {
  234         struct vop_pathconf_args /* {
  235                 struct vnode *a_vp;
  236                 int a_name;
  237                 register_t *a_retval;
  238         } */ *ap = v;
  239 
  240         switch (ap->a_name) {
  241         case _PC_LINK_MAX:
  242                 *ap->a_retval = LINK_MAX;
  243                 return 0;
  244         case _PC_MAX_CANON:
  245                 *ap->a_retval = MAX_CANON;
  246                 return 0;
  247         case _PC_MAX_INPUT:
  248                 *ap->a_retval = MAX_INPUT;
  249                 return 0;
  250         case _PC_PIPE_BUF:
  251                 *ap->a_retval = PIPE_BUF;
  252                 return 0;
  253         case _PC_CHOWN_RESTRICTED:
  254                 *ap->a_retval = 1;
  255                 return 0;
  256         case _PC_VDISABLE:
  257                 *ap->a_retval = _POSIX_VDISABLE;
  258                 return 0;
  259         case _PC_SYNC_IO:
  260                 *ap->a_retval = 1;
  261                 return 0;
  262         default:
  263                 return EINVAL;
  264         }
  265 }
  266 
  267 /*
  268  * _print is used for debugging.
  269  * just print a readable description
  270  * of (vp).
  271  */
  272 int
  273 ptyfs_print(void *v)
  274 {
  275         struct vop_print_args /* {
  276                 struct vnode *a_vp;
  277         } */ *ap = v;
  278         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  279 
  280         printf("tag VT_PTYFS, type %d, pty %d\n",
  281             ptyfs->ptyfs_type, ptyfs->ptyfs_pty);
  282         return 0;
  283 }
  284 
  285 /*
  286  * Invent attributes for ptyfsnode (vp) and store
  287  * them in (vap).
  288  * Directories lengths are returned as zero since
  289  * any real length would require the genuine size
  290  * to be computed, and nothing cares anyway.
  291  *
  292  * this is relatively minimal for ptyfs.
  293  */
  294 int
  295 ptyfs_getattr(void *v)
  296 {
  297         struct vop_getattr_args /* {
  298                 struct vnode *a_vp;
  299                 struct vattr *a_vap;
  300                 kauth_cred_t a_cred;
  301                 struct lwp *a_l;
  302         } */ *ap = v;
  303         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  304         struct vattr *vap = ap->a_vap;
  305 
  306         PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  307 
  308         /* start by zeroing out the attributes */
  309         VATTR_NULL(vap);
  310 
  311         /* next do all the common fields */
  312         vap->va_type = ap->a_vp->v_type;
  313         vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
  314         vap->va_fileid = ptyfs->ptyfs_fileno;
  315         vap->va_gen = 0;
  316         vap->va_flags = 0;
  317         vap->va_nlink = 1;
  318         vap->va_blocksize = PAGE_SIZE;
  319 
  320         vap->va_atime = ptyfs->ptyfs_atime;
  321         vap->va_mtime = ptyfs->ptyfs_mtime;
  322         vap->va_ctime = ptyfs->ptyfs_ctime;
  323         vap->va_birthtime = ptyfs->ptyfs_birthtime;
  324         vap->va_mode = ptyfs->ptyfs_mode;
  325         vap->va_flags = ptyfs->ptyfs_flags;
  326         vap->va_uid = ptyfs->ptyfs_uid;
  327         vap->va_gid = ptyfs->ptyfs_gid;
  328 
  329         switch (ptyfs->ptyfs_type) {
  330         case PTYFSpts:
  331         case PTYFSptc:
  332                 if (pty_isfree(ptyfs->ptyfs_pty, 1))
  333                         return ENOENT;
  334                 vap->va_bytes = vap->va_size = 0;
  335                 vap->va_rdev = ap->a_vp->v_rdev;
  336                 break;
  337         case PTYFSroot:
  338                 vap->va_rdev = 0;
  339                 vap->va_bytes = vap->va_size = DEV_BSIZE;
  340                 break;
  341 
  342         default:
  343                 return EOPNOTSUPP;
  344         }
  345 
  346         return 0;
  347 }
  348 
  349 /*ARGSUSED*/
  350 int
  351 ptyfs_setattr(void *v)
  352 {
  353         struct vop_setattr_args /* {
  354                 struct vnodeop_desc *a_desc;
  355                 struct vnode *a_vp;
  356                 struct vattr *a_vap;
  357                 kauth_cred_t a_cred;
  358                 struct lwp *a_l;
  359         } */ *ap = v;
  360         struct vnode *vp = ap->a_vp;
  361         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  362         struct vattr *vap = ap->a_vap;
  363         kauth_cred_t cred = ap->a_cred;
  364         struct lwp *l = ap->a_l;
  365         int error;
  366 
  367         if (vap->va_size != VNOVAL) {
  368                 switch (ptyfs->ptyfs_type) {
  369                 case PTYFSroot:
  370                         return EISDIR;
  371                 case PTYFSpts:
  372                 case PTYFSptc:
  373                         break;
  374                 default:
  375                         return EINVAL;
  376                 }
  377         }
  378 
  379         if (vap->va_flags != VNOVAL) {
  380                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  381                         return EROFS;
  382                 if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  383                     (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  384                     &l->l_acflag)) != 0)
  385                         return error;
  386                 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
  387                         if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) &&
  388                             securelevel > 0)
  389                                 return EPERM;
  390                         /* Snapshot flag cannot be set or cleared */
  391                         if ((vap->va_flags & SF_SNAPSHOT) !=
  392                             (ptyfs->ptyfs_flags & SF_SNAPSHOT))
  393                                 return EPERM;
  394                         ptyfs->ptyfs_flags = vap->va_flags;
  395                 } else {
  396                         if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) ||
  397                             (vap->va_flags & UF_SETTABLE) != vap->va_flags)
  398                                 return EPERM;
  399                         if ((ptyfs->ptyfs_flags & SF_SETTABLE) !=
  400                             (vap->va_flags & SF_SETTABLE))
  401                                 return EPERM;
  402                         ptyfs->ptyfs_flags &= SF_SETTABLE;
  403                         ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
  404                 }
  405                 ptyfs->ptyfs_flag |= PTYFS_CHANGE;
  406                 if (vap->va_flags & (IMMUTABLE | APPEND))
  407                         return 0;
  408         }
  409         if (ptyfs->ptyfs_flags & (IMMUTABLE | APPEND))
  410                 return EPERM;
  411         /*
  412          * Go through the fields and update iff not VNOVAL.
  413          */
  414         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  415                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  416                         return EROFS;
  417                 if (ptyfs->ptyfs_type == PTYFSroot)
  418                         return EPERM;
  419                 error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
  420                 if (error)
  421                         return error;
  422         }
  423 
  424         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
  425             vap->va_birthtime.tv_sec != VNOVAL) {
  426                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  427                         return EROFS;
  428                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
  429                         return EPERM;
  430                 if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  431                     (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  432                     &l->l_acflag)) &&
  433                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
  434                     (error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0))
  435                         return (error);
  436                 if (vap->va_atime.tv_sec != VNOVAL)
  437                         if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
  438                                 ptyfs->ptyfs_flag |= PTYFS_ACCESS;
  439                 if (vap->va_mtime.tv_sec != VNOVAL)
  440                         ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY;
  441                 if (vap->va_birthtime.tv_sec != VNOVAL)
  442                         ptyfs->ptyfs_birthtime = vap->va_birthtime;
  443                 ptyfs->ptyfs_flag |= PTYFS_CHANGE;
  444                 error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
  445                 if (error)
  446                         return error;
  447         }
  448         if (vap->va_mode != (mode_t)VNOVAL) {
  449                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  450                         return EROFS;
  451                 if (ptyfs->ptyfs_type == PTYFSroot)
  452                         return EPERM;
  453                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
  454                     (vap->va_mode &
  455                     (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH)))
  456                         return EPERM;
  457                 error = ptyfs_chmod(vp, vap->va_mode, cred, l);
  458                 if (error)
  459                         return error;
  460         }
  461         VN_KNOTE(vp, NOTE_ATTRIB);
  462         return 0;
  463 }
  464 
  465 /*
  466  * Change the mode on a file.
  467  * Inode must be locked before calling.
  468  */
  469 static int
  470 ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l)
  471 {
  472         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  473         int error;
  474 
  475         if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  476             (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  477             &l->l_acflag)) != 0)
  478                 return error;
  479         ptyfs->ptyfs_mode &= ~ALLPERMS;
  480         ptyfs->ptyfs_mode |= (mode & ALLPERMS);
  481         return 0;
  482 }
  483 
  484 /*
  485  * Perform chown operation on inode ip;
  486  * inode must be locked prior to call.
  487  */
  488 static int
  489 ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
  490     struct lwp *l)
  491 {
  492         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  493         int             error, ismember = 0;
  494 
  495         if (uid == (uid_t)VNOVAL)
  496                 uid = ptyfs->ptyfs_uid;
  497         if (gid == (gid_t)VNOVAL)
  498                 gid = ptyfs->ptyfs_gid;
  499         /*
  500          * If we don't own the file, are trying to change the owner
  501          * of the file, or are not a member of the target group,
  502          * the caller's credentials must imply super-user privilege
  503          * or the call fails.
  504          */
  505         if ((kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid || uid != ptyfs->ptyfs_uid ||
  506             (gid != ptyfs->ptyfs_gid &&
  507             !(kauth_cred_getegid(cred) == gid ||
  508             (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
  509             ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  510             &l->l_acflag)) != 0))
  511                 return error;
  512 
  513         ptyfs->ptyfs_gid = gid;
  514         ptyfs->ptyfs_uid = uid;
  515         return 0;
  516 }
  517 
  518 /*
  519  * implement access checking.
  520  *
  521  * actually, the check for super-user is slightly
  522  * broken since it will allow read access to write-only
  523  * objects.  this doesn't cause any particular trouble
  524  * but does mean that the i/o entry points need to check
  525  * that the operation really does make sense.
  526  */
  527 int
  528 ptyfs_access(void *v)
  529 {
  530         struct vop_access_args /* {
  531                 struct vnode *a_vp;
  532                 int a_mode;
  533                 kauth_cred_t a_cred;
  534                 struct lwp *a_l;
  535         } */ *ap = v;
  536         struct vattr va;
  537         int error;
  538 
  539         if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
  540                 return error;
  541 
  542         return vaccess(va.va_type, va.va_mode,
  543             va.va_uid, va.va_gid, ap->a_mode, ap->a_cred);
  544 }
  545 
  546 /*
  547  * lookup.  this is incredibly complicated in the
  548  * general case, however for most pseudo-filesystems
  549  * very little needs to be done.
  550  *
  551  * Locking isn't hard here, just poorly documented.
  552  *
  553  * If we're looking up ".", just vref the parent & return it.
  554  *
  555  * If we're looking up "..", unlock the parent, and lock "..". If everything
  556  * went ok, try to re-lock the parent. We do this to prevent lock races.
  557  *
  558  * For anything else, get the needed node.
  559  *
  560  * We try to exit with the parent locked in error cases.
  561  */
  562 int
  563 ptyfs_lookup(void *v)
  564 {
  565         struct vop_lookup_args /* {
  566                 struct vnode * a_dvp;
  567                 struct vnode ** a_vpp;
  568                 struct componentname * a_cnp;
  569         } */ *ap = v;
  570         struct componentname *cnp = ap->a_cnp;
  571         struct vnode **vpp = ap->a_vpp;
  572         struct vnode *dvp = ap->a_dvp;
  573         const char *pname = cnp->cn_nameptr;
  574         struct ptyfsnode *ptyfs;
  575         int pty, error;
  576 
  577         *vpp = NULL;
  578 
  579         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  580                 return EROFS;
  581 
  582         if (cnp->cn_namelen == 1 && *pname == '.') {
  583                 *vpp = dvp;
  584                 VREF(dvp);
  585                 return 0;
  586         }
  587 
  588         ptyfs = VTOPTYFS(dvp);
  589         switch (ptyfs->ptyfs_type) {
  590         case PTYFSroot:
  591                 /*
  592                  * Shouldn't get here with .. in the root node.
  593                  */
  594                 if (cnp->cn_flags & ISDOTDOT)
  595                         return EIO;
  596 
  597                 pty = atoi(pname, cnp->cn_namelen);
  598 
  599                 if (pty < 0 || pty >= npty || pty_isfree(pty, 1))
  600                         break;
  601 
  602                 error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty,
  603                     curlwp);
  604                 return error;
  605 
  606         default:
  607                 return ENOTDIR;
  608         }
  609 
  610         return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
  611 }
  612 
  613 /*
  614  * readdir returns directory entries from ptyfsnode (vp).
  615  *
  616  * the strategy here with ptyfs is to generate a single
  617  * directory entry at a time (struct dirent) and then
  618  * copy that out to userland using uiomove.  a more efficent
  619  * though more complex implementation, would try to minimize
  620  * the number of calls to uiomove().  for ptyfs, this is
  621  * hardly worth the added code complexity.
  622  *
  623  * this should just be done through read()
  624  */
  625 int
  626 ptyfs_readdir(void *v)
  627 {
  628         struct vop_readdir_args /* {
  629                 struct vnode *a_vp;
  630                 struct uio *a_uio;
  631                 kauth_cred_t a_cred;
  632                 int *a_eofflag;
  633                 off_t **a_cookies;
  634                 int *a_ncookies;
  635         } */ *ap = v;
  636         struct uio *uio = ap->a_uio;
  637         struct dirent d;
  638         struct ptyfsnode *ptyfs;
  639         off_t i;
  640         int error;
  641         off_t *cookies = NULL;
  642         int ncookies;
  643         struct vnode *vp;
  644         int nc = 0;
  645 
  646         vp = ap->a_vp;
  647         ptyfs = VTOPTYFS(vp);
  648 
  649         if (uio->uio_resid < UIO_MX)
  650                 return EINVAL;
  651         if (uio->uio_offset < 0)
  652                 return EINVAL;
  653 
  654         error = 0;
  655         i = uio->uio_offset;
  656         (void)memset(&d, 0, sizeof(d));
  657         d.d_reclen = UIO_MX;
  658         ncookies = uio->uio_resid / UIO_MX;
  659 
  660         switch (ptyfs->ptyfs_type) {
  661         case PTYFSroot: /* root */
  662 
  663                 if (i >= npty)
  664                         return 0;
  665 
  666                 if (ap->a_ncookies) {
  667                         ncookies = min(ncookies, (npty + 2 - i));
  668                         cookies = malloc(ncookies * sizeof (off_t),
  669                             M_TEMP, M_WAITOK);
  670                         *ap->a_cookies = cookies;
  671                 }
  672 
  673                 for (; i < 2; i++) {
  674                         switch (i) {
  675                         case 0:         /* `.' */
  676                         case 1:         /* `..' */
  677                                 d.d_fileno = PTYFS_FILENO(0, PTYFSroot);
  678                                 d.d_namlen = i + 1;
  679                                 (void)memcpy(d.d_name, "..", d.d_namlen);
  680                                 d.d_name[i + 1] = '\0';
  681                                 d.d_type = DT_DIR;
  682                                 break;
  683                         }
  684                         if ((error = uiomove(&d, UIO_MX, uio)) != 0)
  685                                 break;
  686                         if (cookies)
  687                                 *cookies++ = i + 1;
  688                         nc++;
  689                 }
  690                 if (error) {
  691                         ncookies = nc;
  692                         break;
  693                 }
  694                 for (; uio->uio_resid >= UIO_MX && i < npty; i++) {
  695                         /* check for used ptys */
  696                         if (pty_isfree(i - 2, 1))
  697                                 continue;
  698 
  699                         d.d_fileno = PTYFS_FILENO(i - 2, PTYFSpts);
  700                         d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
  701                             "%lld", (long long)(i - 2));
  702                         d.d_type = DT_CHR;
  703                         if ((error = uiomove(&d, UIO_MX, uio)) != 0)
  704                                 break;
  705                         if (cookies)
  706                                 *cookies++ = i + 1;
  707                         nc++;
  708                 }
  709                 ncookies = nc;
  710                 break;
  711 
  712         default:
  713                 error = ENOTDIR;
  714                 break;
  715         }
  716 
  717         if (ap->a_ncookies) {
  718                 if (error) {
  719                         if (cookies)
  720                                 free(*ap->a_cookies, M_TEMP);
  721                         *ap->a_ncookies = 0;
  722                         *ap->a_cookies = NULL;
  723                 } else
  724                         *ap->a_ncookies = ncookies;
  725         }
  726         uio->uio_offset = i;
  727         return error;
  728 }
  729 
  730 int
  731 ptyfs_open(void *v)
  732 {
  733         struct vop_open_args /* {
  734                 struct vnode *a_vp;
  735                 int  a_mode;
  736                 kauth_cred_t a_cred;
  737                 struct lwp *a_l;
  738         } */ *ap = v;
  739         struct vnode *vp = ap->a_vp;
  740         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  741 
  742         ptyfs->ptyfs_flag |= PTYFS_CHANGE|PTYFS_ACCESS;
  743         switch (ptyfs->ptyfs_type) {
  744         case PTYFSpts:
  745         case PTYFSptc:
  746                 return spec_open(v);
  747         case PTYFSroot:
  748                 return 0;
  749         default:
  750                 return EINVAL;
  751         }
  752 }
  753 
  754 int
  755 ptyfs_close(void *v)
  756 {
  757         struct vop_close_args /* {
  758                 struct vnode *a_vp;
  759                 int  a_fflag;
  760                 kauth_cred_t a_cred;
  761                 struct lwp *a_l;
  762         } */ *ap = v;
  763         struct vnode *vp = ap->a_vp;
  764         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  765 
  766         simple_lock(&vp->v_interlock);
  767         if (vp->v_usecount > 1)
  768                 PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  769         simple_unlock(&vp->v_interlock);
  770 
  771         switch (ptyfs->ptyfs_type) {
  772         case PTYFSpts:
  773         case PTYFSptc:
  774                 return spec_close(v);
  775         case PTYFSroot:
  776                 return 0;
  777         default:
  778                 return EINVAL;
  779         }
  780 }
  781 
  782 int
  783 ptyfs_read(void *v)
  784 {
  785         struct vop_read_args /* {
  786                 struct vnode *a_vp;
  787                 struct uio *a_uio;
  788                 int  a_ioflag;
  789                 kauth_cred_t a_cred;
  790         } */ *ap = v;
  791         struct timespec ts;
  792         struct vnode *vp = ap->a_vp;
  793         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  794         int error;
  795 
  796         ptyfs->ptyfs_flag |= PTYFS_ACCESS;
  797         /* hardclock() resolution is good enough for ptyfs */
  798         getnanotime(&ts);
  799         (void)ptyfs_update(vp, &ts, &ts, 0);
  800 
  801         switch (ptyfs->ptyfs_type) {
  802         case PTYFSpts:
  803                 VOP_UNLOCK(vp, 0);
  804                 error = (*pts_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
  805                     ap->a_ioflag);
  806                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  807                 return error;
  808         case PTYFSptc:
  809                 VOP_UNLOCK(vp, 0);
  810                 error = (*ptc_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
  811                     ap->a_ioflag);
  812                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  813                 return error;
  814         default:
  815                 return EOPNOTSUPP;
  816         }
  817 }
  818 
  819 int
  820 ptyfs_write(void *v)
  821 {
  822         struct vop_write_args /* {
  823                 struct vnode *a_vp;
  824                 struct uio *a_uio;
  825                 int  a_ioflag;
  826                 kauth_cred_t a_cred;
  827         } */ *ap = v;
  828         struct timespec ts;
  829         struct vnode *vp = ap->a_vp;
  830         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  831         int error;
  832 
  833         ptyfs->ptyfs_flag |= PTYFS_MODIFY;
  834         getnanotime(&ts);
  835         (void)ptyfs_update(vp, &ts, &ts, 0);
  836 
  837         switch (ptyfs->ptyfs_type) {
  838         case PTYFSpts:
  839                 VOP_UNLOCK(vp, 0);
  840                 error = (*pts_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
  841                     ap->a_ioflag);
  842                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  843                 return error;
  844         case PTYFSptc:
  845                 VOP_UNLOCK(vp, 0);
  846                 error = (*ptc_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
  847                     ap->a_ioflag);
  848                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  849                 return error;
  850         default:
  851                 return EOPNOTSUPP;
  852         }
  853 }
  854 
  855 int
  856 ptyfs_ioctl(void *v)
  857 {
  858         struct vop_ioctl_args /* {
  859                 struct vnode *a_vp;
  860                 u_long a_command;
  861                 void *a_data;
  862                 int  a_fflag;
  863                 kauth_cred_t a_cred;
  864                 struct lwp *a_l;
  865         } */ *ap = v;
  866         struct vnode *vp = ap->a_vp;
  867         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  868 
  869         switch (ptyfs->ptyfs_type) {
  870         case PTYFSpts:
  871                 return (*pts_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
  872                     ap->a_data, ap->a_fflag, ap->a_l);
  873         case PTYFSptc:
  874                 return (*ptc_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
  875                     ap->a_data, ap->a_fflag, ap->a_l);
  876         default:
  877                 return EOPNOTSUPP;
  878         }
  879 }
  880 
  881 int
  882 ptyfs_poll(void *v)
  883 {
  884         struct vop_poll_args /* {
  885                 struct vnode *a_vp;
  886                 int a_events;
  887                 struct lwp *a_l;
  888         } */ *ap = v;
  889         struct vnode *vp = ap->a_vp;
  890         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  891 
  892         switch (ptyfs->ptyfs_type) {
  893         case PTYFSpts:
  894                 return (*pts_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
  895         case PTYFSptc:
  896                 return (*ptc_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
  897         default:
  898                 return genfs_poll(v);
  899         }
  900 }
  901 
  902 int
  903 ptyfs_kqfilter(void *v)
  904 {
  905         struct vop_kqfilter_args /* {
  906                 struct vnode *a_vp;
  907                 struct knote *a_kn;
  908         } */ *ap = v;
  909         struct vnode *vp = ap->a_vp;
  910         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  911 
  912         switch (ptyfs->ptyfs_type) {
  913         case PTYFSpts:
  914                 return (*pts_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
  915         case PTYFSptc:
  916                 return (*ptc_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
  917         default:
  918                 return genfs_kqfilter(v);
  919         }
  920 }
  921 
  922 static int
  923 ptyfs_update(struct vnode *vp, const struct timespec *acc,
  924     const struct timespec *mod, int flags)
  925 {
  926         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  927 
  928         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  929                 return 0;
  930 
  931         PTYFS_ITIMES(ptyfs, acc, mod, NULL);
  932         return 0;
  933 }
  934 
  935 void
  936 ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc,
  937     const struct timespec *mod, const struct timespec *cre)
  938 {
  939         struct timespec now;
  940  
  941         KASSERT(ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY));
  942 
  943         getnanotime(&now);
  944         if (ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_MODIFY)) {
  945                 if (acc == NULL)
  946                         acc = &now;
  947                 ptyfs->ptyfs_atime = *acc;
  948         }
  949         if (ptyfs->ptyfs_flag & PTYFS_MODIFY) {
  950                 if (mod == NULL)
  951                         mod = &now;
  952                 ptyfs->ptyfs_mtime = *mod;
  953         }
  954         if (ptyfs->ptyfs_flag & PTYFS_CHANGE) {
  955                 if (cre == NULL)
  956                         cre = &now;
  957                 ptyfs->ptyfs_ctime = *cre;
  958         }
  959         ptyfs->ptyfs_flag &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY);
  960 }
  961 
  962 /*
  963  * convert decimal ascii to int
  964  */
  965 static int
  966 atoi(const char *b, size_t len)
  967 {
  968         int p = 0;
  969 
  970         while (len--) {
  971                 char c = *b++;
  972                 if (c < '' || c > '9')
  973                         return -1;
  974                 p = 10 * p + (c - '');
  975         }
  976 
  977         return p;
  978 }

Cache object: ae05ea9fc523214f435cc99c65d62d1f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.