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 }