bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

new module 'dup3'


From: Bruno Haible
Subject: new module 'dup3'
Date: Mon, 24 Aug 2009 00:17:25 +0200
User-agent: KMail/1.9.9

This implements the 'dup3' replacement function.

Paolo's issue of use of older Linux kernels is not yet handled.


2009-08-23  Bruno Haible  <address@hidden>

        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.

================================= lib/dup3.c =================================
/* 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;
}
================================= m4/dup3.m4 =================================
# 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
])
================================ modules/dup3 ================================
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
==============================================================================
--- doc/glibc-functions/dup3.texi.orig  2009-08-24 00:11:26.000000000 +0200
+++ doc/glibc-functions/dup3.texi       2009-08-23 21:55:58.000000000 +0200
@@ -2,15 +2,15 @@
 @subsection @code{dup3}
 @findex dup3
 
-Gnulib module: ---
+Gnulib module: dup3
 
 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+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
address@hidden
-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
--- lib/unistd.in.h.orig        2009-08-24 00:11:26.000000000 +0200
+++ lib/unistd.in.h     2009-08-24 00:11:22.000000000 +0200
@@ -178,6 +178,27 @@
 #endif
 
 
+#if @GNULIB_DUP3@
+# if address@hidden@
+/* 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 address@hidden@
 /* Set of environment variables and values.  An array of strings of the form
--- m4/unistd_h.m4.orig 2009-08-24 00:11:26.000000000 +0200
+++ m4/unistd_h.m4      2009-08-23 21:55:58.000000000 +0200
@@ -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])
--- modules/unistd.orig 2009-08-24 00:11:26.000000000 +0200
+++ modules/unistd      2009-08-23 21:55:58.000000000 +0200
@@ -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' \




reply via email to

[Prev in Thread] Current Thread [Next in Thread]