xref: /illumos-gate/usr/src/uts/common/syscall/pipe.c (revision eb00b1c8a31c2253a353644606388dff5b0e0275)
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 }
217