]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/pipe.cc
* cygwin.din (dup3): Export.
[newlib-cygwin.git] / winsup / cygwin / pipe.cc
CommitLineData
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
6This file is part of Cygwin.
7
8This software is a copyrighted work licensed under the terms of the
9Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10details. */
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 26fhandler_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 33int
8528ecbd 34fhandler_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
61extern "C" int sscanf (const char *, const char *, ...);
62
e8309efd
CV
63int
64fhandler_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 130out:
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
141fhandler_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
148int
149fhandler_pipe::fadvise (_off64_t offset, _off64_t length, int advice)
150{
151 set_errno (ESPIPE);
152 return -1;
153}
154
155int
156fhandler_pipe::ftruncate (_off64_t length, bool allow_truncate)
157{
158 set_errno (allow_truncate ? EINVAL : ESPIPE);
159 return -1;
160}
161
b040009e
CF
162char *
163fhandler_pipe::get_proc_fd_name (char *buf)
4f27e288
CV
164{
165 __small_sprintf (buf, "pipe:[%d]", get_handle ());
166 return buf;
167}
168
e3cbf1cc 169void
a5d4ae5c 170fhandler_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 175int
a5d4ae5c 176fhandler_pipe::raw_write (const void *ptr, size_t len)
8bce0d72 177{
d9c0e3ec 178 return write_overlapped (ptr, len);
a1dc0932
CF
179}
180
5e733918 181int
dcb091ca 182fhandler_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
206int
207fhandler_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 308int
be1cabba 309fhandler_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
336int
337fhandler_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
363int __stdcall
364fhandler_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
372extern "C" int
373pipe (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
390extern "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
410extern "C" int
411pipe2 (int filedes[2], int mode)
412{
413 return _pipe (filedes, DEFAULT_PIPEBUFSIZE, mode);
414}
This page took 0.360495 seconds and 5 git commands to generate.