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.69 2022/08/05 10:36:02 riastradh 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.69 2022/08/05 10:36:02 riastradh 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 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 int     ptyfs_ioctl     (void *);
  125 int     ptyfs_poll      (void *);
  126 int     ptyfs_kqfilter  (void *);
  127 int     ptyfs_readdir   (void *);
  128 int     ptyfs_reclaim   (void *);
  129 int     ptyfs_inactive  (void *);
  130 int     ptyfs_print     (void *);
  131 int     ptyfs_pathconf  (void *);
  132 int     ptyfs_advlock   (void *);
  133 
  134 static int ptyfs_update(struct vnode *, const struct timespec *,
  135     const struct timespec *, int);
  136 static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
  137     struct lwp *);
  138 static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
  139 static int atoi(const char *, size_t);
  140 
  141 /*
  142  * ptyfs vnode operations.
  143  */
  144 int (**ptyfs_vnodeop_p)(void *);
  145 const struct vnodeopv_entry_desc ptyfs_vnodeop_entries[] = {
  146         { &vop_default_desc, vn_default_error },
  147         { &vop_parsepath_desc, genfs_parsepath },       /* parsepath */
  148         { &vop_lookup_desc, ptyfs_lookup },             /* lookup */
  149         { &vop_create_desc, genfs_eopnotsupp },         /* create */
  150         { &vop_mknod_desc, genfs_eopnotsupp },          /* mknod */
  151         { &vop_open_desc, ptyfs_open },                 /* open */
  152         { &vop_close_desc, ptyfs_close },               /* close */
  153         { &vop_access_desc, ptyfs_access },             /* access */
  154         { &vop_accessx_desc, genfs_accessx },           /* accessx */
  155         { &vop_getattr_desc, ptyfs_getattr },           /* getattr */
  156         { &vop_setattr_desc, ptyfs_setattr },           /* setattr */
  157         { &vop_read_desc, ptyfs_read },                 /* read */
  158         { &vop_write_desc, ptyfs_write },               /* write */
  159         { &vop_fallocate_desc, genfs_eopnotsupp },      /* fallocate */
  160         { &vop_fdiscard_desc, genfs_eopnotsupp },       /* fdiscard */
  161         { &vop_ioctl_desc, ptyfs_ioctl },               /* ioctl */
  162         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
  163         { &vop_poll_desc, ptyfs_poll },                 /* poll */
  164         { &vop_kqfilter_desc, ptyfs_kqfilter },         /* kqfilter */
  165         { &vop_revoke_desc, genfs_revoke },             /* revoke */
  166         { &vop_mmap_desc, genfs_eopnotsupp },           /* mmap */
  167         { &vop_fsync_desc, genfs_nullop },              /* fsync */
  168         { &vop_seek_desc, genfs_nullop },               /* seek */
  169         { &vop_remove_desc, genfs_eopnotsupp },         /* remove */
  170         { &vop_link_desc, genfs_eopnotsupp },           /* link */
  171         { &vop_rename_desc, genfs_eopnotsupp },         /* rename */
  172         { &vop_mkdir_desc, genfs_eopnotsupp },          /* mkdir */
  173         { &vop_rmdir_desc, genfs_eopnotsupp },          /* rmdir */
  174         { &vop_symlink_desc, genfs_eopnotsupp },        /* symlink */
  175         { &vop_readdir_desc, ptyfs_readdir },           /* readdir */
  176         { &vop_readlink_desc, genfs_eopnotsupp },       /* readlink */
  177         { &vop_abortop_desc, genfs_abortop },           /* abortop */
  178         { &vop_inactive_desc, ptyfs_inactive },         /* inactive */
  179         { &vop_reclaim_desc, ptyfs_reclaim },           /* reclaim */
  180         { &vop_lock_desc, genfs_lock },                 /* lock */
  181         { &vop_unlock_desc, genfs_unlock },             /* unlock */
  182         { &vop_bmap_desc, genfs_eopnotsupp },           /* bmap */
  183         { &vop_strategy_desc, genfs_badop },            /* strategy */
  184         { &vop_print_desc, ptyfs_print },               /* print */
  185         { &vop_islocked_desc, genfs_islocked },         /* islocked */
  186         { &vop_pathconf_desc, ptyfs_pathconf },         /* pathconf */
  187         { &vop_advlock_desc, ptyfs_advlock },           /* advlock */
  188         { &vop_bwrite_desc, genfs_eopnotsupp },         /* bwrite */
  189         { &vop_putpages_desc, genfs_null_putpages },    /* putpages */
  190         { NULL, NULL }
  191 };
  192 const struct vnodeopv_desc ptyfs_vnodeop_opv_desc =
  193         { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries };
  194 
  195 /*
  196  * free any private data and remove the node
  197  * from any private lists.
  198  */
  199 int
  200 ptyfs_reclaim(void *v)
  201 {
  202         struct vop_reclaim_v2_args /* {
  203                 struct vnode *a_vp;
  204         } */ *ap = v;
  205         struct vnode *vp = ap->a_vp;
  206 
  207         VOP_UNLOCK(vp);
  208 
  209         vp->v_data = NULL;
  210         return 0;
  211 }
  212 
  213 int
  214 ptyfs_inactive(void *v)
  215 {
  216         struct vop_inactive_v2_args /* {
  217                 struct vnode *a_vp;
  218                 bool *a_recycle;
  219         } */ *ap = v;
  220         struct vnode *vp = ap->a_vp;
  221         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  222 
  223         if (ptyfs->ptyfs_type == PTYFSptc)
  224                 ptyfs_clr_active(vp->v_mount, ptyfs->ptyfs_pty);
  225 
  226         return 0;
  227 }
  228 
  229 /*
  230  * Return POSIX pathconf information applicable to special devices.
  231  */
  232 int
  233 ptyfs_pathconf(void *v)
  234 {
  235         struct vop_pathconf_args /* {
  236                 struct vnode *a_vp;
  237                 int a_name;
  238                 register_t *a_retval;
  239         } */ *ap = v;
  240 
  241         switch (ap->a_name) {
  242         case _PC_LINK_MAX:
  243                 *ap->a_retval = LINK_MAX;
  244                 return 0;
  245         case _PC_MAX_CANON:
  246                 *ap->a_retval = MAX_CANON;
  247                 return 0;
  248         case _PC_MAX_INPUT:
  249                 *ap->a_retval = MAX_INPUT;
  250                 return 0;
  251         case _PC_PIPE_BUF:
  252                 *ap->a_retval = PIPE_BUF;
  253                 return 0;
  254         case _PC_CHOWN_RESTRICTED:
  255                 *ap->a_retval = 1;
  256                 return 0;
  257         case _PC_VDISABLE:
  258                 *ap->a_retval = _POSIX_VDISABLE;
  259                 return 0;
  260         case _PC_SYNC_IO:
  261                 *ap->a_retval = 1;
  262                 return 0;
  263         default:
  264                 return genfs_pathconf(ap);
  265         }
  266 }
  267 
  268 /*
  269  * _print is used for debugging.
  270  * just print a readable description
  271  * of (vp).
  272  */
  273 int
  274 ptyfs_print(void *v)
  275 {
  276         struct vop_print_args /* {
  277                 struct vnode *a_vp;
  278         } */ *ap = v;
  279         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  280 
  281         printf("tag VT_PTYFS, type %d, pty %d\n",
  282             ptyfs->ptyfs_type, ptyfs->ptyfs_pty);
  283         return 0;
  284 }
  285 
  286 /*
  287  * support advisory locking on pty nodes
  288  */
  289 int
  290 ptyfs_advlock(void *v)
  291 {
  292         struct vop_print_args /* {
  293                 struct vnode *a_vp;
  294         } */ *ap = v;
  295         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  296 
  297         switch (ptyfs->ptyfs_type) {
  298         case PTYFSpts:
  299         case PTYFSptc:
  300                 return spec_advlock(v);
  301         default:
  302                 return EOPNOTSUPP;
  303         }
  304 }
  305 
  306 /*
  307  * Invent attributes for ptyfsnode (vp) and store
  308  * them in (vap).
  309  * Directories lengths are returned as zero since
  310  * any real length would require the genuine size
  311  * to be computed, and nothing cares anyway.
  312  *
  313  * this is relatively minimal for ptyfs.
  314  */
  315 int
  316 ptyfs_getattr(void *v)
  317 {
  318         struct vop_getattr_args /* {
  319                 struct vnode *a_vp;
  320                 struct vattr *a_vap;
  321                 kauth_cred_t a_cred;
  322         } */ *ap = v;
  323         struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
  324         struct vattr *vap = ap->a_vap;
  325 
  326         PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  327 
  328         /* start by zeroing out the attributes */
  329         vattr_null(vap);
  330 
  331         /* next do all the common fields */
  332         vap->va_type = ap->a_vp->v_type;
  333         vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
  334         vap->va_fileid = ptyfs->ptyfs_fileno;
  335         vap->va_gen = 0;
  336         vap->va_flags = 0;
  337         vap->va_blocksize = PAGE_SIZE;
  338 
  339         vap->va_atime = ptyfs->ptyfs_atime;
  340         vap->va_mtime = ptyfs->ptyfs_mtime;
  341         vap->va_ctime = ptyfs->ptyfs_ctime;
  342         vap->va_birthtime = ptyfs->ptyfs_birthtime;
  343         vap->va_mode = ptyfs->ptyfs_mode;
  344         vap->va_flags = ptyfs->ptyfs_flags;
  345         vap->va_uid = ptyfs->ptyfs_uid;
  346         vap->va_gid = ptyfs->ptyfs_gid;
  347 
  348         switch (ptyfs->ptyfs_type) {
  349         case PTYFSpts:
  350         case PTYFSptc:
  351                 if (pty_isfree(ptyfs->ptyfs_pty, 1))
  352                         return ENOENT;
  353                 vap->va_bytes = vap->va_size = 0;
  354                 vap->va_rdev = ap->a_vp->v_rdev;
  355                 vap->va_nlink = 1;
  356                 break;
  357         case PTYFSroot:
  358                 vap->va_rdev = 0;
  359                 vap->va_bytes = vap->va_size = DEV_BSIZE;
  360                 vap->va_nlink = 2;
  361                 break;
  362         default:
  363                 return EOPNOTSUPP;
  364         }
  365 
  366         return 0;
  367 }
  368 
  369 /*ARGSUSED*/
  370 int
  371 ptyfs_setattr(void *v)
  372 {
  373         struct vop_setattr_args /* {
  374                 struct vnodeop_desc *a_desc;
  375                 struct vnode *a_vp;
  376                 struct vattr *a_vap;
  377                 kauth_cred_t a_cred;
  378         } */ *ap = v;
  379         struct vnode *vp = ap->a_vp;
  380         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  381         struct vattr *vap = ap->a_vap;
  382         kauth_cred_t cred = ap->a_cred;
  383         struct lwp *l = curlwp;
  384         int error;
  385         kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
  386         bool changing_sysflags = false;
  387 
  388         if (vap->va_size != VNOVALSIZE) {
  389                 switch (ptyfs->ptyfs_type) {
  390                 case PTYFSroot:
  391                         return EISDIR;
  392                 case PTYFSpts:
  393                 case PTYFSptc:
  394                         break;
  395                 default:
  396                         return EINVAL;
  397                 }
  398         }
  399 
  400         if (vap->va_flags != VNOVALFLAGS) {
  401                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  402                         return EROFS;
  403 
  404                 /* Immutable and append-only flags are not supported on ptyfs. */
  405                 if (vap->va_flags & (IMMUTABLE | APPEND))
  406                         return EINVAL;
  407 
  408                 /* Snapshot flag cannot be set or cleared */
  409                 if ((vap->va_flags & SF_SNAPSHOT) != (ptyfs->ptyfs_flags & SF_SNAPSHOT))
  410                         return EPERM;
  411 
  412                 if ((ptyfs->ptyfs_flags & SF_SETTABLE) != (vap->va_flags & SF_SETTABLE)) {
  413                         changing_sysflags = true;
  414                         action |= KAUTH_VNODE_WRITE_SYSFLAGS;
  415                 }
  416 
  417                 error = kauth_authorize_vnode(cred, action, vp, NULL,
  418                     genfs_can_chflags(vp, cred, ptyfs->ptyfs_uid,
  419                     changing_sysflags));
  420                 if (error)
  421                         return error;
  422 
  423                 if (changing_sysflags) {
  424                         ptyfs->ptyfs_flags = vap->va_flags;
  425                 } else {
  426                         ptyfs->ptyfs_flags &= SF_SETTABLE;
  427                         ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
  428                 }
  429                 ptyfs->ptyfs_status |= PTYFS_CHANGE;
  430         }
  431 
  432         /*
  433          * Go through the fields and update iff not VNOVAL.
  434          */
  435         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  436                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  437                         return EROFS;
  438                 error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
  439                 if (error)
  440                         return error;
  441         }
  442 
  443         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
  444             vap->va_birthtime.tv_sec != VNOVAL) {
  445                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  446                         return EROFS;
  447                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
  448                         return EPERM;
  449                 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
  450                     NULL, genfs_can_chtimes(vp, cred, ptyfs->ptyfs_uid,
  451                     vap->va_vaflags));
  452                 if (error)
  453                         return (error);
  454                 if (vap->va_atime.tv_sec != VNOVAL)
  455                         if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
  456                                 ptyfs->ptyfs_status |= PTYFS_ACCESS;
  457                 if (vap->va_mtime.tv_sec != VNOVAL) {
  458                         ptyfs->ptyfs_status |= PTYFS_CHANGE | PTYFS_MODIFY;
  459                         if (vp->v_mount->mnt_flag & MNT_RELATIME)
  460                                 ptyfs->ptyfs_status |= PTYFS_ACCESS;
  461                 }
  462                 if (vap->va_birthtime.tv_sec != VNOVAL)
  463                         ptyfs->ptyfs_birthtime = vap->va_birthtime;
  464                 ptyfs->ptyfs_status |= PTYFS_CHANGE;
  465                 error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
  466                 if (error)
  467                         return error;
  468         }
  469         if (vap->va_mode != (mode_t)VNOVAL) {
  470                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  471                         return EROFS;
  472                 if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
  473                     (vap->va_mode &
  474                     (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH)))
  475                         return EPERM;
  476                 error = ptyfs_chmod(vp, vap->va_mode, cred, l);
  477                 if (error)
  478                         return error;
  479         }
  480         return 0;
  481 }
  482 
  483 /*
  484  * Change the mode on a file.
  485  * Inode must be locked before calling.
  486  */
  487 static int
  488 ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l)
  489 {
  490         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  491         int error;
  492 
  493         error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
  494             NULL, genfs_can_chmod(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid,
  495             mode));
  496         if (error)
  497                 return (error);
  498 
  499         ptyfs->ptyfs_mode &= ~ALLPERMS;
  500         ptyfs->ptyfs_mode |= (mode & ALLPERMS);
  501         return 0;
  502 }
  503 
  504 /*
  505  * Perform chown operation on inode ip;
  506  * inode must be locked prior to call.
  507  */
  508 static int
  509 ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
  510     struct lwp *l)
  511 {
  512         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  513         int error;
  514 
  515         if (uid == (uid_t)VNOVAL)
  516                 uid = ptyfs->ptyfs_uid;
  517         if (gid == (gid_t)VNOVAL)
  518                 gid = ptyfs->ptyfs_gid;
  519 
  520         error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
  521             NULL, genfs_can_chown(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid,
  522             uid, gid));
  523         if (error)
  524                 return (error);
  525 
  526         ptyfs->ptyfs_gid = gid;
  527         ptyfs->ptyfs_uid = uid;
  528         return 0;
  529 }
  530 
  531 /*
  532  * implement access checking.
  533  *
  534  * actually, the check for super-user is slightly
  535  * broken since it will allow read access to write-only
  536  * objects.  this doesn't cause any particular trouble
  537  * but does mean that the i/o entry points need to check
  538  * that the operation really does make sense.
  539  */
  540 int
  541 ptyfs_access(void *v)
  542 {
  543         struct vop_access_args /* {
  544                 struct vnode *a_vp;
  545                 accmode_t a_accmode;
  546                 kauth_cred_t a_cred;
  547         } */ *ap = v;
  548         struct vattr va;
  549         int error;
  550 
  551         if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
  552                 return error;
  553 
  554         return kauth_authorize_vnode(ap->a_cred,
  555             KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode),
  556             ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred, va.va_uid,
  557             va.va_gid, va.va_mode, NULL, ap->a_accmode));
  558 }
  559 
  560 /*
  561  * lookup.  this is incredibly complicated in the
  562  * general case, however for most pseudo-filesystems
  563  * very little needs to be done.
  564  *
  565  * Locking isn't hard here, just poorly documented.
  566  *
  567  * If we're looking up ".", just vref the parent & return it.
  568  *
  569  * If we're looking up "..", unlock the parent, and lock "..". If everything
  570  * went ok, try to re-lock the parent. We do this to prevent lock races.
  571  *
  572  * For anything else, get the needed node.
  573  *
  574  * We try to exit with the parent locked in error cases.
  575  */
  576 int
  577 ptyfs_lookup(void *v)
  578 {
  579         struct vop_lookup_v2_args /* {
  580                 struct vnode * a_dvp;
  581                 struct vnode ** a_vpp;
  582                 struct componentname * a_cnp;
  583         } */ *ap = v;
  584         struct componentname *cnp = ap->a_cnp;
  585         struct vnode **vpp = ap->a_vpp;
  586         struct vnode *dvp = ap->a_dvp;
  587         const char *pname = cnp->cn_nameptr;
  588         struct ptyfsnode *ptyfs;
  589         int pty, error;
  590 
  591         *vpp = NULL;
  592 
  593         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
  594                 return EROFS;
  595 
  596         if (cnp->cn_namelen == 1 && *pname == '.') {
  597                 *vpp = dvp;
  598                 vref(dvp);
  599                 return 0;
  600         }
  601 
  602         ptyfs = VTOPTYFS(dvp);
  603         switch (ptyfs->ptyfs_type) {
  604         case PTYFSroot:
  605                 /*
  606                  * Shouldn't get here with .. in the root node.
  607                  */
  608                 if (cnp->cn_flags & ISDOTDOT)
  609                         return EIO;
  610 
  611                 pty = atoi(pname, cnp->cn_namelen);
  612                 if (pty < 0 || ptyfs_next_active(dvp->v_mount, pty) != pty)
  613                         break;
  614                 error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty);
  615                 if (error)
  616                         return error;
  617                 if (ptyfs_next_active(dvp->v_mount, pty) != pty) {
  618                         vrele(*vpp);
  619                         *vpp = NULL;
  620                         return ENOENT;
  621                 }
  622                 return 0;
  623 
  624         default:
  625                 return ENOTDIR;
  626         }
  627 
  628         return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
  629 }
  630 
  631 /*
  632  * readdir returns directory entries from ptyfsnode (vp).
  633  *
  634  * the strategy here with ptyfs is to generate a single
  635  * directory entry at a time (struct dirent) and then
  636  * copy that out to userland using uiomove.  a more efficient
  637  * though more complex implementation, would try to minimize
  638  * the number of calls to uiomove().  for ptyfs, this is
  639  * hardly worth the added code complexity.
  640  *
  641  * this should just be done through read()
  642  */
  643 int
  644 ptyfs_readdir(void *v)
  645 {
  646         struct vop_readdir_args /* {
  647                 struct vnode *a_vp;
  648                 struct uio *a_uio;
  649                 kauth_cred_t a_cred;
  650                 int *a_eofflag;
  651                 off_t **a_cookies;
  652                 int *a_ncookies;
  653         } */ *ap = v;
  654         struct uio *uio = ap->a_uio;
  655         struct dirent *dp;
  656         struct ptyfsnode *ptyfs;
  657         off_t i;
  658         int error;
  659         off_t *cookies = NULL;
  660         int ncookies;
  661         struct vnode *vp;
  662         int n, nc = 0;
  663 
  664         vp = ap->a_vp;
  665         ptyfs = VTOPTYFS(vp);
  666 
  667         if (uio->uio_resid < UIO_MX)
  668                 return EINVAL;
  669         if (uio->uio_offset < 0)
  670                 return EINVAL;
  671 
  672         dp = malloc(sizeof(struct dirent), M_PTYFSTMP, M_WAITOK | M_ZERO);
  673 
  674         error = 0;
  675         i = uio->uio_offset;
  676         dp->d_reclen = UIO_MX;
  677         ncookies = uio->uio_resid / UIO_MX;
  678 
  679         if (ptyfs->ptyfs_type != PTYFSroot) {
  680                 error = ENOTDIR;
  681                 goto out;
  682         }
  683 
  684         if (i >= npty)
  685                 goto out;
  686 
  687         if (ap->a_ncookies) {
  688                 ncookies = uimin(ncookies, (npty + 2 - i));
  689                 cookies = malloc(ncookies * sizeof (off_t),
  690                     M_TEMP, M_WAITOK);
  691                 *ap->a_cookies = cookies;
  692         }
  693 
  694         for (; i < 2 && uio->uio_resid >= UIO_MX; i++) {
  695                 /* `.' and/or `..' */
  696                 dp->d_fileno = PTYFS_FILENO(PTYFSroot, 0);
  697                 dp->d_namlen = i + 1;
  698                 (void)memcpy(dp->d_name, "..", dp->d_namlen);
  699                 dp->d_name[i + 1] = '\0';
  700                 dp->d_type = DT_DIR;
  701                 if ((error = uiomove(dp, UIO_MX, uio)) != 0)
  702                         goto out;
  703                 if (cookies)
  704                         *cookies++ = i + 1;
  705                 nc++;
  706         }
  707         while (uio->uio_resid >= UIO_MX) {
  708                 /* check for used ptys */
  709                 n = ptyfs_next_active(vp->v_mount, i - 2);
  710                 if (n < 0)
  711                         break;
  712                 dp->d_fileno = PTYFS_FILENO(PTYFSpts, n);
  713                 dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name),
  714                     "%lld", (long long)(n));
  715                 dp->d_type = DT_CHR;
  716                 if ((error = uiomove(dp, UIO_MX, uio)) != 0)
  717                         goto out;
  718                 i = n + 3;
  719                 if (cookies)
  720                         *cookies++ = i;
  721                 nc++;
  722         }
  723 
  724 out:
  725         /* not pertinent in error cases */
  726         ncookies = nc;
  727 
  728         if (ap->a_ncookies) {
  729                 if (error) {
  730                         if (cookies)
  731                                 free(*ap->a_cookies, M_TEMP);
  732                         *ap->a_ncookies = 0;
  733                         *ap->a_cookies = NULL;
  734                 } else
  735                         *ap->a_ncookies = ncookies;
  736         }
  737         uio->uio_offset = i;
  738         free(dp, M_PTYFSTMP);
  739         return error;
  740 }
  741 
  742 int
  743 ptyfs_open(void *v)
  744 {
  745         struct vop_open_args /* {
  746                 struct vnode *a_vp;
  747                 int  a_mode;
  748                 kauth_cred_t a_cred;
  749         } */ *ap = v;
  750         struct vnode *vp = ap->a_vp;
  751         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  752 
  753         switch (ptyfs->ptyfs_type) {
  754         case PTYFSpts:
  755         case PTYFSptc:
  756                 return spec_open(v);
  757         case PTYFSroot:
  758                 return 0;
  759         default:
  760                 return EINVAL;
  761         }
  762 }
  763 
  764 int
  765 ptyfs_close(void *v)
  766 {
  767         struct vop_close_args /* {
  768                 struct vnode *a_vp;
  769                 int  a_fflag;
  770                 kauth_cred_t a_cred;
  771         } */ *ap = v;
  772         struct vnode *vp = ap->a_vp;
  773         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  774 
  775         mutex_enter(vp->v_interlock);
  776         if (vrefcnt(vp) > 1)
  777                 PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
  778         mutex_exit(vp->v_interlock);
  779 
  780         switch (ptyfs->ptyfs_type) {
  781         case PTYFSpts:
  782         case PTYFSptc:
  783                 return spec_close(v);
  784         case PTYFSroot:
  785                 return 0;
  786         default:
  787                 return EINVAL;
  788         }
  789 }
  790 
  791 int
  792 ptyfs_read(void *v)
  793 {
  794         struct vop_read_args /* {
  795                 struct vnode *a_vp;
  796                 struct uio *a_uio;
  797                 int  a_ioflag;
  798                 kauth_cred_t a_cred;
  799         } */ *ap = v;
  800         struct timespec ts;
  801         struct vnode *vp = ap->a_vp;
  802         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  803         int error;
  804 
  805         if (vp->v_type == VDIR)
  806                 return EISDIR;
  807 
  808         ptyfs->ptyfs_status |= PTYFS_ACCESS;
  809         /* hardclock() resolution is good enough for ptyfs */
  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);
  817                 error = cdev_read(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_write(void *v)
  827 {
  828         struct vop_write_args /* {
  829                 struct vnode *a_vp;
  830                 struct uio *a_uio;
  831                 int  a_ioflag;
  832                 kauth_cred_t a_cred;
  833         } */ *ap = v;
  834         struct timespec ts;
  835         struct vnode *vp = ap->a_vp;
  836         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  837         int error;
  838 
  839         ptyfs->ptyfs_status |= PTYFS_MODIFY;
  840         getnanotime(&ts);
  841         (void)ptyfs_update(vp, &ts, &ts, 0);
  842 
  843         switch (ptyfs->ptyfs_type) {
  844         case PTYFSpts:
  845         case PTYFSptc:
  846                 VOP_UNLOCK(vp);
  847                 error = cdev_write(vp->v_rdev, ap->a_uio, 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         } */ *ap = v;
  865         struct vnode *vp = ap->a_vp;
  866         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  867 
  868         switch (ptyfs->ptyfs_type) {
  869         case PTYFSpts:
  870         case PTYFSptc:
  871                 return cdev_ioctl(vp->v_rdev, ap->a_command,
  872                     ap->a_data, ap->a_fflag, curlwp);
  873         default:
  874                 return EOPNOTSUPP;
  875         }
  876 }
  877 
  878 int
  879 ptyfs_poll(void *v)
  880 {
  881         struct vop_poll_args /* {
  882                 struct vnode *a_vp;
  883                 int a_events;
  884         } */ *ap = v;
  885         struct vnode *vp = ap->a_vp;
  886         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  887 
  888         switch (ptyfs->ptyfs_type) {
  889         case PTYFSpts:
  890         case PTYFSptc:
  891                 return cdev_poll(vp->v_rdev, ap->a_events, curlwp);
  892         default:
  893                 return genfs_poll(v);
  894         }
  895 }
  896 
  897 int
  898 ptyfs_kqfilter(void *v)
  899 {
  900         struct vop_kqfilter_args /* {
  901                 struct vnode *a_vp;
  902                 struct knote *a_kn;
  903         } */ *ap = v;
  904         struct vnode *vp = ap->a_vp;
  905         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  906 
  907         switch (ptyfs->ptyfs_type) {
  908         case PTYFSpts:
  909         case PTYFSptc:
  910                 return cdev_kqfilter(vp->v_rdev, ap->a_kn);
  911         default:
  912                 return genfs_kqfilter(v);
  913         }
  914 }
  915 
  916 static int
  917 ptyfs_update(struct vnode *vp, const struct timespec *acc,
  918     const struct timespec *mod, int flags)
  919 {
  920         struct ptyfsnode *ptyfs = VTOPTYFS(vp);
  921 
  922         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  923                 return 0;
  924 
  925         PTYFS_ITIMES(ptyfs, acc, mod, NULL);
  926         return 0;
  927 }
  928 
  929 void
  930 ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc,
  931     const struct timespec *mod, const struct timespec *cre)
  932 {
  933         struct timespec now;
  934  
  935         KASSERT(ptyfs->ptyfs_status & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY));
  936 
  937         getnanotime(&now);
  938         if (ptyfs->ptyfs_status & PTYFS_ACCESS) {
  939                 if (acc == NULL)
  940                         acc = &now;
  941                 ptyfs->ptyfs_atime = *acc;
  942         }
  943         if (ptyfs->ptyfs_status & PTYFS_MODIFY) {
  944                 if (mod == NULL)
  945                         mod = &now;
  946                 ptyfs->ptyfs_mtime = *mod;
  947         }
  948         if (ptyfs->ptyfs_status & PTYFS_CHANGE) {
  949                 if (cre == NULL)
  950                         cre = &now;
  951                 ptyfs->ptyfs_ctime = *cre;
  952         }
  953         ptyfs->ptyfs_status &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY);
  954 }
  955 
  956 /*
  957  * convert decimal ascii to int
  958  */
  959 static int
  960 atoi(const char *b, size_t len)
  961 {
  962         int p = 0;
  963 
  964         while (len--) {
  965                 char c = *b++;
  966                 if (c < '' || c > '9')
  967                         return -1;
  968                 p = 10 * p + (c - '');
  969         }
  970 
  971         return p;
  972 }

Cache object: acf703d51806265dc4fa39f3d688bbd7


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