root/maint/gnulib/tests/test-dup2.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_open
  2. is_inheritable
  3. zero
  4. is_mode
  5. main

   1 /* Test duplicating file descriptors.
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
  18 
  19 #include <config.h>
  20 
  21 #include <unistd.h>
  22 
  23 #include "signature.h"
  24 SIGNATURE_CHECK (dup2, int, (int, int));
  25 
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 
  29 #if HAVE_SYS_RESOURCE_H
  30 # include <sys/resource.h>
  31 #endif
  32 
  33 #include "binary-io.h"
  34 
  35 #if GNULIB_TEST_CLOEXEC
  36 # include "cloexec.h"
  37 #endif
  38 
  39 #if defined _WIN32 && ! defined __CYGWIN__
  40 /* Get declarations of the native Windows API functions.  */
  41 # define WIN32_LEAN_AND_MEAN
  42 # include <windows.h>
  43 /* Get _get_osfhandle.  */
  44 # if GNULIB_MSVC_NOTHROW
  45 #  include "msvc-nothrow.h"
  46 # else
  47 #  include <io.h>
  48 # endif
  49 #endif
  50 
  51 #include "macros.h"
  52 
  53 /* Return non-zero if FD is open.  */
  54 static int
  55 is_open (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57 #if defined _WIN32 && ! defined __CYGWIN__
  58   /* On native Windows, the initial state of unassigned standard file
  59      descriptors is that they are open but point to an
  60      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  61   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
  62 #else
  63 # ifndef F_GETFL
  64 #  error Please port fcntl to your platform
  65 # endif
  66   return 0 <= fcntl (fd, F_GETFL);
  67 #endif
  68 }
  69 
  70 #if GNULIB_TEST_CLOEXEC
  71 /* Return non-zero if FD is open and inheritable across exec/spawn.  */
  72 static int
  73 is_inheritable (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75 # if defined _WIN32 && ! defined __CYGWIN__
  76   /* On native Windows, the initial state of unassigned standard file
  77      descriptors is that they are open but point to an
  78      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  79   HANDLE h = (HANDLE) _get_osfhandle (fd);
  80   DWORD flags;
  81   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
  82     return 0;
  83   return (flags & HANDLE_FLAG_INHERIT) != 0;
  84 # else
  85 #  ifndef F_GETFD
  86 #   error Please port fcntl to your platform
  87 #  endif
  88   int i = fcntl (fd, F_GETFD);
  89   return 0 <= i && (i & FD_CLOEXEC) == 0;
  90 # endif
  91 }
  92 #endif /* GNULIB_TEST_CLOEXEC */
  93 
  94 #if !O_BINARY
  95 # define set_binary_mode(f,m) zero ()
  96 static int zero (void) { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  97 #endif
  98 
  99 /* Return non-zero if FD is open in the given MODE, which is either
 100    O_TEXT or O_BINARY.  */
 101 static int
 102 is_mode (int fd, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104   int value = set_binary_mode (fd, O_BINARY);
 105   set_binary_mode (fd, value);
 106   return mode == value;
 107 }
 108 
 109 int
 110 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112   const char *file = "test-dup2.tmp";
 113   char buffer[1];
 114   int bad_fd = getdtablesize ();
 115   int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600);
 116 
 117   /* Assume std descriptors were provided by invoker.  */
 118   ASSERT (STDERR_FILENO < fd);
 119   ASSERT (is_open (fd));
 120   /* Ignore any other fd's leaked into this process.  */
 121   close (fd + 1);
 122   close (fd + 2);
 123   ASSERT (!is_open (fd + 1));
 124   ASSERT (!is_open (fd + 2));
 125 
 126   /* Assigning to self must be a no-op.  */
 127   ASSERT (dup2 (fd, fd) == fd);
 128   ASSERT (is_open (fd));
 129 
 130   /* The source must be valid.  */
 131   errno = 0;
 132   ASSERT (dup2 (-1, fd) == -1);
 133   ASSERT (errno == EBADF);
 134   close (99);
 135   errno = 0;
 136   ASSERT (dup2 (99, fd) == -1);
 137   ASSERT (errno == EBADF);
 138   errno = 0;
 139   ASSERT (dup2 (AT_FDCWD, fd) == -1);
 140   ASSERT (errno == EBADF);
 141   ASSERT (is_open (fd));
 142 
 143   /* If the source is not open, then the destination is unaffected.  */
 144   errno = 0;
 145   ASSERT (dup2 (fd + 1, fd + 1) == -1);
 146   ASSERT (errno == EBADF);
 147   ASSERT (!is_open (fd + 1));
 148   errno = 0;
 149   ASSERT (dup2 (fd + 1, fd) == -1);
 150   ASSERT (errno == EBADF);
 151   ASSERT (is_open (fd));
 152 
 153   /* The destination must be valid.  */
 154   errno = 0;
 155   ASSERT (dup2 (fd, -2) == -1);
 156   ASSERT (errno == EBADF);
 157   if (bad_fd > 256)
 158     {
 159       ASSERT (dup2 (fd, 255) == 255);
 160       ASSERT (dup2 (fd, 256) == 256);
 161       ASSERT (close (255) == 0);
 162       ASSERT (close (256) == 0);
 163     }
 164   ASSERT (dup2 (fd, bad_fd - 1) == bad_fd - 1);
 165   ASSERT (close (bad_fd - 1) == 0);
 166   errno = 0;
 167   ASSERT (dup2 (fd, bad_fd) == -1);
 168   ASSERT (errno == EBADF);
 169 
 170   /* Using dup2 can skip fds.  */
 171   ASSERT (dup2 (fd, fd + 2) == fd + 2);
 172   ASSERT (is_open (fd));
 173   ASSERT (!is_open (fd + 1));
 174   ASSERT (is_open (fd + 2));
 175 
 176   /* Verify that dup2 closes the previous occupant of a fd.  */
 177   ASSERT (open ("/dev/null", O_WRONLY, 0600) == fd + 1);
 178   ASSERT (dup2 (fd + 1, fd) == fd);
 179   ASSERT (close (fd + 1) == 0);
 180   ASSERT (write (fd, "1", 1) == 1);
 181   ASSERT (dup2 (fd + 2, fd) == fd);
 182   ASSERT (lseek (fd, 0, SEEK_END) == 0);
 183   ASSERT (write (fd + 2, "2", 1) == 1);
 184   ASSERT (lseek (fd, 0, SEEK_SET) == 0);
 185   ASSERT (read (fd, buffer, 1) == 1);
 186   ASSERT (*buffer == '2');
 187 
 188 #if GNULIB_TEST_CLOEXEC
 189   /* Any new fd created by dup2 must not be cloexec.  */
 190   ASSERT (close (fd + 2) == 0);
 191   ASSERT (dup_cloexec (fd) == fd + 1);
 192   ASSERT (!is_inheritable (fd + 1));
 193   ASSERT (dup2 (fd + 1, fd + 1) == fd + 1);
 194   ASSERT (!is_inheritable (fd + 1));
 195   ASSERT (dup2 (fd + 1, fd + 2) == fd + 2);
 196   ASSERT (!is_inheritable (fd + 1));
 197   ASSERT (is_inheritable (fd + 2));
 198   errno = 0;
 199   ASSERT (dup2 (fd + 1, -1) == -1);
 200   ASSERT (errno == EBADF);
 201   ASSERT (!is_inheritable (fd + 1));
 202 #endif
 203 
 204   /* On systems that distinguish between text and binary mode, dup2
 205      reuses the mode of the source.  */
 206   set_binary_mode (fd, O_BINARY);
 207   ASSERT (is_mode (fd, O_BINARY));
 208   ASSERT (dup2 (fd, fd + 1) == fd + 1);
 209   ASSERT (is_mode (fd + 1, O_BINARY));
 210   set_binary_mode (fd, O_TEXT);
 211   ASSERT (is_mode (fd, O_TEXT));
 212   ASSERT (dup2 (fd, fd + 1) == fd + 1);
 213   ASSERT (is_mode (fd + 1, O_TEXT));
 214 
 215   /* Clean up.  */
 216   ASSERT (close (fd + 2) == 0);
 217   ASSERT (close (fd + 1) == 0);
 218   ASSERT (close (fd) == 0);
 219   ASSERT (unlink (file) == 0);
 220 
 221   return 0;
 222 }

/* [previous][next][first][last][top][bottom][index][help] */