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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ptyfs_vnops.c,v 1.27 2008/01/02 11:48:43 ad 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.27 2008/01/02 11:48:43 ad 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 MALLOC_DECLARE(M_PTYFSTMP);
  110 
  111 /*
  112  * Vnode Operations.
  113  *
  114  */
  115 
  116 int     ptyfs_lookup    (void *);
  117 #define ptyfs_create    genfs_eopnotsupp
  118 #define ptyfs_mknod     genfs_eopnotsupp
  119 int     ptyfs_open      (void *);
  120 int     ptyfs_close     (void *);
  121 int     ptyfs_access    (void *);
  122 int     ptyfs_getattr   (void *);
  123 int     ptyfs_setattr   (void *);
  124 int     ptyfs_read      (void *);
  125 int     ptyfs_write     (void *);
  126 #define ptyfs_fcntl     genfs_fcntl
  127 int     ptyfs_ioctl     (void *);
  128 int     ptyfs_poll      (void *);
  129 int     ptyfs_kqfilter  (void *);
  130 #define ptyfs_revoke    genfs_revoke
  131 #define ptyfs_mmap      genfs_eopnotsupp
  132 #define ptyfs_fsync     genfs_nullop
  133 #define ptyfs_seek      genfs_nullop
  134 #define ptyfs_remove    genfs_eopnotsupp
  135 #define ptyfs_link      genfs_abortop
  136 #define ptyfs_rename    genfs_eopnotsupp
  137 #define ptyfs_mkdir     genfs_eopnotsupp
  138 #define ptyfs_rmdir     genfs_eopnotsupp
  139 #define ptyfs_symlink   genfs_abortop
  140 int     ptyfs_readdir   (void *);
  141 #define ptyfs_readlink  genfs_eopnotsupp
  142 #define ptyfs_abortop   genfs_abortop
  143 int     ptyfs_reclaim   (void *);
  144 #define ptyfs_lock      genfs_lock
  145 #define ptyfs_unlock    genfs_unlock
  146 #define ptyfs_bmap      genfs_badop
  147 #define ptyfs_strategy  genfs_badop
  148 int     ptyfs_print     (void *);
  149 int     ptyfs_pathconf  (void *);
  150 #define ptyfs_islocked  genfs_islocked
  151 #define ptyfs_advlock   genfs_einval
  152 #define ptyfs_bwrite    genfs_eopnotsupp
  153 #define ptyfs_putpages  genfs_null_putpages
  154 
  155 static int ptyfs_update(struct vnode *, const struct timespec *,
  156     const struct timespec *, int);
  157 static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
  158     struct lwp *);
  159 static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
  160 static int atoi(const char *, size_t);
  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         } */ *ap = v;
  302         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  303         struct vattr *vap = ap->a_vap;
  304 
  305         PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  306 
  307         /* start by zeroing out the attributes */
  308         VATTR_NULL(vap);
  309 
  310         /* next do all the common fields */
  311         vap->va_type = ap->a_vp->v_type;
  312         vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
  313         vap->va_fileid = ptyfs->ptyfs_fileno;
  314         vap->va_gen = 0;
  315         vap->va_flags = 0;
  316         vap->va_nlink = 1;
  317         vap->va_blocksize = PAGE_SIZE;
  318 
  319         vap->va_atime = ptyfs->ptyfs_atime;
  320         vap->va_mtime = ptyfs->ptyfs_mtime;
  321         vap->va_ctime = ptyfs->ptyfs_ctime;
  322         vap->va_birthtime = ptyfs->ptyfs_birthtime;
  323         vap->va_mode = ptyfs->ptyfs_mode;
  324         vap->va_flags = ptyfs->ptyfs_flags;
  325         vap->va_uid = ptyfs->ptyfs_uid;
  326         vap->va_gid = ptyfs->ptyfs_gid;
  327 
  328         switch (ptyfs->ptyfs_type) {
  329         case PTYFSpts:
  330         case PTYFSptc:
  331                 if (pty_isfree(ptyfs->ptyfs_pty, 1))
  332                         return ENOENT;
  333                 vap->va_bytes = vap->va_size = 0;
  334                 vap->va_rdev = ap->a_vp->v_rdev;
  335                 break;
  336         case PTYFSroot:
  337                 vap->va_rdev = 0;
  338                 vap->va_bytes = vap->va_size = DEV_BSIZE;
  339                 break;
  340 
  341         default:
  342                 return EOPNOTSUPP;
  343         }
  344 
  345         return 0;
  346 }
  347 
  348 /*ARGSUSED*/
  349 int
  350 ptyfs_setattr(void *v)
  351 {
  352         struct vop_setattr_args /* {
  353                 struct vnodeop_desc *a_desc;
  354                 struct vnode *a_vp;
  355                 struct vattr *a_vap;
  356                 kauth_cred_t a_cred;
  357         } */ *ap = v;
  358         struct vnode *vp = ap->a_vp;
  359         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  360         struct vattr *vap = ap->a_vap;
  361         kauth_cred_t cred = ap->a_cred;
  362         struct lwp *l = curlwp;
  363         int error;
  364 
  365         if (vap->va_size != VNOVAL) {
  366                 switch (ptyfs->ptyfs_type) {
  367                 case PTYFSroot:
  368                         return EISDIR;
  369                 case PTYFSpts:
  370                 case PTYFSptc:
  371                         break;
  372                 default:
  373                         return EINVAL;
  374                 }
  375         }
  376 
  377         if (vap->va_flags != VNOVAL) {
  378                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  379                         return EROFS;
  380                 if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  381                     (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  382                     NULL)) != 0)
  383                         return error;
  384                 /* Immutable and append-only flags are not supported on ptyfs. */
  385                 if (vap->va_flags & (IMMUTABLE | APPEND))
  386                         return EINVAL;
  387                 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
  388                         /* Snapshot flag cannot be set or cleared */
  389                         if ((vap->va_flags & SF_SNAPSHOT) !=
  390                             (ptyfs->ptyfs_flags & SF_SNAPSHOT))
  391                                 return EPERM;
  392                         ptyfs->ptyfs_flags = vap->va_flags;
  393                 } else {
  394                         if ((ptyfs->ptyfs_flags & SF_SETTABLE) !=
  395                             (vap->va_flags & SF_SETTABLE))
  396                                 return EPERM;
  397                         ptyfs->ptyfs_flags &= SF_SETTABLE;
  398                         ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
  399                 }
  400                 ptyfs->ptyfs_flag |= PTYFS_CHANGE;
  401         }
  402 
  403         /*
  404          * Go through the fields and update iff not VNOVAL.
  405          */
  406         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  407                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  408                         return EROFS;
  409                 if (ptyfs->ptyfs_type == PTYFSroot)
  410                         return EPERM;
  411                 error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
  412                 if (error)
  413                         return error;
  414         }
  415 
  416         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
  417             vap->va_birthtime.tv_sec != VNOVAL) {
  418                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  419                         return EROFS;
  420                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
  421                         return EPERM;
  422                 if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  423                     (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  424                     NULL)) &&
  425                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
  426                     (error = VOP_ACCESS(vp, VWRITE, cred)) != 0))
  427                         return (error);
  428                 if (vap->va_atime.tv_sec != VNOVAL)
  429                         if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
  430                                 ptyfs->ptyfs_flag |= PTYFS_ACCESS;
  431                 if (vap->va_mtime.tv_sec != VNOVAL)
  432                         ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY;
  433                 if (vap->va_birthtime.tv_sec != VNOVAL)
  434                         ptyfs->ptyfs_birthtime = vap->va_birthtime;
  435                 ptyfs->ptyfs_flag |= PTYFS_CHANGE;
  436                 error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
  437                 if (error)
  438                         return error;
  439         }
  440         if (vap->va_mode != (mode_t)VNOVAL) {
  441                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  442                         return EROFS;
  443                 if (ptyfs->ptyfs_type == PTYFSroot)
  444                         return EPERM;
  445                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
  446                     (vap->va_mode &
  447                     (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH)))
  448                         return EPERM;
  449                 error = ptyfs_chmod(vp, vap->va_mode, cred, l);
  450                 if (error)
  451                         return error;
  452         }
  453         VN_KNOTE(vp, NOTE_ATTRIB);
  454         return 0;
  455 }
  456 
  457 /*
  458  * Change the mode on a file.
  459  * Inode must be locked before calling.
  460  */
  461 static int
  462 ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l)
  463 {
  464         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  465         int error;
  466 
  467         if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
  468             (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  469             NULL)) != 0)
  470                 return error;
  471         ptyfs->ptyfs_mode &= ~ALLPERMS;
  472         ptyfs->ptyfs_mode |= (mode & ALLPERMS);
  473         return 0;
  474 }
  475 
  476 /*
  477  * Perform chown operation on inode ip;
  478  * inode must be locked prior to call.
  479  */
  480 static int
  481 ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
  482     struct lwp *l)
  483 {
  484         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  485         int             error, ismember = 0;
  486 
  487         if (uid == (uid_t)VNOVAL)
  488                 uid = ptyfs->ptyfs_uid;
  489         if (gid == (gid_t)VNOVAL)
  490                 gid = ptyfs->ptyfs_gid;
  491         /*
  492          * If we don't own the file, are trying to change the owner
  493          * of the file, or are not a member of the target group,
  494          * the caller's credentials must imply super-user privilege
  495          * or the call fails.
  496          */
  497         if ((kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid || uid != ptyfs->ptyfs_uid ||
  498             (gid != ptyfs->ptyfs_gid &&
  499             !(kauth_cred_getegid(cred) == gid ||
  500             (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
  501             ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
  502             NULL)) != 0))
  503                 return error;
  504 
  505         ptyfs->ptyfs_gid = gid;
  506         ptyfs->ptyfs_uid = uid;
  507         return 0;
  508 }
  509 
  510 /*
  511  * implement access checking.
  512  *
  513  * actually, the check for super-user is slightly
  514  * broken since it will allow read access to write-only
  515  * objects.  this doesn't cause any particular trouble
  516  * but does mean that the i/o entry points need to check
  517  * that the operation really does make sense.
  518  */
  519 int
  520 ptyfs_access(void *v)
  521 {
  522         struct vop_access_args /* {
  523                 struct vnode *a_vp;
  524                 int a_mode;
  525                 kauth_cred_t a_cred;
  526         } */ *ap = v;
  527         struct vattr va;
  528         int error;
  529 
  530         if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
  531                 return error;
  532 
  533         return vaccess(va.va_type, va.va_mode,
  534             va.va_uid, va.va_gid, ap->a_mode, ap->a_cred);
  535 }
  536 
  537 /*
  538  * lookup.  this is incredibly complicated in the
  539  * general case, however for most pseudo-filesystems
  540  * very little needs to be done.
  541  *
  542  * Locking isn't hard here, just poorly documented.
  543  *
  544  * If we're looking up ".", just vref the parent & return it.
  545  *
  546  * If we're looking up "..", unlock the parent, and lock "..". If everything
  547  * went ok, try to re-lock the parent. We do this to prevent lock races.
  548  *
  549  * For anything else, get the needed node.
  550  *
  551  * We try to exit with the parent locked in error cases.
  552  */
  553 int
  554 ptyfs_lookup(void *v)
  555 {
  556         struct vop_lookup_args /* {
  557                 struct vnode * a_dvp;
  558                 struct vnode ** a_vpp;
  559                 struct componentname * a_cnp;
  560         } */ *ap = v;
  561         struct componentname *cnp = ap->a_cnp;
  562         struct vnode **vpp = ap->a_vpp;
  563         struct vnode *dvp = ap->a_dvp;
  564         const char *pname = cnp->cn_nameptr;
  565         struct ptyfsnode *ptyfs;
  566         int pty, error;
  567 
  568         *vpp = NULL;
  569 
  570         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  571                 return EROFS;
  572 
  573         if (cnp->cn_namelen == 1 && *pname == '.') {
  574                 *vpp = dvp;
  575                 VREF(dvp);
  576                 return 0;
  577         }
  578 
  579         ptyfs = VTOPTYFS(dvp);
  580         switch (ptyfs->ptyfs_type) {
  581         case PTYFSroot:
  582                 /*
  583                  * Shouldn't get here with .. in the root node.
  584                  */
  585                 if (cnp->cn_flags & ISDOTDOT)
  586                         return EIO;
  587 
  588                 pty = atoi(pname, cnp->cn_namelen);
  589 
  590                 if (pty < 0 || pty >= npty || pty_isfree(pty, 1))
  591                         break;
  592 
  593                 error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty,
  594                     curlwp);
  595                 return error;
  596 
  597         default:
  598                 return ENOTDIR;
  599         }
  600 
  601         return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
  602 }
  603 
  604 /*
  605  * readdir returns directory entries from ptyfsnode (vp).
  606  *
  607  * the strategy here with ptyfs is to generate a single
  608  * directory entry at a time (struct dirent) and then
  609  * copy that out to userland using uiomove.  a more efficent
  610  * though more complex implementation, would try to minimize
  611  * the number of calls to uiomove().  for ptyfs, this is
  612  * hardly worth the added code complexity.
  613  *
  614  * this should just be done through read()
  615  */
  616 int
  617 ptyfs_readdir(void *v)
  618 {
  619         struct vop_readdir_args /* {
  620                 struct vnode *a_vp;
  621                 struct uio *a_uio;
  622                 kauth_cred_t a_cred;
  623                 int *a_eofflag;
  624                 off_t **a_cookies;
  625                 int *a_ncookies;
  626         } */ *ap = v;
  627         struct uio *uio = ap->a_uio;
  628         struct dirent *dp;
  629         struct ptyfsnode *ptyfs;
  630         off_t i;
  631         int error;
  632         off_t *cookies = NULL;
  633         int ncookies;
  634         struct vnode *vp;
  635         int nc = 0;
  636 
  637         vp = ap->a_vp;
  638         ptyfs = VTOPTYFS(vp);
  639 
  640         if (uio->uio_resid < UIO_MX)
  641                 return EINVAL;
  642         if (uio->uio_offset < 0)
  643                 return EINVAL;
  644 
  645         dp = malloc(sizeof(struct dirent), M_PTYFSTMP, M_WAITOK | M_ZERO);
  646 
  647         error = 0;
  648         i = uio->uio_offset;
  649         dp->d_reclen = UIO_MX;
  650         ncookies = uio->uio_resid / UIO_MX;
  651 
  652         if (ptyfs->ptyfs_type != PTYFSroot) {
  653                 error = ENOTDIR;
  654                 goto out;
  655         }
  656 
  657         if (i >= npty)
  658                 goto out;
  659 
  660         if (ap->a_ncookies) {
  661                 ncookies = min(ncookies, (npty + 2 - i));
  662                 cookies = malloc(ncookies * sizeof (off_t),
  663                     M_TEMP, M_WAITOK);
  664                 *ap->a_cookies = cookies;
  665         }
  666 
  667         for (; i < 2; i++) {
  668                 /* `.' and/or `..' */
  669                 dp->d_fileno = PTYFS_FILENO(0, PTYFSroot);
  670                 dp->d_namlen = i + 1;
  671                 (void)memcpy(dp->d_name, "..", dp->d_namlen);
  672                 dp->d_name[i + 1] = '\0';
  673                 dp->d_type = DT_DIR;
  674                 if ((error = uiomove(dp, UIO_MX, uio)) != 0)
  675                         goto out;
  676                 if (cookies)
  677                         *cookies++ = i + 1;
  678                 nc++;
  679         }
  680         for (; uio->uio_resid >= UIO_MX && i < npty; i++) {
  681                 /* check for used ptys */
  682                 if (pty_isfree(i - 2, 1))
  683                         continue;
  684 
  685                 dp->d_fileno = PTYFS_FILENO(i - 2, PTYFSpts);
  686                 dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name),
  687                     "%lld", (long long)(i - 2));
  688                 dp->d_type = DT_CHR;
  689                 if ((error = uiomove(dp, UIO_MX, uio)) != 0)
  690                         goto out;
  691                 if (cookies)
  692                         *cookies++ = i + 1;
  693                 nc++;
  694         }
  695 
  696 out:
  697         /* not pertinent in error cases */
  698         ncookies = nc;
  699 
  700         if (ap->a_ncookies) {
  701                 if (error) {
  702                         if (cookies)
  703                                 free(*ap->a_cookies, M_TEMP);
  704                         *ap->a_ncookies = 0;
  705                         *ap->a_cookies = NULL;
  706                 } else
  707                         *ap->a_ncookies = ncookies;
  708         }
  709         uio->uio_offset = i;
  710         free(dp, M_PTYFSTMP);
  711         return error;
  712 }
  713 
  714 int
  715 ptyfs_open(void *v)
  716 {
  717         struct vop_open_args /* {
  718                 struct vnode *a_vp;
  719                 int  a_mode;
  720                 kauth_cred_t a_cred;
  721         } */ *ap = v;
  722         struct vnode *vp = ap->a_vp;
  723         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  724 
  725         ptyfs->ptyfs_flag |= PTYFS_CHANGE|PTYFS_ACCESS;
  726         switch (ptyfs->ptyfs_type) {
  727         case PTYFSpts:
  728         case PTYFSptc:
  729                 return spec_open(v);
  730         case PTYFSroot:
  731                 return 0;
  732         default:
  733                 return EINVAL;
  734         }
  735 }
  736 
  737 int
  738 ptyfs_close(void *v)
  739 {
  740         struct vop_close_args /* {
  741                 struct vnode *a_vp;
  742                 int  a_fflag;
  743                 kauth_cred_t a_cred;
  744         } */ *ap = v;
  745         struct vnode *vp = ap->a_vp;
  746         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  747 
  748         mutex_enter(&vp->v_interlock);
  749         if (vp->v_usecount > 1)
  750                 PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  751         mutex_exit(&vp->v_interlock);
  752 
  753         switch (ptyfs->ptyfs_type) {
  754         case PTYFSpts:
  755         case PTYFSptc:
  756                 return spec_close(v);
  757         case PTYFSroot:
  758                 return 0;
  759         default:
  760                 return EINVAL;
  761         }
  762 }
  763 
  764 int
  765 ptyfs_read(void *v)
  766 {
  767         struct vop_read_args /* {
  768                 struct vnode *a_vp;
  769                 struct uio *a_uio;
  770                 int  a_ioflag;
  771                 kauth_cred_t a_cred;
  772         } */ *ap = v;
  773         struct timespec ts;
  774         struct vnode *vp = ap->a_vp;
  775         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  776         int error;
  777 
  778         ptyfs->ptyfs_flag |= PTYFS_ACCESS;
  779         /* hardclock() resolution is good enough for ptyfs */
  780         getnanotime(&ts);
  781         (void)ptyfs_update(vp, &ts, &ts, 0);
  782 
  783         switch (ptyfs->ptyfs_type) {
  784         case PTYFSpts:
  785         case PTYFSptc:
  786                 VOP_UNLOCK(vp, 0);
  787                 error = cdev_read(vp->v_rdev, ap->a_uio, ap->a_ioflag);
  788                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  789                 return error;
  790         default:
  791                 return EOPNOTSUPP;
  792         }
  793 }
  794 
  795 int
  796 ptyfs_write(void *v)
  797 {
  798         struct vop_write_args /* {
  799                 struct vnode *a_vp;
  800                 struct uio *a_uio;
  801                 int  a_ioflag;
  802                 kauth_cred_t a_cred;
  803         } */ *ap = v;
  804         struct timespec ts;
  805         struct vnode *vp = ap->a_vp;
  806         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  807         int error;
  808 
  809         ptyfs->ptyfs_flag |= PTYFS_MODIFY;
  810         getnanotime(&ts);
  811         (void)ptyfs_update(vp, &ts, &ts, 0);
  812 
  813         switch (ptyfs->ptyfs_type) {
  814         case PTYFSpts:
  815         case PTYFSptc:
  816                 VOP_UNLOCK(vp, 0);
  817                 error = cdev_write(vp->v_rdev, ap->a_uio, ap->a_ioflag);
  818                 vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
  819                 return error;
  820         default:
  821                 return EOPNOTSUPP;
  822         }
  823 }
  824 
  825 int
  826 ptyfs_ioctl(void *v)
  827 {
  828         struct vop_ioctl_args /* {
  829                 struct vnode *a_vp;
  830                 u_long a_command;
  831                 void *a_data;
  832                 int  a_fflag;
  833                 kauth_cred_t a_cred;
  834         } */ *ap = v;
  835         struct vnode *vp = ap->a_vp;
  836         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  837 
  838         switch (ptyfs->ptyfs_type) {
  839         case PTYFSpts:
  840         case PTYFSptc:
  841                 return cdev_ioctl(vp->v_rdev, ap->a_command,
  842                     ap->a_data, ap->a_fflag, curlwp);
  843         default:
  844                 return EOPNOTSUPP;
  845         }
  846 }
  847 
  848 int
  849 ptyfs_poll(void *v)
  850 {
  851         struct vop_poll_args /* {
  852                 struct vnode *a_vp;
  853                 int a_events;
  854         } */ *ap = v;
  855         struct vnode *vp = ap->a_vp;
  856         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  857 
  858         switch (ptyfs->ptyfs_type) {
  859         case PTYFSpts:
  860         case PTYFSptc:
  861                 return cdev_poll(vp->v_rdev, ap->a_events, curlwp);
  862         default:
  863                 return genfs_poll(v);
  864         }
  865 }
  866 
  867 int
  868 ptyfs_kqfilter(void *v)
  869 {
  870         struct vop_kqfilter_args /* {
  871                 struct vnode *a_vp;
  872                 struct knote *a_kn;
  873         } */ *ap = v;
  874         struct vnode *vp = ap->a_vp;
  875         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  876 
  877         switch (ptyfs->ptyfs_type) {
  878         case PTYFSpts:
  879         case PTYFSptc:
  880                 return cdev_kqfilter(vp->v_rdev, ap->a_kn);
  881         default:
  882                 return genfs_kqfilter(v);
  883         }
  884 }
  885 
  886 static int
  887 ptyfs_update(struct vnode *vp, const struct timespec *acc,
  888     const struct timespec *mod, int flags)
  889 {
  890         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  891 
  892         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  893                 return 0;
  894 
  895         PTYFS_ITIMES(ptyfs, acc, mod, NULL);
  896         return 0;
  897 }
  898 
  899 void
  900 ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc,
  901     const struct timespec *mod, const struct timespec *cre)
  902 {
  903         struct timespec now;
  904  
  905         KASSERT(ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY));
  906 
  907         getnanotime(&now);
  908         if (ptyfs->ptyfs_flag & PTYFS_ACCESS) {
  909                 if (acc == NULL)
  910                         acc = &now;
  911                 ptyfs->ptyfs_atime = *acc;
  912         }
  913         if (ptyfs->ptyfs_flag & PTYFS_MODIFY) {
  914                 if (mod == NULL)
  915                         mod = &now;
  916                 ptyfs->ptyfs_mtime = *mod;
  917         }
  918         if (ptyfs->ptyfs_flag & PTYFS_CHANGE) {
  919                 if (cre == NULL)
  920                         cre = &now;
  921                 ptyfs->ptyfs_ctime = *cre;
  922         }
  923         ptyfs->ptyfs_flag &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY);
  924 }
  925 
  926 /*
  927  * convert decimal ascii to int
  928  */
  929 static int
  930 atoi(const char *b, size_t len)
  931 {
  932         int p = 0;
  933 
  934         while (len--) {
  935                 char c = *b++;
  936                 if (c < '' || c > '9')
  937                         return -1;
  938                 p = 10 * p + (c - '');
  939         }
  940 
  941         return p;
  942 }

Cache object: fe5dc1e238552d369409d43f01a3f78b


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