]>
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, |
e70fdfb9 | 4 | 2008, 2009, 2010 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 () |
9a8597c1 | 27 | : fhandler_base (), popen_pid (0), overlapped (NULL) |
5e733918 | 28 | { |
b040009e | 29 | need_fork_fixup (true); |
1ae0cd13 | 30 | uninterruptible_io (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); |
9a8597c1 | 57 | setup_overlapped (opened_properly); |
3c4f2024 | 58 | return 1; |
634a4140 CF |
59 | } |
60 | ||
7d880770 CV |
61 | extern "C" int sscanf (const char *, const char *, ...); |
62 | ||
e8309efd CV |
63 | int |
64 | fhandler_pipe::open (int flags, mode_t mode) | |
65 | { | |
8ae1d98d | 66 | HANDLE proc, pipe_hdl, nio_hdl = NULL; |
7d880770 CV |
67 | fhandler_pipe *fh = NULL; |
68 | size_t size; | |
69 | int pid, rwflags = (flags & O_ACCMODE); | |
f62412f2 | 70 | bool inh; |
7d880770 | 71 | |
7d880770 CV |
72 | sscanf (get_name (), "/proc/%d/fd/pipe:[%d]", &pid, (int *) &pipe_hdl); |
73 | if (pid == myself->pid) | |
74 | { | |
16bbf0cc | 75 | cygheap_fdenum cfd (true); |
7d880770 CV |
76 | while (cfd.next () >= 0) |
77 | { | |
78 | if (cfd->get_handle () != pipe_hdl) | |
79 | continue; | |
80 | if ((rwflags == O_RDONLY && !(cfd->get_access () & GENERIC_READ)) | |
81 | || (rwflags == O_WRONLY && !(cfd->get_access () & GENERIC_WRITE))) | |
01a94cf8 | 82 | { |
7d880770 CV |
83 | set_errno (EACCES); |
84 | return 0; | |
01a94cf8 | 85 | } |
dcb091ca | 86 | if (!cfd->dup (this)) |
7d880770 CV |
87 | return 1; |
88 | return 0; | |
01a94cf8 | 89 | } |
7d880770 CV |
90 | set_errno (ENOENT); |
91 | return 0; | |
92 | } | |
93 | ||
94 | pinfo p (pid); | |
95 | if (!p) | |
96 | { | |
97 | set_errno (ESRCH); | |
98 | return 0; | |
99 | } | |
100 | if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) | |
101 | { | |
102 | __seterrno (); | |
103 | return 0; | |
104 | } | |
105 | if (!(fh = p->pipe_fhandler (pipe_hdl, size)) || !size) | |
106 | { | |
107 | set_errno (ENOENT); | |
108 | goto out; | |
109 | } | |
110 | /* Too bad, but Windows only allows the same access mode when dup'ing | |
111 | the pipe. */ | |
112 | if ((rwflags == O_RDONLY && !(fh->get_access () & GENERIC_READ)) | |
113 | || (rwflags == O_WRONLY && !(fh->get_access () & GENERIC_WRITE))) | |
114 | { | |
115 | set_errno (EACCES); | |
116 | goto out; | |
117 | } | |
e70fdfb9 | 118 | inh = !(flags & O_CLOEXEC); |
f16706de | 119 | if (!DuplicateHandle (proc, pipe_hdl, GetCurrentProcess (), &nio_hdl, |
8ae1d98d | 120 | 0, inh, DUPLICATE_SAME_ACCESS)) |
7d880770 CV |
121 | { |
122 | __seterrno (); | |
123 | goto out; | |
124 | } | |
7d880770 | 125 | init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY); |
7d880770 | 126 | uninterruptible_io (fh->uninterruptible_io ()); |
0d8efc42 | 127 | cfree (fh); |
7d880770 CV |
128 | CloseHandle (proc); |
129 | return 1; | |
01a94cf8 | 130 | out: |
7d880770 CV |
131 | if (nio_hdl) |
132 | CloseHandle (nio_hdl); | |
133 | if (fh) | |
134 | free (fh); | |
135 | if (proc) | |
136 | CloseHandle (proc); | |
e8309efd CV |
137 | return 0; |
138 | } | |
139 | ||
1727fba0 CV |
140 | _off64_t |
141 | fhandler_pipe::lseek (_off64_t offset, int whence) | |
5e733918 CF |
142 | { |
143 | debug_printf ("(%d, %d)", offset, whence); | |
144 | set_errno (ESPIPE); | |
145 | return -1; | |
146 | } | |
147 | ||
7636b585 CV |
148 | int |
149 | fhandler_pipe::fadvise (_off64_t offset, _off64_t length, int advice) | |
150 | { | |
151 | set_errno (ESPIPE); | |
152 | return -1; | |
153 | } | |
154 | ||
155 | int | |
156 | fhandler_pipe::ftruncate (_off64_t length, bool allow_truncate) | |
157 | { | |
158 | set_errno (allow_truncate ? EINVAL : ESPIPE); | |
159 | return -1; | |
160 | } | |
161 | ||
b040009e CF |
162 | char * |
163 | fhandler_pipe::get_proc_fd_name (char *buf) | |
4f27e288 CV |
164 | { |
165 | __small_sprintf (buf, "pipe:[%d]", get_handle ()); | |
166 | return buf; | |
167 | } | |
168 | ||
e3cbf1cc | 169 | void |
a5d4ae5c | 170 | fhandler_pipe::raw_read (void *in_ptr, size_t& in_len) |
5e733918 | 171 | { |
d9c0e3ec | 172 | return read_overlapped (in_ptr, in_len); |
5e733918 CF |
173 | } |
174 | ||
7ac61736 | 175 | int |
a5d4ae5c | 176 | fhandler_pipe::raw_write (const void *ptr, size_t len) |
8bce0d72 | 177 | { |
d9c0e3ec | 178 | return write_overlapped (ptr, len); |
a1dc0932 CF |
179 | } |
180 | ||
5e733918 | 181 | int |
dcb091ca | 182 | fhandler_pipe::dup (fhandler_base *child) |
5e733918 | 183 | { |
f7239090 | 184 | fhandler_pipe *ftp = (fhandler_pipe *) child; |
c16548b2 | 185 | ftp->set_popen_pid (0); |
f7239090 | 186 | |
d9c0e3ec | 187 | int res; |
b040009e | 188 | if (get_handle () && fhandler_base::dup (child)) |
d9c0e3ec | 189 | res = -1; |
b040009e | 190 | else |
d9c0e3ec | 191 | res = 0; |
35f879a6 | 192 | |
f7239090 CF |
193 | debug_printf ("res %d", res); |
194 | return res; | |
5e733918 CF |
195 | } |
196 | ||
1ffe3e67 CF |
197 | #define PIPE_INTRO "\\\\.\\pipe\\cygwin-" |
198 | ||
6644c628 CF |
199 | /* Create a pipe, and return handles to the read and write ends, |
200 | just like CreatePipe, but ensure that the write end permits | |
201 | FILE_READ_ATTRIBUTES access, on later versions of win32 where | |
202 | this is supported. This access is needed by NtQueryInformationFile, | |
203 | which is used to implement select and nonblocking writes. | |
fb201f92 | 204 | Note that the return value is either 0 or GetLastError, |
6644c628 | 205 | unlike CreatePipe, which returns a bool for success or failure. */ |
fb201f92 CF |
206 | int |
207 | fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |
1ffe3e67 | 208 | HANDLE& w, DWORD psize, const char *name) |
6644c628 CF |
209 | { |
210 | /* Default to error. */ | |
fb201f92 | 211 | r = w = INVALID_HANDLE_VALUE; |
6644c628 CF |
212 | |
213 | /* Ensure that there is enough pipe buffer space for atomic writes. */ | |
be1cabba | 214 | if (psize < PIPE_BUF) |
6644c628 CF |
215 | psize = PIPE_BUF; |
216 | ||
526b0fbc CV |
217 | char pipename[MAX_PATH]; |
218 | const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", | |
219 | &installation_key); | |
220 | ||
1ffe3e67 CF |
221 | /* FIXME: Eventually make ttys work with overlapped I/O. */ |
222 | DWORD overlapped = name ? 0 : FILE_FLAG_OVERLAPPED; | |
6644c628 CF |
223 | |
224 | /* Retry CreateNamedPipe as long as the pipe name is in use. | |
225 | Retrying will probably never be necessary, but we want | |
226 | to be as robust as possible. */ | |
1ffe3e67 CF |
227 | DWORD err; |
228 | do | |
6644c628 | 229 | { |
fb201f92 | 230 | static volatile ULONG pipe_unique_id; |
1ffe3e67 | 231 | if (!name) |
526b0fbc | 232 | __small_sprintf (pipename + len, "pipe-%p-%p", myself->pid, |
1ffe3e67 CF |
233 | InterlockedIncrement ((LONG *) &pipe_unique_id)); |
234 | else | |
526b0fbc | 235 | strcpy (pipename + len, name); |
6644c628 CF |
236 | |
237 | debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize); | |
238 | ||
1ffe3e67 | 239 | err = 0; |
6644c628 | 240 | /* Use CreateNamedPipe instead of CreatePipe, because the latter |
d584454c CF |
241 | returns a write handle that does not permit FILE_READ_ATTRIBUTES |
242 | access, on versions of win32 earlier than WinXP SP2. | |
243 | CreatePipe also stupidly creates a full duplex pipe, which is | |
244 | a waste, since only a single direction is actually used. | |
245 | It's important to only allow a single instance, to ensure that | |
246 | the pipe was not created earlier by some other process, even if | |
247 | the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE | |
248 | because that is only available for Win2k SP2 and WinXP. */ | |
1ffe3e67 | 249 | r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND | overlapped, |
fb201f92 CF |
250 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, psize, |
251 | psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); | |
6644c628 | 252 | |
64232968 | 253 | /* Win 95 seems to return NULL instead of INVALID_HANDLE_VALUE */ |
fb201f92 | 254 | if (r && r != INVALID_HANDLE_VALUE) |
d584454c | 255 | { |
fb201f92 | 256 | debug_printf ("pipe read handle %p", r); |
d584454c CF |
257 | break; |
258 | } | |
6644c628 | 259 | |
1ffe3e67 | 260 | err = GetLastError (); |
6644c628 | 261 | switch (err) |
d584454c CF |
262 | { |
263 | case ERROR_PIPE_BUSY: | |
264 | /* The pipe is already open with compatible parameters. | |
265 | Pick a new name and retry. */ | |
3c4f2024 | 266 | debug_printf ("pipe busy", name ? ", retrying" : ""); |
fb201f92 | 267 | break; |
d584454c CF |
268 | case ERROR_ACCESS_DENIED: |
269 | /* The pipe is already open with incompatible parameters. | |
270 | Pick a new name and retry. */ | |
3c4f2024 | 271 | debug_printf ("pipe access denied%s", name ? ", retrying" : ""); |
fb201f92 CF |
272 | break; |
273 | default: | |
d9c0e3ec CF |
274 | { |
275 | err = GetLastError (); | |
276 | debug_printf ("CreatePipe failed, %E"); | |
277 | return err; | |
278 | } | |
d584454c | 279 | } |
6644c628 | 280 | } |
1ffe3e67 CF |
281 | while (!name); |
282 | ||
283 | if (err) | |
284 | return err; | |
6644c628 CF |
285 | |
286 | debug_printf ("CreateFile: name %s", pipename); | |
287 | ||
288 | /* Open the named pipe for writing. | |
289 | Be sure to permit FILE_READ_ATTRIBUTES access. */ | |
fb201f92 | 290 | w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr, |
1ffe3e67 | 291 | OPEN_EXISTING, overlapped, 0); |
fb201f92 CF |
292 | |
293 | if (!w || w == INVALID_HANDLE_VALUE) | |
6644c628 CF |
294 | { |
295 | /* Failure. */ | |
296 | DWORD err = GetLastError (); | |
297 | debug_printf ("CreateFile failed, %E"); | |
fb201f92 | 298 | CloseHandle (r); |
6644c628 CF |
299 | return err; |
300 | } | |
301 | ||
fb201f92 | 302 | debug_printf ("pipe write handle %p", w); |
6644c628 CF |
303 | |
304 | /* Success. */ | |
fb201f92 | 305 | return 0; |
6644c628 CF |
306 | } |
307 | ||
35f879a6 | 308 | int |
be1cabba | 309 | fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) |
1fd5e000 | 310 | { |
1fd5e000 | 311 | HANDLE r, w; |
e70fdfb9 | 312 | SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); |
8528ecbd | 313 | int res; |
1fd5e000 | 314 | |
be1cabba | 315 | int ret = create_selectable (sa, r, w, psize); |
fb201f92 | 316 | if (ret) |
8528ecbd CF |
317 | { |
318 | __seterrno_from_win_error (ret); | |
319 | res = -1; | |
320 | } | |
7ac61736 | 321 | else |
1fd5e000 | 322 | { |
7ac61736 CF |
323 | fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev); |
324 | fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev); | |
325 | ||
8528ecbd CF |
326 | mode |= mode & O_TEXT ?: O_BINARY; |
327 | fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, mode); | |
328 | fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode); | |
7ac61736 | 329 | res = 0; |
1fd5e000 CF |
330 | } |
331 | ||
2d2a0680 | 332 | syscall_printf ("%d = pipe ([%p, %p], %d, %p)", res, fhs[0], fhs[1], psize, mode); |
57bf29e8 | 333 | return res; |
1fd5e000 CF |
334 | } |
335 | ||
49f7ea16 CF |
336 | int |
337 | fhandler_pipe::ioctl (unsigned int cmd, void *p) | |
338 | { | |
339 | int n; | |
340 | ||
341 | switch (cmd) | |
342 | { | |
343 | case FIONREAD: | |
344 | if (get_device () == FH_PIPEW) | |
345 | { | |
346 | set_errno (EINVAL); | |
347 | return -1; | |
348 | } | |
349 | if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, (DWORD *) &n, NULL)) | |
350 | { | |
351 | __seterrno (); | |
352 | return -1; | |
353 | } | |
354 | break; | |
355 | default: | |
356 | return fhandler_base::ioctl (cmd, p); | |
357 | break; | |
358 | } | |
359 | *(int *) p = n; | |
360 | return 0; | |
361 | } | |
362 | ||
3323df7e CV |
363 | int __stdcall |
364 | fhandler_pipe::fstatvfs (struct statvfs *sfs) | |
365 | { | |
366 | set_errno (EBADF); | |
367 | return -1; | |
368 | } | |
369 | ||
fbf39a58 | 370 | #define DEFAULT_PIPEBUFSIZE 65536 |
6644c628 | 371 | |
1fd5e000 CF |
372 | extern "C" int |
373 | pipe (int filedes[2]) | |
374 | { | |
7ac61736 | 375 | fhandler_pipe *fhs[2]; |
fd8e5366 | 376 | int res = fhandler_pipe::create (fhs, DEFAULT_PIPEBUFSIZE, O_BINARY); |
7ac61736 CF |
377 | if (res == 0) |
378 | { | |
379 | cygheap_fdnew fdin; | |
380 | cygheap_fdnew fdout (fdin, false); | |
381 | fdin = fhs[0]; | |
382 | fdout = fhs[1]; | |
383 | filedes[0] = fdin; | |
384 | filedes[1] = fdout; | |
385 | } | |
386 | ||
387 | return res; | |
1fd5e000 CF |
388 | } |
389 | ||
390 | extern "C" int | |
391 | _pipe (int filedes[2], unsigned int psize, int mode) | |
392 | { | |
7ac61736 CF |
393 | fhandler_pipe *fhs[2]; |
394 | int res = fhandler_pipe::create (fhs, psize, mode); | |
1fd5e000 CF |
395 | /* This type of pipe is not interruptible so set the appropriate flag. */ |
396 | if (!res) | |
7ac61736 CF |
397 | { |
398 | cygheap_fdnew fdin; | |
399 | cygheap_fdnew fdout (fdin, false); | |
56551a9b | 400 | fhs[0]->uninterruptible_io (true); |
7ac61736 CF |
401 | fdin = fhs[0]; |
402 | fdout = fhs[1]; | |
403 | filedes[0] = fdin; | |
404 | filedes[1] = fdout; | |
405 | } | |
406 | ||
1fd5e000 CF |
407 | return res; |
408 | } | |
e70fdfb9 CV |
409 | |
410 | extern "C" int | |
411 | pipe2 (int filedes[2], int mode) | |
412 | { | |
413 | return _pipe (filedes, DEFAULT_PIPEBUFSIZE, mode); | |
414 | } |