/src/CMake/Utilities/cmlibuv/src/unix/pipe.c
Line | Count | Source |
1 | | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. |
2 | | * |
3 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | | * of this software and associated documentation files (the "Software"), to |
5 | | * deal in the Software without restriction, including without limitation the |
6 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
7 | | * sell copies of the Software, and to permit persons to whom the Software is |
8 | | * furnished to do so, subject to the following conditions: |
9 | | * |
10 | | * The above copyright notice and this permission notice shall be included in |
11 | | * all copies or substantial portions of the Software. |
12 | | * |
13 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
14 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
15 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
16 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
17 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
18 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
19 | | * IN THE SOFTWARE. |
20 | | */ |
21 | | |
22 | | #include "uv.h" |
23 | | #include "internal.h" |
24 | | |
25 | | #include <assert.h> |
26 | | #include <errno.h> |
27 | | #include <string.h> |
28 | | #include <sys/un.h> |
29 | | #include <unistd.h> |
30 | | #include <stdlib.h> |
31 | | |
32 | | |
33 | | /* Does the file path contain embedded nul bytes? */ |
34 | 0 | static int includes_invalid_nul(const char *s, size_t n) { |
35 | 0 | if (n == 0) |
36 | 0 | return 0; |
37 | 0 | #ifdef __linux__ |
38 | | /* Accept abstract socket namespace paths, throughout which nul bytes have |
39 | | * no special significance ("\0foo\0bar"). |
40 | | */ |
41 | 0 | if (s[0] == '\0') |
42 | 0 | return 0; |
43 | 0 | #endif |
44 | 0 | return NULL != memchr(s, '\0', n); |
45 | 0 | } |
46 | | |
47 | | |
48 | 0 | int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { |
49 | 0 | uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); |
50 | 0 | handle->shutdown_req = NULL; |
51 | 0 | handle->connect_req = NULL; |
52 | 0 | handle->pipe_fname = NULL; |
53 | 0 | handle->ipc = ipc; |
54 | 0 | return 0; |
55 | 0 | } |
56 | | |
57 | | |
58 | 0 | int uv_pipe_bind(uv_pipe_t* handle, const char* name) { |
59 | 0 | return uv_pipe_bind2(handle, name, strlen(name), 0); |
60 | 0 | } |
61 | | |
62 | | |
63 | | int uv_pipe_bind2(uv_pipe_t* handle, |
64 | | const char* name, |
65 | | size_t namelen, |
66 | 0 | unsigned int flags) { |
67 | 0 | struct sockaddr_un saddr; |
68 | 0 | char* pipe_fname = NULL; |
69 | 0 | int sockfd = -1; |
70 | 0 | int err; |
71 | 0 | socklen_t addrlen; |
72 | |
|
73 | 0 | if (flags & ~UV_PIPE_NO_TRUNCATE) |
74 | 0 | return UV_EINVAL; |
75 | | |
76 | 0 | if (name == NULL) |
77 | 0 | return UV_EINVAL; |
78 | | |
79 | | /* namelen==0 on Linux means autobind the listen socket in the abstract |
80 | | * socket namespace, see `man 7 unix` for details. |
81 | | */ |
82 | | #if !defined(__linux__) |
83 | | if (namelen == 0) |
84 | | return UV_EINVAL; |
85 | | #endif |
86 | | |
87 | 0 | if (includes_invalid_nul(name, namelen)) |
88 | 0 | return UV_EINVAL; |
89 | | |
90 | 0 | if (flags & UV_PIPE_NO_TRUNCATE) |
91 | 0 | if (namelen > sizeof(saddr.sun_path)) |
92 | 0 | return UV_EINVAL; |
93 | | |
94 | | /* Truncate long paths. Documented behavior. */ |
95 | 0 | if (namelen > sizeof(saddr.sun_path)) |
96 | 0 | namelen = sizeof(saddr.sun_path); |
97 | | |
98 | | /* Already bound? */ |
99 | 0 | if (uv__stream_fd(handle) >= 0) |
100 | 0 | return UV_EINVAL; |
101 | | |
102 | 0 | if (uv__is_closing(handle)) |
103 | 0 | return UV_EINVAL; |
104 | | |
105 | | /* Make a copy of the file path unless it is an abstract socket. |
106 | | * We unlink the file later but abstract sockets disappear |
107 | | * automatically since they're not real file system entities. |
108 | | */ |
109 | 0 | if (*name == '\0') { |
110 | 0 | addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; |
111 | 0 | } else { |
112 | 0 | pipe_fname = uv__malloc(namelen + 1); |
113 | 0 | if (pipe_fname == NULL) |
114 | 0 | return UV_ENOMEM; |
115 | 0 | memcpy(pipe_fname, name, namelen); |
116 | 0 | pipe_fname[namelen] = '\0'; |
117 | 0 | addrlen = sizeof saddr; |
118 | 0 | } |
119 | | |
120 | 0 | err = uv__socket(AF_UNIX, SOCK_STREAM, 0); |
121 | 0 | if (err < 0) |
122 | 0 | goto err_socket; |
123 | 0 | sockfd = err; |
124 | |
|
125 | 0 | memset(&saddr, 0, sizeof saddr); |
126 | 0 | memcpy(&saddr.sun_path, name, namelen); |
127 | 0 | saddr.sun_family = AF_UNIX; |
128 | |
|
129 | 0 | if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) { |
130 | 0 | err = UV__ERR(errno); |
131 | | /* Convert ENOENT to EACCES for compatibility with Windows. */ |
132 | 0 | if (err == UV_ENOENT) |
133 | 0 | err = UV_EACCES; |
134 | |
|
135 | 0 | uv__close(sockfd); |
136 | 0 | goto err_socket; |
137 | 0 | } |
138 | | |
139 | | /* Success. */ |
140 | 0 | handle->flags |= UV_HANDLE_BOUND; |
141 | 0 | handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */ |
142 | 0 | handle->io_watcher.fd = sockfd; |
143 | 0 | return 0; |
144 | | |
145 | 0 | err_socket: |
146 | 0 | uv__free(pipe_fname); |
147 | 0 | return err; |
148 | 0 | } |
149 | | |
150 | | |
151 | 0 | int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { |
152 | 0 | if (uv__stream_fd(handle) == -1) |
153 | 0 | return UV_EINVAL; |
154 | | |
155 | 0 | if (handle->ipc) |
156 | 0 | return UV_EINVAL; |
157 | | |
158 | | #if defined(__MVS__) || defined(__PASE__) |
159 | | /* On zOS, backlog=0 has undefined behaviour */ |
160 | | /* On IBMi PASE, backlog=0 leads to "Connection refused" error */ |
161 | | if (backlog == 0) |
162 | | backlog = 1; |
163 | | else if (backlog < 0) |
164 | | backlog = SOMAXCONN; |
165 | | #endif |
166 | | |
167 | 0 | if (listen(uv__stream_fd(handle), backlog)) |
168 | 0 | return UV__ERR(errno); |
169 | | |
170 | 0 | handle->connection_cb = cb; |
171 | 0 | uv__io_cb_set(&handle->io_watcher, UV__SERVER_IO); |
172 | 0 | return uv__io_start(handle->loop, &handle->io_watcher, POLLIN); |
173 | 0 | } |
174 | | |
175 | | |
176 | 0 | void uv__pipe_close(uv_pipe_t* handle) { |
177 | 0 | if (handle->pipe_fname) { |
178 | | /* |
179 | | * Unlink the file system entity before closing the file descriptor. |
180 | | * Doing it the other way around introduces a race where our process |
181 | | * unlinks a socket with the same name that's just been created by |
182 | | * another thread or process. |
183 | | */ |
184 | 0 | unlink(handle->pipe_fname); |
185 | 0 | uv__free((void*)handle->pipe_fname); |
186 | 0 | handle->pipe_fname = NULL; |
187 | 0 | } |
188 | |
|
189 | 0 | uv__stream_close((uv_stream_t*)handle); |
190 | 0 | } |
191 | | |
192 | | |
193 | 0 | int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { |
194 | 0 | int flags; |
195 | 0 | int mode; |
196 | 0 | int err; |
197 | 0 | flags = 0; |
198 | |
|
199 | 0 | if (uv__fd_exists(handle->loop, fd)) |
200 | 0 | return UV_EEXIST; |
201 | | |
202 | 0 | do |
203 | 0 | mode = fcntl(fd, F_GETFL); |
204 | 0 | while (mode == -1 && errno == EINTR); |
205 | |
|
206 | 0 | if (mode == -1) |
207 | 0 | return UV__ERR(errno); /* according to docs, must be EBADF */ |
208 | | |
209 | 0 | err = uv__nonblock(fd, 1); |
210 | 0 | if (err) |
211 | 0 | return err; |
212 | | |
213 | | #if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) |
214 | | err = uv__stream_try_select((uv_stream_t*) handle, &fd); |
215 | | if (err) |
216 | | return err; |
217 | | #endif /* defined(__APPLE__) */ |
218 | | |
219 | 0 | mode &= O_ACCMODE; |
220 | 0 | if (mode != O_WRONLY) |
221 | 0 | flags |= UV_HANDLE_READABLE; |
222 | 0 | if (mode != O_RDONLY) |
223 | 0 | flags |= UV_HANDLE_WRITABLE; |
224 | |
|
225 | 0 | return uv__stream_open((uv_stream_t*)handle, fd, flags); |
226 | 0 | } |
227 | | |
228 | | |
229 | | void uv_pipe_connect(uv_connect_t* req, |
230 | | uv_pipe_t* handle, |
231 | | const char* name, |
232 | 0 | uv_connect_cb cb) { |
233 | 0 | int err; |
234 | |
|
235 | 0 | err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); |
236 | |
|
237 | 0 | if (err) { |
238 | 0 | handle->delayed_error = err; |
239 | 0 | handle->connect_req = req; |
240 | |
|
241 | 0 | uv__req_init(handle->loop, req, UV_CONNECT); |
242 | 0 | req->handle = (uv_stream_t*) handle; |
243 | 0 | req->cb = cb; |
244 | 0 | uv__queue_init(&req->queue); |
245 | | |
246 | | /* Force callback to run on next tick in case of error. */ |
247 | 0 | uv__io_feed(handle->loop, &handle->io_watcher); |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | |
252 | | int uv_pipe_connect2(uv_connect_t* req, |
253 | | uv_pipe_t* handle, |
254 | | const char* name, |
255 | | size_t namelen, |
256 | | unsigned int flags, |
257 | 0 | uv_connect_cb cb) { |
258 | 0 | struct sockaddr_un saddr; |
259 | 0 | int new_sock; |
260 | 0 | int err; |
261 | 0 | int r; |
262 | 0 | socklen_t addrlen; |
263 | |
|
264 | 0 | if (flags & ~UV_PIPE_NO_TRUNCATE) |
265 | 0 | return UV_EINVAL; |
266 | | |
267 | 0 | if (name == NULL) |
268 | 0 | return UV_EINVAL; |
269 | | |
270 | 0 | if (namelen == 0) |
271 | 0 | return UV_EINVAL; |
272 | | |
273 | 0 | if (includes_invalid_nul(name, namelen)) |
274 | 0 | return UV_EINVAL; |
275 | | |
276 | 0 | if (flags & UV_PIPE_NO_TRUNCATE) |
277 | 0 | if (namelen > sizeof(saddr.sun_path)) |
278 | 0 | return UV_EINVAL; |
279 | | |
280 | | /* Truncate long paths. Documented behavior. */ |
281 | 0 | if (namelen > sizeof(saddr.sun_path)) |
282 | 0 | namelen = sizeof(saddr.sun_path); |
283 | |
|
284 | 0 | new_sock = (uv__stream_fd(handle) == -1); |
285 | |
|
286 | 0 | if (new_sock) { |
287 | 0 | err = uv__socket(AF_UNIX, SOCK_STREAM, 0); |
288 | 0 | if (err < 0) |
289 | 0 | goto out; |
290 | 0 | handle->io_watcher.fd = err; |
291 | 0 | } |
292 | | |
293 | 0 | memset(&saddr, 0, sizeof saddr); |
294 | 0 | memcpy(&saddr.sun_path, name, namelen); |
295 | 0 | saddr.sun_family = AF_UNIX; |
296 | |
|
297 | 0 | if (*name == '\0') |
298 | 0 | addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; |
299 | 0 | else |
300 | 0 | addrlen = sizeof saddr; |
301 | |
|
302 | 0 | do { |
303 | 0 | r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen); |
304 | 0 | } |
305 | 0 | while (r == -1 && errno == EINTR); |
306 | |
|
307 | 0 | if (r == -1 && errno != EINPROGRESS) { |
308 | 0 | err = UV__ERR(errno); |
309 | | #if defined(__CYGWIN__) || defined(__MSYS__) |
310 | | /* EBADF is supposed to mean that the socket fd is bad, but |
311 | | Cygwin reports EBADF instead of ENOTSOCK when the file is |
312 | | not a socket. We do not expect to see a bad fd here |
313 | | (e.g. due to new_sock), so translate the error. */ |
314 | | if (err == UV_EBADF) |
315 | | err = UV_ENOTSOCK; |
316 | | #endif |
317 | 0 | goto out; |
318 | 0 | } |
319 | | |
320 | 0 | err = 0; |
321 | 0 | if (new_sock) { |
322 | 0 | err = uv__stream_open((uv_stream_t*)handle, |
323 | 0 | uv__stream_fd(handle), |
324 | 0 | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); |
325 | 0 | } |
326 | |
|
327 | 0 | if (err == 0) |
328 | 0 | uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); |
329 | |
|
330 | 0 | out: |
331 | 0 | handle->delayed_error = err; |
332 | 0 | handle->connect_req = req; |
333 | |
|
334 | 0 | uv__req_init(handle->loop, req, UV_CONNECT); |
335 | 0 | req->handle = (uv_stream_t*) handle; |
336 | 0 | req->cb = cb; |
337 | 0 | uv__queue_init(&req->queue); |
338 | | |
339 | | /* Force callback to run on next tick in case of error. */ |
340 | 0 | if (err) |
341 | 0 | uv__io_feed(handle->loop, &handle->io_watcher); |
342 | |
|
343 | 0 | return 0; |
344 | 0 | } |
345 | | |
346 | | |
347 | | static int uv__pipe_getsockpeername(const uv_pipe_t* handle, |
348 | | uv__peersockfunc func, |
349 | | char* buffer, |
350 | 0 | size_t* size) { |
351 | 0 | #if defined(__linux__) |
352 | 0 | static const int is_linux = 1; |
353 | | #else |
354 | | static const int is_linux = 0; |
355 | | #endif |
356 | 0 | struct sockaddr_un sa; |
357 | 0 | socklen_t addrlen; |
358 | 0 | size_t slop; |
359 | 0 | char* p; |
360 | 0 | int err; |
361 | |
|
362 | 0 | if (buffer == NULL || size == NULL || *size == 0) |
363 | 0 | return UV_EINVAL; |
364 | | |
365 | 0 | addrlen = sizeof(sa); |
366 | 0 | memset(&sa, 0, addrlen); |
367 | 0 | err = uv__getsockpeername((const uv_handle_t*) handle, |
368 | 0 | func, |
369 | 0 | (struct sockaddr*) &sa, |
370 | 0 | (int*) &addrlen); |
371 | 0 | if (err < 0) { |
372 | 0 | *size = 0; |
373 | 0 | return err; |
374 | 0 | } |
375 | | |
376 | 0 | slop = 1; |
377 | 0 | if (is_linux && sa.sun_path[0] == '\0') { |
378 | | /* Linux abstract namespace. Not zero-terminated. */ |
379 | 0 | slop = 0; |
380 | 0 | addrlen -= offsetof(struct sockaddr_un, sun_path); |
381 | 0 | } else { |
382 | 0 | p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path)); |
383 | 0 | if (p == NULL) |
384 | 0 | p = ARRAY_END(sa.sun_path); |
385 | 0 | addrlen = p - sa.sun_path; |
386 | 0 | } |
387 | |
|
388 | 0 | if ((size_t)addrlen + slop > *size) { |
389 | 0 | *size = addrlen + slop; |
390 | 0 | return UV_ENOBUFS; |
391 | 0 | } |
392 | | |
393 | 0 | memcpy(buffer, sa.sun_path, addrlen); |
394 | 0 | *size = addrlen; |
395 | | |
396 | | /* only null-terminate if it's not an abstract socket */ |
397 | 0 | if (buffer[0] != '\0') |
398 | 0 | buffer[addrlen] = '\0'; |
399 | |
|
400 | 0 | return 0; |
401 | 0 | } |
402 | | |
403 | | |
404 | 0 | int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { |
405 | 0 | return uv__pipe_getsockpeername(handle, getsockname, buffer, size); |
406 | 0 | } |
407 | | |
408 | | |
409 | 0 | int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { |
410 | 0 | return uv__pipe_getsockpeername(handle, getpeername, buffer, size); |
411 | 0 | } |
412 | | |
413 | | |
414 | 0 | void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { |
415 | 0 | } |
416 | | |
417 | | |
418 | 0 | int uv_pipe_pending_count(uv_pipe_t* handle) { |
419 | 0 | uv__stream_queued_fds_t* queued_fds; |
420 | |
|
421 | 0 | if (!handle->ipc) |
422 | 0 | return 0; |
423 | | |
424 | 0 | if (handle->accepted_fd == -1) |
425 | 0 | return 0; |
426 | | |
427 | 0 | if (handle->queued_fds == NULL) |
428 | 0 | return 1; |
429 | | |
430 | 0 | queued_fds = handle->queued_fds; |
431 | 0 | return queued_fds->offset + 1; |
432 | 0 | } |
433 | | |
434 | | |
435 | 0 | uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { |
436 | 0 | if (!handle->ipc) |
437 | 0 | return UV_UNKNOWN_HANDLE; |
438 | | |
439 | 0 | if (handle->accepted_fd == -1) |
440 | 0 | return UV_UNKNOWN_HANDLE; |
441 | 0 | else |
442 | 0 | return uv_guess_handle(handle->accepted_fd); |
443 | 0 | } |
444 | | |
445 | | |
446 | 0 | int uv_pipe_chmod(uv_pipe_t* handle, int mode) { |
447 | 0 | char name_buffer[1 + UV__PATH_MAX]; |
448 | 0 | int desired_mode; |
449 | 0 | size_t name_len; |
450 | 0 | const char* name; |
451 | 0 | int fd; |
452 | 0 | int r; |
453 | |
|
454 | 0 | if (handle == NULL) |
455 | 0 | return UV_EBADF; |
456 | | |
457 | 0 | fd = uv__stream_fd(handle); |
458 | 0 | if (fd == -1) |
459 | 0 | return UV_EBADF; |
460 | | |
461 | 0 | if (mode != UV_READABLE && |
462 | 0 | mode != UV_WRITABLE && |
463 | 0 | mode != (UV_WRITABLE | UV_READABLE)) |
464 | 0 | return UV_EINVAL; |
465 | | |
466 | 0 | desired_mode = 0; |
467 | 0 | if (mode & UV_READABLE) |
468 | 0 | desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; |
469 | 0 | if (mode & UV_WRITABLE) |
470 | 0 | desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; |
471 | | |
472 | | /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */ |
473 | 0 | if (fchmod(fd, desired_mode)) |
474 | 0 | if (errno != EINVAL && errno != EOPNOTSUPP) |
475 | 0 | return UV__ERR(errno); |
476 | | |
477 | | /* Fall back to chmod. */ |
478 | 0 | name_len = sizeof(name_buffer); |
479 | 0 | r = uv_pipe_getsockname(handle, name_buffer, &name_len); |
480 | 0 | if (r != 0) |
481 | 0 | return r; |
482 | 0 | name = name_buffer; |
483 | | |
484 | | /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */ |
485 | 0 | if (name_len == 0 && handle->pipe_fname != NULL) |
486 | 0 | name = handle->pipe_fname; |
487 | |
|
488 | 0 | if (chmod(name, desired_mode)) |
489 | 0 | return UV__ERR(errno); |
490 | | |
491 | 0 | return 0; |
492 | 0 | } |
493 | | |
494 | | |
495 | 0 | int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { |
496 | 0 | uv_os_fd_t temp[2]; |
497 | 0 | int err; |
498 | 0 | #if defined(__linux__) || \ |
499 | 0 | defined(__FreeBSD__) || \ |
500 | 0 | defined(__OpenBSD__) || \ |
501 | 0 | defined(__DragonFly__) || \ |
502 | 0 | defined(__NetBSD__) || \ |
503 | 0 | defined(__illumos__) || \ |
504 | 0 | (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4) |
505 | 0 | int flags = O_CLOEXEC; |
506 | |
|
507 | 0 | if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) |
508 | 0 | flags |= UV_FS_O_NONBLOCK; |
509 | |
|
510 | 0 | if (pipe2(temp, flags)) |
511 | 0 | return UV__ERR(errno); |
512 | | |
513 | 0 | if (flags & UV_FS_O_NONBLOCK) { |
514 | 0 | fds[0] = temp[0]; |
515 | 0 | fds[1] = temp[1]; |
516 | 0 | return 0; |
517 | 0 | } |
518 | | #else |
519 | | if (pipe(temp)) |
520 | | return UV__ERR(errno); |
521 | | |
522 | | if ((err = uv__cloexec(temp[0], 1))) |
523 | | goto fail; |
524 | | |
525 | | if ((err = uv__cloexec(temp[1], 1))) |
526 | | goto fail; |
527 | | #endif |
528 | | |
529 | 0 | if (read_flags & UV_NONBLOCK_PIPE) |
530 | 0 | if ((err = uv__nonblock(temp[0], 1))) |
531 | 0 | goto fail; |
532 | | |
533 | 0 | if (write_flags & UV_NONBLOCK_PIPE) |
534 | 0 | if ((err = uv__nonblock(temp[1], 1))) |
535 | 0 | goto fail; |
536 | | |
537 | 0 | fds[0] = temp[0]; |
538 | 0 | fds[1] = temp[1]; |
539 | 0 | return 0; |
540 | | |
541 | 0 | fail: |
542 | 0 | uv__close(temp[0]); |
543 | 0 | uv__close(temp[1]); |
544 | 0 | return err; |
545 | 0 | } |
546 | | |
547 | | |
548 | 0 | int uv__make_pipe(int fds[2], int flags) { |
549 | 0 | return uv_pipe(fds, |
550 | 0 | flags & UV_NONBLOCK_PIPE, |
551 | 0 | flags & UV_NONBLOCK_PIPE); |
552 | 0 | } |