X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpipe2.c;h=cd1fe56413c7048a2ce9d0f6a83a948295e9f8ef;hb=efbbfb91034a125333b7b147bc6a32170b25c890;hp=726813f9af5fc4e54c217ff9b87af84d5e21e41a;hpb=d7834f34cb055a90437b1076b2c94bad34e317b8;p=gnulib.git diff --git a/lib/pipe2.c b/lib/pipe2.c index 726813f9a..cd1fe5641 100644 --- a/lib/pipe2.c +++ b/lib/pipe2.c @@ -1,5 +1,5 @@ /* Create a pipe, with specific opening flags. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009-2011 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,57 +23,106 @@ #include #include +#include "binary-io.h" +#include "verify.h" + +#if GNULIB_defined_O_NONBLOCK +# include "nonblocking.h" +#endif + #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ /* Native Woe32 API. */ # include +#endif + int pipe2 (int fd[2], int flags) { + /* Mingw _pipe() corrupts fd on failure; also, if we succeed at + creating the pipe but later fail at changing fcntl, we want + to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */ + int tmp[2]; + tmp[0] = fd[0]; + tmp[1] = fd[1]; + +#if HAVE_PIPE2 +# undef pipe2 + /* Try the system call first, if it exists. (We may be running with a glibc + that has the function but with an older kernel that lacks it.) */ + { + /* Cache the information whether the system call really exists. */ + static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */ + if (have_pipe2_really >= 0) + { + int result = pipe2 (fd, flags); + if (!(result < 0 && errno == ENOSYS)) + { + have_pipe2_really = 1; + return result; + } + have_pipe2_really = -1; + } + } +#endif + /* Check the supported flags. */ - if ((flags & ~(O_CLOEXEC | O_BINARY | O_TEXT)) != 0) + if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0) { errno = EINVAL; return -1; } - return _pipe (fd, 4096, flags); -} - -#else -/* Unix API. */ - -# ifndef O_CLOEXEC -# define O_CLOEXEC 0 -# endif +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Native Woe32 API. */ -int -pipe2 (int fd[2], int flags) -{ - /* Check the supported flags. */ - if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_TEXT | O_BINARY)) != 0) + if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0) { - errno = EINVAL; + fd[0] = tmp[0]; + fd[1] = tmp[1]; return -1; } + /* O_NONBLOCK handling. + On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the + functions defined by the gnulib module 'nonblocking'. */ +# if GNULIB_defined_O_NONBLOCK + if (flags & O_NONBLOCK) + { + if (set_nonblocking_flag (fd[0], true) != 0 + || set_nonblocking_flag (fd[1], true) != 0) + goto fail; + } +# else + { + verify (O_NONBLOCK == 0); + } +# endif + + return 0; + +#else +/* Unix API. */ + if (pipe (fd) < 0) return -1; /* POSIX says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on - both fd[0] amd fd[1]. */ + both fd[0] and fd[1]. */ + /* O_NONBLOCK handling. + On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */ if (flags & O_NONBLOCK) { int fcntl_flags; if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0 - || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1 - || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0 - || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1) - goto fail; + || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1 + || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0 + || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1) + goto fail; } if (flags & O_CLOEXEC) @@ -81,13 +130,13 @@ pipe2 (int fd[2], int flags) int fcntl_flags; if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0 - || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1 - || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0 - || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) - goto fail; + || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1 + || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0 + || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) + goto fail; } -#if O_BINARY +# if O_BINARY if (flags & O_BINARY) { setmode (fd[1], O_BINARY); @@ -98,18 +147,23 @@ pipe2 (int fd[2], int flags) setmode (fd[1], O_TEXT); setmode (fd[0], O_TEXT); } -#endif +# endif return 0; +#endif + +#if GNULIB_defined_O_NONBLOCK || \ + !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) fail: { int saved_errno = errno; close (fd[0]); close (fd[1]); + fd[0] = tmp[0]; + fd[1] = tmp[1]; errno = saved_errno; return -1; } -} - #endif +}