Mercurial > hg > octave-nkf > gnulib-hg
changeset 11886:3ac76948db10
New module 'dup3'.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Mon, 24 Aug 2009 00:17:47 +0200 |
parents | e61a5067af2f |
children | ce99ebbf27a3 |
files | ChangeLog doc/glibc-functions/dup3.texi lib/dup3.c lib/unistd.in.h m4/dup3.m4 m4/unistd_h.m4 modules/dup3 modules/unistd |
diffstat | 8 files changed, 289 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-08-23 Bruno Haible <bruno@clisp.org> + + New module 'dup3'. + * lib/unistd.in.h (dup3): New declaration. + * lib/dup3.c: New file. + * m4/dup3.m4: New file. + * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize GNULIB_DUP3 and + HAVE_DUP3. + * modules/unistd (Makefile.am): Substitute GNULIB_DUP3 and HAVE_DUP3. + * modules/dup3: New file. + * doc/glibc-functions/dup3.texi: Mention the new module. + 2009-08-23 Bruno Haible <bruno@clisp.org> Tweak the dup2 test.
--- a/doc/glibc-functions/dup3.texi +++ b/doc/glibc-functions/dup3.texi @@ -2,15 +2,15 @@ @subsection @code{dup3} @findex dup3 -Gnulib module: --- +Gnulib module: dup3 Portability problems fixed by Gnulib: @itemize -@end itemize - -Portability problems not fixed by Gnulib: -@itemize @item This function is missing on all non-glibc platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, Interix 3.5, BeOS. @end itemize + +Portability problems not fixed by Gnulib: +@itemize +@end itemize
new file mode 100644 --- /dev/null +++ b/lib/dup3.c @@ -0,0 +1,200 @@ +/* Copy a file descriptor, applying specific flags. + Copyright (C) 2009 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 + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <config.h> + +/* Specification. */ +#include <unistd.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> + +#include "binary-io.h" + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Native Woe32 API. */ + +/* Get declarations of the Win32 API functions. */ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> + +/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */ +# define OPEN_MAX_MAX 0x10000 + +#else +/* Unix API. */ + +# ifndef O_CLOEXEC +# define O_CLOEXEC 0 +# endif + +#endif + +int +dup3 (int oldfd, int newfd, int flags) +{ + if (oldfd < 0 || newfd < 0 || newfd >= getdtablesize ()) + { + errno = EBADF; + return -1; + } + + if (newfd == oldfd) + { + errno = EINVAL; + return -1; + } + + /* Check the supported flags. + Note that O_NONBLOCK is not supported, because setting it on newfd + would implicitly also set it on oldfd. */ + if ((flags & ~(O_CLOEXEC | O_BINARY | O_TEXT)) != 0) + { + errno = EINVAL; + return -1; + } + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Native Woe32 API. */ + + if (flags & O_CLOEXEC) + { + /* Neither dup() nor dup2() can create a file descriptor with + O_CLOEXEC = O_NOINHERIT set. We need to use the low-level function + _open_osfhandle for this. Iterate until all file descriptors less + than newfd are filled up. */ + HANDLE curr_process = GetCurrentProcess (); + HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd); + unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT]; + unsigned int fds_to_close_bound = 0; + int result; + + if (old_handle == INVALID_HANDLE_VALUE) + { + /* oldfd is not open, or is an unassigned standard file + descriptor. */ + errno = EBADF; + return -1; + } + + close (newfd); + + for (;;) + { + HANDLE new_handle; + int duplicated_fd; + unsigned int index; + + if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ + old_handle, /* SourceHandle */ + curr_process, /* TargetProcessHandle */ + (PHANDLE) &new_handle, /* TargetHandle */ + (DWORD) 0, /* DesiredAccess */ + FALSE, /* InheritHandle */ + DUPLICATE_SAME_ACCESS)) /* Options */ + { + errno = EBADF; /* arbitrary */ + result = -1; + break; + } + duplicated_fd = _open_osfhandle ((long) new_handle, flags); + if (duplicated_fd < 0) + { + CloseHandle (new_handle); + result = -1; + break; + } + if (duplicated_fd > newfd) + /* Shouldn't happen, since newfd is still closed. */ + abort (); + if (duplicated_fd == newfd) + { + result = newfd; + break; + } + + /* Set the bit duplicated_fd in fds_to_close[]. */ + index = (unsigned int) duplicated_fd / CHAR_BIT; + if (index >= fds_to_close_bound) + { + if (index >= sizeof (fds_to_close)) + /* Need to increase OPEN_MAX_MAX. */ + abort (); + memset (fds_to_close + fds_to_close_bound, '\0', + index + 1 - fds_to_close_bound); + fds_to_close_bound = index + 1; + } + fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT); + } + + /* Close the previous fds that turned out to be too small. */ + { + int saved_errno = errno; + unsigned int duplicated_fd; + + for (duplicated_fd = 0; + duplicated_fd < fds_to_close_bound * CHAR_BIT; + duplicated_fd++) + if ((fds_to_close[duplicated_fd / CHAR_BIT] + >> (duplicated_fd % CHAR_BIT)) + & 1) + close (duplicated_fd); + + errno = saved_errno; + } + + return result; + } + + if (dup2 (oldfd, newfd) < 0) + return -1; + +#else +/* Unix API. */ + + if (dup2 (oldfd, newfd) < 0) + return -1; + + /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/dup.html> + says that initially, the FD_CLOEXEC flag is cleared on newfd. */ + + if (flags & O_CLOEXEC) + { + int fcntl_flags; + + if ((fcntl_flags = fcntl (newfd, F_GETFD, 0)) < 0 + || fcntl (newfd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) + { + int saved_errno = errno; + close (newfd); + errno = saved_errno; + return -1; + } + } + +#endif + +#if O_BINARY + if (flags & O_BINARY) + setmode (newfd, O_BINARY); + else if (flags & O_TEXT) + setmode (newfd, O_TEXT); +#endif + + return newfd; +}
--- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -178,6 +178,27 @@ #endif +#if @GNULIB_DUP3@ +# if !@HAVE_DUP3@ +/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the + specified flags. + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>) + and O_TEXT, O_BINARY (defined in "binary-io.h"). + Close NEWFD first if it is open. + Return newfd if successful, otherwise -1 and errno set. + See the Linux man page at + <http://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>. */ +extern int dup3 (int oldfd, int newfd, int flags); +# endif +#elif defined GNULIB_POSIXCHECK +# undef dup3 +# define dup3(o,n,f) \ + (GL_LINK_WARNING ("dup3 is unportable - " \ + "use gnulib module dup3 for portability"), \ + dup3 (o, n, f)) +#endif + + #if @GNULIB_ENVIRON@ # if !@HAVE_DECL_ENVIRON@ /* Set of environment variables and values. An array of strings of the form
new file mode 100644 --- /dev/null +++ b/m4/dup3.m4 @@ -0,0 +1,19 @@ +# dup3.m4 serial 1 +dnl Copyright (C) 2009 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_DUP3], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + + dnl Persuade glibc <unistd.h> to declare dup3(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([dup3]) + if test $ac_cv_func_dup3 != yes; then + HAVE_DUP3=0 + AC_LIBOBJ([dup3]) + fi +])
--- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -1,4 +1,4 @@ -# unistd_h.m4 serial 20 +# unistd_h.m4 serial 21 dnl Copyright (C) 2006-2009 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -35,6 +35,7 @@ GNULIB_CHOWN=0; AC_SUBST([GNULIB_CHOWN]) GNULIB_CLOSE=0; AC_SUBST([GNULIB_CLOSE]) GNULIB_DUP2=0; AC_SUBST([GNULIB_DUP2]) + GNULIB_DUP3=0; AC_SUBST([GNULIB_DUP3]) GNULIB_ENVIRON=0; AC_SUBST([GNULIB_ENVIRON]) GNULIB_EUIDACCESS=0; AC_SUBST([GNULIB_EUIDACCESS]) GNULIB_FCHDIR=0; AC_SUBST([GNULIB_FCHDIR]) @@ -58,6 +59,7 @@ GNULIB_WRITE=0; AC_SUBST([GNULIB_WRITE]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_DUP2=1; AC_SUBST([HAVE_DUP2]) + HAVE_DUP3=1; AC_SUBST([HAVE_DUP3]) HAVE_EUIDACCESS=1; AC_SUBST([HAVE_EUIDACCESS]) HAVE_FSYNC=1; AC_SUBST([HAVE_FSYNC]) HAVE_FTRUNCATE=1; AC_SUBST([HAVE_FTRUNCATE])
new file mode 100644 --- /dev/null +++ b/modules/dup3 @@ -0,0 +1,27 @@ +Description: +dup3() function: copy a file descriptor, applying specific flags. + +Files: +lib/dup3.c +m4/dup3.m4 + +Depends-on: +unistd +fcntl +binary-io +getdtablesize + +configure.ac: +gl_FUNC_DUP3 +gl_UNISTD_MODULE_INDICATOR([dup3]) + +Makefile.am: + +Include: +<unistd.h> + +License: +LGPL + +Maintainer: +Bruno Haible, Jim Meyering
--- a/modules/unistd +++ b/modules/unistd @@ -28,6 +28,7 @@ -e 's|@''GNULIB_CHOWN''@|$(GNULIB_CHOWN)|g' \ -e 's|@''GNULIB_CLOSE''@|$(GNULIB_CLOSE)|g' \ -e 's|@''GNULIB_DUP2''@|$(GNULIB_DUP2)|g' \ + -e 's|@''GNULIB_DUP3''@|$(GNULIB_DUP3)|g' \ -e 's|@''GNULIB_ENVIRON''@|$(GNULIB_ENVIRON)|g' \ -e 's|@''GNULIB_EUIDACCESS''@|$(GNULIB_EUIDACCESS)|g' \ -e 's|@''GNULIB_FCHDIR''@|$(GNULIB_FCHDIR)|g' \ @@ -50,6 +51,7 @@ -e 's|@''GNULIB_UNISTD_H_SIGPIPE''@|$(GNULIB_UNISTD_H_SIGPIPE)|g' \ -e 's|@''GNULIB_WRITE''@|$(GNULIB_WRITE)|g' \ -e 's|@''HAVE_DUP2''@|$(HAVE_DUP2)|g' \ + -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \ -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \ -e 's|@''HAVE_FSYNC''@|$(HAVE_FSYNC)|g' \ -e 's|@''HAVE_FTRUNCATE''@|$(HAVE_FTRUNCATE)|g' \