(root)/
m4-1.4.19/
tests/
test-dup-safer.c
       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; }
      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)
      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)
      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)
     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)
     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  }