root/maint/gnulib/tests/test-dup-safer.c

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

DEFINITIONS

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

   1 /* Test that dup_safer leaves standard fds alone.
   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 <fcntl.h>
  24 #include <errno.h>
  25 #include <stdbool.h>
  26 #include <stdio.h>
  27 #include <unistd.h>
  28 
  29 #include "binary-io.h"
  30 #include "cloexec.h"
  31 
  32 #if defined _WIN32 && ! defined __CYGWIN__
  33 /* Get declarations of the native Windows API functions.  */
  34 # define WIN32_LEAN_AND_MEAN
  35 # include <windows.h>
  36 /* Get _get_osfhandle.  */
  37 # if GNULIB_MSVC_NOTHROW
  38 #  include "msvc-nothrow.h"
  39 # else
  40 #  include <io.h>
  41 # endif
  42 #endif
  43 
  44 #if !O_BINARY
  45 # define set_binary_mode(f,m) zero ()
  46 static int zero (void) { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
  47 #endif
  48 
  49 /* This test intentionally closes stderr.  So, we arrange to have fd 10
  50    (outside the range of interesting fd's during the test) set up to
  51    duplicate the original stderr.  */
  52 
  53 #define BACKUP_STDERR_FILENO 10
  54 #define ASSERT_STREAM myerr
  55 #include "macros.h"
  56 
  57 static FILE *myerr;
  58 
  59 /* Return true if FD is open.  */
  60 static bool
  61 is_open (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63 #if defined _WIN32 && ! defined __CYGWIN__
  64   /* On native Windows, the initial state of unassigned standard file
  65      descriptors is that they are open but point to an
  66      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  67   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
  68 #else
  69 # ifndef F_GETFL
  70 #  error Please port fcntl to your platform
  71 # endif
  72   return 0 <= fcntl (fd, F_GETFL);
  73 #endif
  74 }
  75 
  76 /* Return true if FD is open and inheritable across exec/spawn.  */
  77 static bool
  78 is_inheritable (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80 #if defined _WIN32 && ! defined __CYGWIN__
  81   /* On native Windows, the initial state of unassigned standard file
  82      descriptors is that they are open but point to an
  83      INVALID_HANDLE_VALUE, and there is no fcntl.  */
  84   HANDLE h = (HANDLE) _get_osfhandle (fd);
  85   DWORD flags;
  86   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
  87     return 0;
  88   return (flags & HANDLE_FLAG_INHERIT) != 0;
  89 #else
  90 # ifndef F_GETFD
  91 #  error Please port fcntl to your platform
  92 # endif
  93   int i = fcntl (fd, F_GETFD);
  94   return 0 <= i && (i & FD_CLOEXEC) == 0;
  95 #endif
  96 }
  97 
  98 /* Return true if FD is open in the given MODE, which is either
  99    O_TEXT or O_BINARY.  */
 100 static bool
 101 is_mode (int fd, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103   int value = set_binary_mode (fd, O_BINARY);
 104   set_binary_mode (fd, value);
 105   return mode == value;
 106 }
 107 
 108 #define witness "test-dup-safer.txt"
 109 
 110 int
 111 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113   int i;
 114   int fd;
 115   int bad_fd = getdtablesize ();
 116 
 117   /* We close fd 2 later, so save it in fd 10.  */
 118   if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
 119       || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
 120     return 2;
 121 
 122   /* Create file for later checks.  */
 123   fd = creat (witness, 0600);
 124   ASSERT (STDERR_FILENO < fd);
 125 
 126   /* Four iterations, with progressively more standard descriptors
 127      closed.  */
 128   for (i = -1; i <= STDERR_FILENO; i++)
 129     {
 130       if (0 <= i)
 131         ASSERT (close (i) == 0);
 132 
 133       /* Detect errors.  */
 134       errno = 0;
 135       ASSERT (dup (-1) == -1);
 136       ASSERT (errno == EBADF);
 137       errno = 0;
 138       ASSERT (dup (bad_fd) == -1);
 139       ASSERT (errno == EBADF);
 140       close (fd + 1);
 141       errno = 0;
 142       ASSERT (dup (fd + 1) == -1);
 143       ASSERT (errno == EBADF);
 144 
 145       /* Preserve text vs. binary.  */
 146       set_binary_mode (fd, O_BINARY);
 147       ASSERT (dup (fd) == fd + 1);
 148       ASSERT (is_open (fd + 1));
 149       ASSERT (is_inheritable (fd + 1));
 150       ASSERT (is_mode (fd + 1, O_BINARY));
 151 
 152       ASSERT (close (fd + 1) == 0);
 153       set_binary_mode (fd, O_TEXT);
 154       ASSERT (dup (fd) == fd + 1);
 155       ASSERT (is_open (fd + 1));
 156       ASSERT (is_inheritable (fd + 1));
 157       ASSERT (is_mode (fd + 1, O_TEXT));
 158 
 159       /* Create cloexec copy.  */
 160       ASSERT (close (fd + 1) == 0);
 161       ASSERT (fd_safer_flag (dup_cloexec (fd), O_CLOEXEC) == fd + 1);
 162       ASSERT (set_cloexec_flag (fd + 1, true) == 0);
 163       ASSERT (is_open (fd + 1));
 164       ASSERT (!is_inheritable (fd + 1));
 165       ASSERT (close (fd) == 0);
 166 
 167       /* dup always creates inheritable copies.  Also, check that
 168          earliest slot past std fds is used.  */
 169       ASSERT (dup (fd + 1) == fd);
 170       ASSERT (is_open (fd));
 171       ASSERT (is_inheritable (fd));
 172       ASSERT (close (fd + 1) == 0);
 173     }
 174 
 175   /* Cleanup.  */
 176   ASSERT (close (fd) == 0);
 177   ASSERT (unlink (witness) == 0);
 178 
 179   return 0;
 180 }

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