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
_init(void)84 _init(void)
85 {
86 return (mod_install(&modlinkage));
87 }
88
89 int
_fini(void)90 _fini(void)
91 {
92 return (EBUSY);
93 }
94
95 int
_info(struct modinfo * modinfop)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
pipe(intptr_t arg,int flags)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 }
217