]>
Commit | Line | Data |
---|---|---|
f02f1f14 | 1 | /* pipe.cc: pipe for Cygwin. |
1fd5e000 | 2 | |
e1ab5e68 | 3 | Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
61522196 | 4 | 2008, 2009, 2010, 2011, 2012, 2013 Hat, Inc. |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
45586380 CF |
12 | /* FIXME: Should this really be fhandler_pipe.cc? */ |
13 | ||
4c8d72de | 14 | #include "winsup.h" |
6644c628 | 15 | #include <stdlib.h> |
49f7ea16 | 16 | #include <sys/socket.h> |
9e2baf8d | 17 | #include "cygerrno.h" |
6b91b8d5 | 18 | #include "security.h" |
47063f00 | 19 | #include "path.h" |
7ac61736 | 20 | #include "fhandler.h" |
bccd5e0d | 21 | #include "dtable.h" |
0381fec6 | 22 | #include "cygheap.h" |
35f879a6 | 23 | #include "pinfo.h" |
526b0fbc | 24 | #include "shared_info.h" |
35f879a6 | 25 | |
7ac61736 | 26 | fhandler_pipe::fhandler_pipe () |
2aeef065 | 27 | : fhandler_base_overlapped (), popen_pid (0) |
5e733918 | 28 | { |
779ece3c | 29 | max_atomic_write = DEFAULT_PIPEBUFSIZE; |
b040009e | 30 | need_fork_fixup (true); |
5e733918 CF |
31 | } |
32 | ||
3c4f2024 | 33 | int |
8528ecbd | 34 | fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode) |
634a4140 | 35 | { |
824d8518 CF |
36 | /* FIXME: Have to clean this up someday |
37 | FIXME: Do we have to check for both !get_win32_name() and | |
38 | !*get_win32_name()? */ | |
39 | if ((!get_win32_name () || !*get_win32_name ()) && get_name ()) | |
634a4140 | 40 | { |
824d8518 CF |
41 | char *d; |
42 | const char *s; | |
634a4140 | 43 | char *hold_normalized_name = (char *) alloca (strlen (get_name ()) + 1); |
824d8518 | 44 | for (s = get_name (), d = hold_normalized_name; *s; s++, d++) |
634a4140 CF |
45 | if (*s == '/') |
46 | *d = '\\'; | |
47 | else | |
48 | *d = *s; | |
49 | *d = '\0'; | |
50 | set_name (hold_normalized_name); | |
51 | } | |
52 | ||
53 | bool opened_properly = a & FILE_CREATE_PIPE_INSTANCE; | |
54 | a &= ~FILE_CREATE_PIPE_INSTANCE; | |
8528ecbd | 55 | fhandler_base::init (f, a, mode); |
e70fdfb9 | 56 | close_on_exec (mode & O_CLOEXEC); |
5151c80c CF |
57 | if (opened_properly) |
58 | setup_overlapped (); | |
59 | else | |
60 | destroy_overlapped (); | |
3c4f2024 | 61 | return 1; |
634a4140 CF |
62 | } |
63 | ||
7d880770 CV |
64 | extern "C" int sscanf (const char *, const char *, ...); |
65 | ||
e8309efd CV |
66 | int |
67 | fhandler_pipe::open (int flags, mode_t mode) | |
68 | { | |
8ae1d98d | 69 | HANDLE proc, pipe_hdl, nio_hdl = NULL; |
7d880770 CV |
70 | fhandler_pipe *fh = NULL; |
71 | size_t size; | |
72 | int pid, rwflags = (flags & O_ACCMODE); | |
f62412f2 | 73 | bool inh; |
7d880770 | 74 | |
61522196 CV |
75 | sscanf (get_name (), "/proc/%d/fd/pipe:[%lu]", |
76 | &pid, (unsigned long *) &pipe_hdl); | |
7d880770 CV |
77 | if (pid == myself->pid) |
78 | { | |
16bbf0cc | 79 | cygheap_fdenum cfd (true); |
7d880770 CV |
80 | while (cfd.next () >= 0) |
81 | { | |
82 | if (cfd->get_handle () != pipe_hdl) | |
83 | continue; | |
84 | if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ)) | |
85 | || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE))) | |
01a94cf8 | 86 | { |
7d880770 CV |
87 | set_errno (EACCES); |
88 | return 0; | |
01a94cf8 | 89 | } |
23771fa1 | 90 | cfd->copyto (this); |
f5a51f91 CV |
91 | set_io_handle (NULL); |
92 | pc.reset_conv_handle (); | |
23771fa1 | 93 | if (!cfd->dup (this, flags)) |
7d880770 CV |
94 | return 1; |
95 | return 0; | |
01a94cf8 | 96 | } |
7d880770 CV |
97 | set_errno (ENOENT); |
98 | return 0; | |
99 | } | |
100 | ||
101 | pinfo p (pid); | |
102 | if (!p) | |
103 | { | |
104 | set_errno (ESRCH); | |
105 | return 0; | |
106 | } | |
107 | if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) | |
108 | { | |
109 | __seterrno (); | |
110 | return 0; | |
111 | } | |
112 | if (!(fh = p->pipe_fhandler (pipe_hdl, size)) || !size) | |
113 | { | |
114 | set_errno (ENOENT); | |
115 | goto out; | |
116 | } | |
117 | /* Too bad, but Windows only allows the same access mode when dup'ing | |
118 | the pipe. */ | |
119 | if ((rwflags == O_RDONLY && !(fh->get_access () & GENERIC_READ)) | |
120 | || (rwflags == O_WRONLY && !(fh->get_access () & GENERIC_WRITE))) | |
121 | { | |
122 | set_errno (EACCES); | |
123 | goto out; | |
124 | } | |
e70fdfb9 | 125 | inh = !(flags & O_CLOEXEC); |
f16706de | 126 | if (!DuplicateHandle (proc, pipe_hdl, GetCurrentProcess (), &nio_hdl, |
8ae1d98d | 127 | 0, inh, DUPLICATE_SAME_ACCESS)) |
7d880770 CV |
128 | { |
129 | __seterrno (); | |
130 | goto out; | |
131 | } | |
7d880770 | 132 | init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY); |
0d8efc42 | 133 | cfree (fh); |
7d880770 CV |
134 | CloseHandle (proc); |
135 | return 1; | |
01a94cf8 | 136 | out: |
7d880770 CV |
137 | if (nio_hdl) |
138 | CloseHandle (nio_hdl); | |
139 | if (fh) | |
140 | free (fh); | |
141 | if (proc) | |
142 | CloseHandle (proc); | |
e8309efd CV |
143 | return 0; |
144 | } | |
145 | ||
61522196 CV |
146 | off_t |
147 | fhandler_pipe::lseek (off_t offset, int whence) | |
5e733918 | 148 | { |
61522196 | 149 | debug_printf ("(%D, %d)", offset, whence); |
5e733918 CF |
150 | set_errno (ESPIPE); |
151 | return -1; | |
152 | } | |
153 | ||
7636b585 | 154 | int |
61522196 | 155 | fhandler_pipe::fadvise (off_t offset, off_t length, int advice) |
7636b585 CV |
156 | { |
157 | set_errno (ESPIPE); | |
158 | return -1; | |
159 | } | |
160 | ||
161 | int | |
61522196 | 162 | fhandler_pipe::ftruncate (off_t length, bool allow_truncate) |
7636b585 CV |
163 | { |
164 | set_errno (allow_truncate ? EINVAL : ESPIPE); | |
165 | return -1; | |
166 | } | |
167 | ||
b040009e CF |
168 | char * |
169 | fhandler_pipe::get_proc_fd_name (char *buf) | |
4f27e288 | 170 | { |
61522196 | 171 | __small_sprintf (buf, "pipe:[%lu]", get_handle ()); |
4f27e288 CV |
172 | return buf; |
173 | } | |
174 | ||
5e733918 | 175 | int |
23771fa1 | 176 | fhandler_pipe::dup (fhandler_base *child, int flags) |
5e733918 | 177 | { |
f7239090 | 178 | fhandler_pipe *ftp = (fhandler_pipe *) child; |
c16548b2 | 179 | ftp->set_popen_pid (0); |
f7239090 | 180 | |
d9c0e3ec | 181 | int res; |
23771fa1 | 182 | if (get_handle () && fhandler_base_overlapped::dup (child, flags)) |
d9c0e3ec | 183 | res = -1; |
b040009e | 184 | else |
d9c0e3ec | 185 | res = 0; |
35f879a6 | 186 | |
f7239090 CF |
187 | debug_printf ("res %d", res); |
188 | return res; | |
5e733918 CF |
189 | } |
190 | ||
1ffe3e67 CF |
191 | #define PIPE_INTRO "\\\\.\\pipe\\cygwin-" |
192 | ||
6644c628 CF |
193 | /* Create a pipe, and return handles to the read and write ends, |
194 | just like CreatePipe, but ensure that the write end permits | |
195 | FILE_READ_ATTRIBUTES access, on later versions of win32 where | |
196 | this is supported. This access is needed by NtQueryInformationFile, | |
197 | which is used to implement select and nonblocking writes. | |
fb201f92 | 198 | Note that the return value is either 0 or GetLastError, |
6644c628 | 199 | unlike CreatePipe, which returns a bool for success or failure. */ |
9f65451e CF |
200 | DWORD |
201 | fhandler_pipe::create (LPSECURITY_ATTRIBUTES sa_ptr, PHANDLE r, PHANDLE w, | |
202 | DWORD psize, const char *name, DWORD open_mode) | |
6644c628 CF |
203 | { |
204 | /* Default to error. */ | |
cd071d13 CF |
205 | if (r) |
206 | *r = NULL; | |
207 | if (w) | |
208 | *w = NULL; | |
6644c628 CF |
209 | |
210 | /* Ensure that there is enough pipe buffer space for atomic writes. */ | |
9f65451e | 211 | if (!psize) |
779ece3c | 212 | psize = DEFAULT_PIPEBUFSIZE; |
6644c628 | 213 | |
526b0fbc | 214 | char pipename[MAX_PATH]; |
28c8ae66 CF |
215 | size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", |
216 | &cygheap->installation_key); | |
61522196 CV |
217 | DWORD pipe_mode = PIPE_READMODE_BYTE |
218 | | (wincap.has_pipe_reject_remote_clients () | |
219 | ? PIPE_REJECT_REMOTE_CLIENTS : 0); | |
ea17849f CF |
220 | if (!name) |
221 | pipe_mode |= pipe_byte ? PIPE_TYPE_BYTE : PIPE_TYPE_MESSAGE; | |
222 | else | |
348b56b5 | 223 | pipe_mode |= PIPE_TYPE_MESSAGE; |
526b0fbc | 224 | |
348b56b5 | 225 | if (!name || (open_mode & PIPE_ADD_PID)) |
28c8ae66 CF |
226 | { |
227 | len += __small_sprintf (pipename + len, "%u-", GetCurrentProcessId ()); | |
228 | open_mode &= ~PIPE_ADD_PID; | |
229 | } | |
230 | ||
348b56b5 CF |
231 | if (name) |
232 | len += __small_sprintf (pipename + len, "%s", name); | |
233 | ||
61522196 | 234 | open_mode |= PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; |
6644c628 CF |
235 | |
236 | /* Retry CreateNamedPipe as long as the pipe name is in use. | |
237 | Retrying will probably never be necessary, but we want | |
238 | to be as robust as possible. */ | |
cd071d13 CF |
239 | DWORD err = 0; |
240 | while (r && !*r) | |
6644c628 | 241 | { |
fb201f92 | 242 | static volatile ULONG pipe_unique_id; |
1ffe3e67 | 243 | if (!name) |
ea17849f CF |
244 | __small_sprintf (pipename + len, "pipe-%p", |
245 | InterlockedIncrement ((LONG *) &pipe_unique_id)); | |
6644c628 | 246 | |
61522196 | 247 | debug_printf ("name %s, size %u, mode %s", pipename, psize, |
ea17849f CF |
248 | (pipe_mode & PIPE_TYPE_MESSAGE) |
249 | ? "PIPE_TYPE_MESSAGE" : "PIPE_TYPE_BYTE"); | |
6644c628 CF |
250 | |
251 | /* Use CreateNamedPipe instead of CreatePipe, because the latter | |
d584454c CF |
252 | returns a write handle that does not permit FILE_READ_ATTRIBUTES |
253 | access, on versions of win32 earlier than WinXP SP2. | |
254 | CreatePipe also stupidly creates a full duplex pipe, which is | |
255 | a waste, since only a single direction is actually used. | |
256 | It's important to only allow a single instance, to ensure that | |
257 | the pipe was not created earlier by some other process, even if | |
61522196 | 258 | the pid has been reused. |
31d2bedc CF |
259 | |
260 | Note that the write side of the pipe is opened as PIPE_TYPE_MESSAGE. | |
261 | This *seems* to more closely mimic Linux pipe behavior and is | |
262 | definitely required for pty handling since fhandler_pty_master | |
263 | writes to the pipe in chunks, terminated by newline when CANON mode | |
264 | is specified. */ | |
ea17849f | 265 | *r = CreateNamedPipe (pipename, open_mode, pipe_mode, 1, psize, |
fb201f92 | 266 | psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); |
6644c628 | 267 | |
cd071d13 | 268 | if (*r != INVALID_HANDLE_VALUE) |
d584454c | 269 | { |
cd071d13 CF |
270 | debug_printf ("pipe read handle %p", *r); |
271 | err = 0; | |
d584454c CF |
272 | break; |
273 | } | |
6644c628 | 274 | |
1ffe3e67 | 275 | err = GetLastError (); |
6644c628 | 276 | switch (err) |
d584454c CF |
277 | { |
278 | case ERROR_PIPE_BUSY: | |
279 | /* The pipe is already open with compatible parameters. | |
280 | Pick a new name and retry. */ | |
cd071d13 | 281 | debug_printf ("pipe busy", !name ? ", retrying" : ""); |
5f38ec46 | 282 | if (!name) |
cd071d13 | 283 | *r = NULL; |
fb201f92 | 284 | break; |
d584454c CF |
285 | case ERROR_ACCESS_DENIED: |
286 | /* The pipe is already open with incompatible parameters. | |
287 | Pick a new name and retry. */ | |
cd071d13 | 288 | debug_printf ("pipe access denied%s", !name ? ", retrying" : ""); |
5f38ec46 | 289 | if (!name) |
cd071d13 | 290 | *r = NULL; |
fb201f92 CF |
291 | break; |
292 | default: | |
d9c0e3ec CF |
293 | { |
294 | err = GetLastError (); | |
cd071d13 | 295 | debug_printf ("failed, %E"); |
d9c0e3ec | 296 | } |
d584454c | 297 | } |
6644c628 | 298 | } |
1ffe3e67 CF |
299 | |
300 | if (err) | |
6644c628 | 301 | { |
cd071d13 | 302 | *r = NULL; |
6644c628 CF |
303 | return err; |
304 | } | |
305 | ||
cd071d13 CF |
306 | if (!w) |
307 | debug_printf ("pipe write handle NULL"); | |
308 | else | |
309 | { | |
310 | debug_printf ("CreateFile: name %s", pipename); | |
311 | ||
312 | /* Open the named pipe for writing. | |
313 | Be sure to permit FILE_READ_ATTRIBUTES access. */ | |
314 | DWORD access = GENERIC_WRITE | FILE_READ_ATTRIBUTES; | |
315 | if ((open_mode & PIPE_ACCESS_DUPLEX) == PIPE_ACCESS_DUPLEX) | |
316 | access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; | |
317 | *w = CreateFile (pipename, access, 0, sa_ptr, OPEN_EXISTING, | |
318 | open_mode & FILE_FLAG_OVERLAPPED, 0); | |
319 | ||
320 | if (!*w || *w == INVALID_HANDLE_VALUE) | |
321 | { | |
322 | /* Failure. */ | |
323 | DWORD err = GetLastError (); | |
1ad58ee7 | 324 | debug_printf ("CreateFile failed, r %p, %E", r); |
cd071d13 CF |
325 | if (r) |
326 | CloseHandle (*r); | |
327 | *w = NULL; | |
328 | return err; | |
329 | } | |
330 | ||
331 | debug_printf ("pipe write handle %p", *w); | |
332 | } | |
6644c628 CF |
333 | |
334 | /* Success. */ | |
fb201f92 | 335 | return 0; |
6644c628 CF |
336 | } |
337 | ||
35f879a6 | 338 | int |
be1cabba | 339 | fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) |
1fd5e000 | 340 | { |
1fd5e000 | 341 | HANDLE r, w; |
e70fdfb9 | 342 | SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); |
9e1fd6bc | 343 | int res = -1; |
1fd5e000 | 344 | |
9f65451e | 345 | int ret = create (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED); |
fb201f92 | 346 | if (ret) |
9e1fd6bc CV |
347 | __seterrno_from_win_error (ret); |
348 | else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) | |
8528ecbd | 349 | { |
9e1fd6bc CV |
350 | CloseHandle (r); |
351 | CloseHandle (w); | |
352 | } | |
353 | else if ((fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev)) == NULL) | |
354 | { | |
355 | delete fhs[0]; | |
356 | CloseHandle (w); | |
8528ecbd | 357 | } |
7ac61736 | 358 | else |
1fd5e000 | 359 | { |
8528ecbd CF |
360 | mode |= mode & O_TEXT ?: O_BINARY; |
361 | fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode); | |
362 | fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode); | |
7ac61736 | 363 | res = 0; |
1fd5e000 CF |
364 | } |
365 | ||
61522196 | 366 | debug_printf ("%R = pipe([%p, %p], %d, %y)", res, fhs[0], fhs[1], psize, mode); |
57bf29e8 | 367 | return res; |
1fd5e000 CF |
368 | } |
369 | ||
49f7ea16 CF |
370 | int |
371 | fhandler_pipe::ioctl (unsigned int cmd, void *p) | |
372 | { | |
373 | int n; | |
374 | ||
375 | switch (cmd) | |
376 | { | |
377 | case FIONREAD: | |
378 | if (get_device () == FH_PIPEW) | |
379 | { | |
380 | set_errno (EINVAL); | |
381 | return -1; | |
382 | } | |
383 | if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, (DWORD *) &n, NULL)) | |
384 | { | |
385 | __seterrno (); | |
386 | return -1; | |
387 | } | |
388 | break; | |
389 | default: | |
390 | return fhandler_base::ioctl (cmd, p); | |
391 | break; | |
392 | } | |
393 | *(int *) p = n; | |
394 | return 0; | |
395 | } | |
396 | ||
3323df7e CV |
397 | int __stdcall |
398 | fhandler_pipe::fstatvfs (struct statvfs *sfs) | |
399 | { | |
400 | set_errno (EBADF); | |
401 | return -1; | |
402 | } | |
403 | ||
6e75c72b | 404 | static int __reg3 |
b11797ad | 405 | pipe_worker (int filedes[2], unsigned int psize, int mode) |
1fd5e000 | 406 | { |
7ac61736 | 407 | fhandler_pipe *fhs[2]; |
56c387b1 CV |
408 | int res = fhandler_pipe::create (fhs, psize, mode); |
409 | if (!res) | |
7ac61736 CF |
410 | { |
411 | cygheap_fdnew fdin; | |
412 | cygheap_fdnew fdout (fdin, false); | |
2aeef065 CF |
413 | char buf[sizeof ("/dev/fd/pipe:[2147483647]")]; |
414 | __small_sprintf (buf, "/dev/fd/pipe:[%d]", (int) fdin); | |
415 | fhs[0]->pc.set_normalized_path (buf); | |
416 | __small_sprintf (buf, "pipe:[%d]", (int) fdout); | |
417 | fhs[1]->pc.set_normalized_path (buf); | |
7ac61736 CF |
418 | fdin = fhs[0]; |
419 | fdout = fhs[1]; | |
420 | filedes[0] = fdin; | |
421 | filedes[1] = fdout; | |
1b23b30b | 422 | } |
b11797ad CF |
423 | return res; |
424 | } | |
425 | ||
426 | extern "C" int | |
427 | _pipe (int filedes[2], unsigned int psize, int mode) | |
428 | { | |
429 | int res = pipe_worker (filedes, psize, mode); | |
430 | int read, write; | |
431 | if (res != 0) | |
432 | read = write = -1; | |
433 | else | |
434 | { | |
435 | read = filedes[0]; | |
436 | write = filedes[1]; | |
7ac61736 | 437 | } |
61522196 | 438 | syscall_printf ("%R = _pipe([%d, %d], %u, %y)", res, read, write, psize, mode); |
7ac61736 | 439 | return res; |
1fd5e000 CF |
440 | } |
441 | ||
442 | extern "C" int | |
56c387b1 | 443 | pipe (int filedes[2]) |
1fd5e000 | 444 | { |
b11797ad CF |
445 | int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, O_BINARY); |
446 | int read, write; | |
447 | if (res != 0) | |
448 | read = write = -1; | |
449 | else | |
450 | { | |
451 | read = filedes[0]; | |
452 | write = filedes[1]; | |
453 | } | |
454 | syscall_printf ("%R = pipe([%d, %d])", res, read, write); | |
455 | return res; | |
1fd5e000 | 456 | } |
e70fdfb9 CV |
457 | |
458 | extern "C" int | |
459 | pipe2 (int filedes[2], int mode) | |
460 | { | |
b11797ad CF |
461 | int res = pipe_worker (filedes, DEFAULT_PIPEBUFSIZE, mode); |
462 | int read, write; | |
463 | if (res != 0) | |
464 | read = write = -1; | |
465 | else | |
466 | { | |
467 | read = filedes[0]; | |
468 | write = filedes[1]; | |
469 | } | |
61522196 | 470 | syscall_printf ("%R = pipe2([%d, %d], %y)", res, read, write, mode); |
b11797ad | 471 | return res; |
e70fdfb9 | 472 | } |