1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved.
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 
  32 #include <sys/types.h>
  33 #include <sys/sysmacros.h>
  34 #include <sys/param.h>
  35 #include <sys/systm.h>
  36 #include <sys/cred.h>
  37 #include <sys/user.h>
  38 #include <sys/vnode.h>
  39 #include <sys/file.h>
  40 #include <sys/stream.h>
  41 #include <sys/strsubr.h>
  42 #include <sys/errno.h>
  43 #include <sys/debug.h>
  44 #include <sys/fs/fifonode.h>
  45 #include <sys/fcntl.h>
  46 
  47 /*
  48  * This is the loadable module wrapper.
  49  */
  50 #include <sys/modctl.h>
  51 #include <sys/syscall.h>
  52 
  53 int pipe(intptr_t fds, int);
  54 
  55 static struct sysent pipe_sysent = {
  56         2,
  57         SE_ARGC | SE_32RVAL1 | SE_NOUNLOAD,
  58         (int (*)())pipe
  59 };
  60 
  61 /*
  62  * Module linkage information for the kernel.
  63  */
  64 static struct modlsys modlsys = {
  65         &mod_syscallops, "pipe(2) syscall", &pipe_sysent
  66 };
  67 
  68 #ifdef _SYSCALL32_IMPL
  69 static struct modlsys modlsys32 = {
  70         &mod_syscallops32, "32-bit pipe(2) syscall", &pipe_sysent
  71 };
  72 #endif
  73 
  74 static struct modlinkage modlinkage = {
  75         MODREV_1,
  76         {   &modlsys,
  77 #ifdef _SYSCALL32_IMPL
  78             &modlsys32,
  79 #endif
  80             NULL
  81         }
  82 };
  83 
  84 int
  85 _init(void)
  86 {
  87         return (mod_install(&modlinkage));
  88 }
  89 
  90 int
  91 _fini(void)
  92 {
  93         return (EBUSY);
  94 }
  95 
  96 int
  97 _info(struct modinfo *modinfop)
  98 {
  99         return (mod_info(&modlinkage, modinfop));
 100 }
 101 
 102 /*
 103  * pipe(2) system call.
 104  * Create a pipe by connecting two streams together. Associate
 105  * each end of the pipe with a vnode, a file descriptor and
 106  * one of the streams.
 107  */
 108 int
 109 pipe(intptr_t arg, int flags)
 110 {
 111         vnode_t *vp1, *vp2;
 112         struct file *fp1, *fp2;
 113         int error = 0;
 114         int flag1, flag2, iflags;
 115         int fd1, fd2;
 116 
 117         /*
 118          * Validate allowed flags.
 119          */
 120         if ((flags & ~(FCLOEXEC|FNONBLOCK)) != 0) {
 121                 return (set_errno(EINVAL));
 122         }
 123         /*
 124          * Allocate and initialize two vnodes.
 125          */
 126         makepipe(&vp1, &vp2);
 127 
 128         /*
 129          * Allocate and initialize two file table entries and two
 130          * file pointers. Each file pointer is open for read and
 131          * write.
 132          */
 133         if (error = falloc(vp1, FWRITE|FREAD, &fp1, &fd1)) {
 134                 VN_RELE(vp1);
 135                 VN_RELE(vp2);
 136                 return (set_errno(error));
 137         }
 138 
 139         if (error = falloc(vp2, FWRITE|FREAD, &fp2, &fd2))
 140                 goto out2;
 141 
 142         /*
 143          * Create two stream heads and attach to each vnode.
 144          */
 145         if (error = fifo_stropen(&vp1, FWRITE|FREAD, fp1->f_cred, 0, 0))
 146                 goto out;
 147 
 148         if (error = fifo_stropen(&vp2, FWRITE|FREAD, fp2->f_cred, 0, 0)) {
 149                 (void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0,
 150                     fp1->f_cred, NULL);
 151                 goto out;
 152         }
 153 
 154         strmate(vp1, vp2);
 155 
 156         VTOF(vp1)->fn_ino = VTOF(vp2)->fn_ino = fifogetid();
 157 
 158         /*
 159          * Set the O_NONBLOCK flag if requested.
 160          */
 161         if (flags & FNONBLOCK) {
 162                 flag1 = fp1->f_flag;
 163                 flag2 = fp2->f_flag;
 164                 iflags = flags & FNONBLOCK;
 165 
 166                 if (error = VOP_SETFL(vp1, flag1, iflags, fp1->f_cred, NULL)) {
 167                         goto out_vop_close;
 168                 }
 169                 fp1->f_flag |= iflags;
 170 
 171                 if (error = VOP_SETFL(vp2, flag2, iflags, fp2->f_cred, NULL)) {
 172                         goto out_vop_close;
 173                 }
 174                 fp2->f_flag |= iflags;
 175         }
 176 
 177         /*
 178          * Return the file descriptors to the user. They now
 179          * point to two different vnodes which have different
 180          * stream heads.
 181          */
 182         if (copyout(&fd1, &((int *)arg)[0], sizeof (int)) ||
 183             copyout(&fd2, &((int *)arg)[1], sizeof (int))) {
 184                 error = EFAULT;
 185                 goto out_vop_close;
 186         }
 187 
 188         /*
 189          * Now fill in the entries that falloc reserved
 190          */
 191         mutex_exit(&fp1->f_tlock);
 192         mutex_exit(&fp2->f_tlock);
 193         setf(fd1, fp1);
 194         setf(fd2, fp2);
 195 
 196         /*
 197          * Optionally set the FCLOEXEC flag
 198          */
 199         if ((flags & FCLOEXEC) != 0) {
 200                 f_setfd(fd1, FD_CLOEXEC);
 201                 f_setfd(fd2, FD_CLOEXEC);
 202         }
 203 
 204         return (0);
 205 out_vop_close:
 206         (void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0, fp1->f_cred, NULL);
 207         (void) VOP_CLOSE(vp2, FWRITE|FREAD, 1, (offset_t)0, fp2->f_cred, NULL);
 208 out:
 209         setf(fd2, NULL);
 210         unfalloc(fp2);
 211 out2:
 212         setf(fd1, NULL);
 213         unfalloc(fp1);
 214         VN_RELE(vp1);
 215         VN_RELE(vp2);
 216         return (set_errno(error));
 217 }