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 int
  84 _init(void)
  85 {
  86         return (mod_install(&modlinkage));
  87 }
  88 
  89 int
  90 _fini(void)
  91 {
  92         return (EBUSY);
  93 }
  94 
  95 int
  96 _info(struct modinfo *modinfop)
  97 {
  98         return (mod_info(&modlinkage, modinfop));
  99 }
 100 
 101 /*
 102  * pipe(2) system call.
 103  * Create a pipe by connecting two streams together. Associate
 104  * each end of the pipe with a vnode, a file descriptor and
 105  * one of the streams.
 106  */
 107 int
 108 pipe(intptr_t arg, int flags)
 109 {
 110         vnode_t *vp1, *vp2;
 111         struct file *fp1, *fp2;
 112         int error = 0;
 113         int flag1, flag2, iflags;
 114         int fd1, fd2;
 115 
 116         /*
 117          * Validate allowed flags.
 118          */
 119         if ((flags & ~(FCLOEXEC|FNONBLOCK)) != 0) {
 120                 return (set_errno(EINVAL));
 121         }
 122         /*
 123          * Allocate and initialize two vnodes.
 124          */
 125         makepipe(&vp1, &vp2);
 126 
 127         /*
 128          * Allocate and initialize two file table entries and two
 129          * file pointers. Each file pointer is open for read and
 130          * write.
 131          */
 132         if (error = falloc(vp1, FWRITE|FREAD, &fp1, &fd1)) {
 133                 VN_RELE(vp1);
 134                 VN_RELE(vp2);
 135                 return (set_errno(error));
 136         }
 137 
 138         if (error = falloc(vp2, FWRITE|FREAD, &fp2, &fd2))
 139                 goto out2;
 140 
 141         /*
 142          * Create two stream heads and attach to each vnode.
 143          */
 144         if (error = fifo_stropen(&vp1, FWRITE|FREAD, fp1->f_cred, 0, 0))
 145                 goto out;
 146 
 147         if (error = fifo_stropen(&vp2, FWRITE|FREAD, fp2->f_cred, 0, 0)) {
 148                 (void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0,
 149                     fp1->f_cred, NULL);
 150                 goto out;
 151         }
 152 
 153         strmate(vp1, vp2);
 154 
 155         VTOF(vp1)->fn_ino = VTOF(vp2)->fn_ino = fifogetid();
 156 
 157         /*
 158          * Set the O_NONBLOCK flag if requested.
 159          */
 160         if (flags & FNONBLOCK) {
 161                 flag1 = fp1->f_flag;
 162                 flag2 = fp2->f_flag;
 163                 iflags = flags & FNONBLOCK;
 164 
 165                 if (error = VOP_SETFL(vp1, flag1, iflags, fp1->f_cred, NULL)) {
 166                         goto out_vop_close;
 167                 }
 168                 fp1->f_flag |= iflags;
 169 
 170                 if (error = VOP_SETFL(vp2, flag2, iflags, fp2->f_cred, NULL)) {
 171                         goto out_vop_close;
 172                 }
 173                 fp2->f_flag |= iflags;
 174         }
 175 
 176         /*
 177          * Return the file descriptors to the user. They now
 178          * point to two different vnodes which have different
 179          * stream heads.
 180          */
 181         if (copyout(&fd1, &((int *)arg)[0], sizeof (int)) ||
 182             copyout(&fd2, &((int *)arg)[1], sizeof (int))) {
 183                 error = EFAULT;
 184                 goto out_vop_close;
 185         }
 186 
 187         /*
 188          * Now fill in the entries that falloc reserved
 189          */
 190         mutex_exit(&fp1->f_tlock);
 191         mutex_exit(&fp2->f_tlock);
 192         setf(fd1, fp1);
 193         setf(fd2, fp2);
 194 
 195         /*
 196          * Optionally set the FCLOEXEC flag
 197          */
 198         if ((flags & FCLOEXEC) != 0) {
 199                 f_setfd(fd1, FD_CLOEXEC);
 200                 f_setfd(fd2, FD_CLOEXEC);
 201         }
 202 
 203         return (0);
 204 out_vop_close:
 205         (void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0, fp1->f_cred, NULL);
 206         (void) VOP_CLOSE(vp2, FWRITE|FREAD, 1, (offset_t)0, fp2->f_cred, NULL);
 207 out:
 208         setf(fd2, NULL);
 209         unfalloc(fp2);
 210 out2:
 211         setf(fd1, NULL);
 212         unfalloc(fp1);
 213         VN_RELE(vp1);
 214         VN_RELE(vp2);
 215         return (set_errno(error));
 216 }