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

Cache object: 748cdda9d85fe3c3e373b1d1f62c9d96


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