LCOV - code coverage report
Current view: top level - gltests - test-dup2.c (source / functions) Hit Total Coverage
Test: GNU Libidn Lines: 93 93 100.0 %
Date: 2020-07-22 17:53:13 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Test duplicating file descriptors.
       2             :    Copyright (C) 2009-2020 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          10 : is_open (int fd)
      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          10 :   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           5 : is_inheritable (int fd)
      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           5 :   int i = fcntl (fd, F_GETFD);
      89           5 :   return 0 <= i && (i & FD_CLOEXEC) == 0;
      90             : # endif
      91             : }
      92             : #endif /* GNULIB_TEST_CLOEXEC */
      93             : 
      94             : #if !O_BINARY
      95             : # define setmode(f,m) zero ()
      96          10 : static int zero (void) { return 0; }
      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           4 : is_mode (int fd, int mode)
     103             : {
     104           4 :   int value = setmode (fd, O_BINARY);
     105           4 :   setmode (fd, value);
     106           4 :   return mode == value;
     107             : }
     108             : 
     109             : int
     110           1 : main (void)
     111             : {
     112           1 :   const char *file = "test-dup2.tmp";
     113             :   char buffer[1];
     114           1 :   int bad_fd = getdtablesize ();
     115           1 :   int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600);
     116             : 
     117             :   /* Assume std descriptors were provided by invoker.  */
     118           1 :   ASSERT (STDERR_FILENO < fd);
     119           1 :   ASSERT (is_open (fd));
     120             :   /* Ignore any other fd's leaked into this process.  */
     121           1 :   close (fd + 1);
     122           1 :   close (fd + 2);
     123           1 :   ASSERT (!is_open (fd + 1));
     124           1 :   ASSERT (!is_open (fd + 2));
     125             : 
     126             :   /* Assigning to self must be a no-op.  */
     127           1 :   ASSERT (dup2 (fd, fd) == fd);
     128           1 :   ASSERT (is_open (fd));
     129             : 
     130             :   /* The source must be valid.  */
     131           1 :   errno = 0;
     132           1 :   ASSERT (dup2 (-1, fd) == -1);
     133           1 :   ASSERT (errno == EBADF);
     134           1 :   close (99);
     135           1 :   errno = 0;
     136           1 :   ASSERT (dup2 (99, fd) == -1);
     137           1 :   ASSERT (errno == EBADF);
     138           1 :   errno = 0;
     139           1 :   ASSERT (dup2 (AT_FDCWD, fd) == -1);
     140           1 :   ASSERT (errno == EBADF);
     141           1 :   ASSERT (is_open (fd));
     142             : 
     143             :   /* If the source is not open, then the destination is unaffected.  */
     144           1 :   errno = 0;
     145           1 :   ASSERT (dup2 (fd + 1, fd + 1) == -1);
     146           1 :   ASSERT (errno == EBADF);
     147           1 :   ASSERT (!is_open (fd + 1));
     148           1 :   errno = 0;
     149           1 :   ASSERT (dup2 (fd + 1, fd) == -1);
     150           1 :   ASSERT (errno == EBADF);
     151           1 :   ASSERT (is_open (fd));
     152             : 
     153             :   /* The destination must be valid.  */
     154           1 :   errno = 0;
     155           1 :   ASSERT (dup2 (fd, -2) == -1);
     156           1 :   ASSERT (errno == EBADF);
     157           1 :   if (bad_fd > 256)
     158             :     {
     159           1 :       ASSERT (dup2 (fd, 255) == 255);
     160           1 :       ASSERT (dup2 (fd, 256) == 256);
     161           1 :       ASSERT (close (255) == 0);
     162           1 :       ASSERT (close (256) == 0);
     163             :     }
     164           1 :   ASSERT (dup2 (fd, bad_fd - 1) == bad_fd - 1);
     165           1 :   ASSERT (close (bad_fd - 1) == 0);
     166           1 :   errno = 0;
     167           1 :   ASSERT (dup2 (fd, bad_fd) == -1);
     168           1 :   ASSERT (errno == EBADF);
     169             : 
     170             :   /* Using dup2 can skip fds.  */
     171           1 :   ASSERT (dup2 (fd, fd + 2) == fd + 2);
     172           1 :   ASSERT (is_open (fd));
     173           1 :   ASSERT (!is_open (fd + 1));
     174           1 :   ASSERT (is_open (fd + 2));
     175             : 
     176             :   /* Verify that dup2 closes the previous occupant of a fd.  */
     177           1 :   ASSERT (open ("/dev/null", O_WRONLY, 0600) == fd + 1);
     178           1 :   ASSERT (dup2 (fd + 1, fd) == fd);
     179           1 :   ASSERT (close (fd + 1) == 0);
     180           1 :   ASSERT (write (fd, "1", 1) == 1);
     181           1 :   ASSERT (dup2 (fd + 2, fd) == fd);
     182           1 :   ASSERT (lseek (fd, 0, SEEK_END) == 0);
     183           1 :   ASSERT (write (fd + 2, "2", 1) == 1);
     184           1 :   ASSERT (lseek (fd, 0, SEEK_SET) == 0);
     185           1 :   ASSERT (read (fd, buffer, 1) == 1);
     186           1 :   ASSERT (*buffer == '2');
     187             : 
     188             : #if GNULIB_TEST_CLOEXEC
     189             :   /* Any new fd created by dup2 must not be cloexec.  */
     190           1 :   ASSERT (close (fd + 2) == 0);
     191           1 :   ASSERT (dup_cloexec (fd) == fd + 1);
     192           1 :   ASSERT (!is_inheritable (fd + 1));
     193           1 :   ASSERT (dup2 (fd + 1, fd + 1) == fd + 1);
     194           1 :   ASSERT (!is_inheritable (fd + 1));
     195           1 :   ASSERT (dup2 (fd + 1, fd + 2) == fd + 2);
     196           1 :   ASSERT (!is_inheritable (fd + 1));
     197           1 :   ASSERT (is_inheritable (fd + 2));
     198           1 :   errno = 0;
     199           1 :   ASSERT (dup2 (fd + 1, -1) == -1);
     200           1 :   ASSERT (errno == EBADF);
     201           1 :   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           1 :   setmode (fd, O_BINARY);
     207           1 :   ASSERT (is_mode (fd, O_BINARY));
     208           1 :   ASSERT (dup2 (fd, fd + 1) == fd + 1);
     209           1 :   ASSERT (is_mode (fd + 1, O_BINARY));
     210           1 :   setmode (fd, O_TEXT);
     211           1 :   ASSERT (is_mode (fd, O_TEXT));
     212           1 :   ASSERT (dup2 (fd, fd + 1) == fd + 1);
     213           1 :   ASSERT (is_mode (fd + 1, O_TEXT));
     214             : 
     215             :   /* Clean up.  */
     216           1 :   ASSERT (close (fd + 2) == 0);
     217           1 :   ASSERT (close (fd + 1) == 0);
     218           1 :   ASSERT (close (fd) == 0);
     219           1 :   ASSERT (unlink (file) == 0);
     220             : 
     221           1 :   return 0;
     222             : }

Generated by: LCOV version 1.13