(root)/
sed-4.9/
gnulib-tests/
test-fcntl.c
       1  /* Test of fcntl(2).
       2     Copyright (C) 2009-2022 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  /* Specification.  */
      22  #include <fcntl.h>
      23  
      24  #include "signature.h"
      25  SIGNATURE_CHECK (fcntl, int, (int, int, ...));
      26  
      27  /* Helpers.  */
      28  #include <errno.h>
      29  #include <stdarg.h>
      30  #include <unistd.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  #include "binary-io.h"
      45  #include "macros.h"
      46  
      47  #if !O_BINARY
      48  # define set_binary_mode(f,m) zero ()
      49  static int zero (void) { return 0; }
      50  #endif
      51  
      52  /* Return true if FD is open.  */
      53  static bool
      54  is_open (int fd)
      55  {
      56  #if defined _WIN32 && ! defined __CYGWIN__
      57    /* On native Windows, the initial state of unassigned standard file
      58       descriptors is that they are open but point to an
      59       INVALID_HANDLE_VALUE, and there is no fcntl.  */
      60    return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
      61  #else
      62  # ifndef F_GETFL
      63  #  error Please port fcntl to your platform
      64  # endif
      65    return 0 <= fcntl (fd, F_GETFL);
      66  #endif
      67  }
      68  
      69  /* Return true if FD is open and inheritable across exec/spawn.  */
      70  static bool
      71  is_inheritable (int fd)
      72  {
      73  #if defined _WIN32 && ! defined __CYGWIN__
      74    /* On native Windows, the initial state of unassigned standard file
      75       descriptors is that they are open but point to an
      76       INVALID_HANDLE_VALUE, and there is no fcntl.  */
      77    HANDLE h = (HANDLE) _get_osfhandle (fd);
      78    DWORD flags;
      79    if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
      80      return false;
      81    return (flags & HANDLE_FLAG_INHERIT) != 0;
      82  #else
      83  # ifndef F_GETFD
      84  #  error Please port fcntl to your platform
      85  # endif
      86    int i = fcntl (fd, F_GETFD);
      87    return 0 <= i && (i & FD_CLOEXEC) == 0;
      88  #endif
      89  }
      90  
      91  /* Return non-zero if FD is open in the given MODE, which is either
      92     O_TEXT or O_BINARY.  */
      93  static bool
      94  is_mode (int fd, int mode)
      95  {
      96    int value = set_binary_mode (fd, O_BINARY);
      97    set_binary_mode (fd, value);
      98    return mode == value;
      99  }
     100  
     101  /* Since native fcntl can have more supported operations than our
     102     replacement is aware of, and since various operations assign
     103     different types to the vararg argument, a wrapper around fcntl must
     104     be able to pass a vararg of unknown type on through to the original
     105     fcntl.  Make sure that this works properly: func1 behaves like the
     106     original fcntl interpreting the vararg as an int or a pointer to a
     107     struct, and func2 behaves like rpl_fcntl that doesn't know what
     108     type to forward.  */
     109  struct dummy_struct
     110  {
     111    long filler;
     112    int value;
     113  };
     114  static int
     115  func1 (int a, ...)
     116  {
     117    va_list arg;
     118    int i;
     119    va_start (arg, a);
     120    if (a < 4)
     121      i = va_arg (arg, int);
     122    else
     123      {
     124        struct dummy_struct *s = va_arg (arg, struct dummy_struct *);
     125        i = s->value;
     126      }
     127    va_end (arg);
     128    return i;
     129  }
     130  static int
     131  func2 (int a, ...)
     132  {
     133    va_list arg;
     134    void *p;
     135    va_start (arg, a);
     136    p = va_arg (arg, void *);
     137    va_end (arg);
     138    return func1 (a, p);
     139  }
     140  
     141  /* Ensure that all supported fcntl actions are distinct, and
     142     usable in preprocessor expressions.  */
     143  static void
     144  check_flags (void)
     145  {
     146    switch (0)
     147      {
     148      case F_DUPFD:
     149  #if F_DUPFD
     150  #endif
     151  
     152      case F_DUPFD_CLOEXEC:
     153  #if F_DUPFD_CLOEXEC
     154  #endif
     155  
     156      case F_GETFD:
     157  #if F_GETFD
     158  #endif
     159  
     160  #ifdef F_SETFD
     161      case F_SETFD:
     162  # if F_SETFD
     163  # endif
     164  #endif
     165  
     166  #ifdef F_GETFL
     167      case F_GETFL:
     168  # if F_GETFL
     169  # endif
     170  #endif
     171  
     172  #ifdef F_SETFL
     173      case F_SETFL:
     174  # if F_SETFL
     175  # endif
     176  #endif
     177  
     178  #ifdef F_GETOWN
     179      case F_GETOWN:
     180  # if F_GETOWN
     181  # endif
     182  #endif
     183  
     184  #ifdef F_SETOWN
     185      case F_SETOWN:
     186  # if F_SETOWN
     187  # endif
     188  #endif
     189  
     190  #ifdef F_GETLK
     191      case F_GETLK:
     192  # if F_GETLK
     193  # endif
     194  #endif
     195  
     196  #ifdef F_SETLK
     197      case F_SETLK:
     198  # if F_SETLK
     199  # endif
     200  #endif
     201  
     202  #ifdef F_SETLKW
     203      case F_SETLKW:
     204  # if F_SETLKW
     205  # endif
     206  #endif
     207  
     208      default:
     209        ;
     210      }
     211  }
     212  
     213  int
     214  main (int argc, char *argv[])
     215  {
     216    if (argc > 1)
     217      /* child process */
     218      return (is_open (10) ? 42 : 0);
     219  
     220    const char *file = "test-fcntl.tmp";
     221    int fd;
     222    int bad_fd = getdtablesize ();
     223  
     224    /* Sanity check that rpl_fcntl is likely to work.  */
     225    ASSERT (func2 (1, 2) == 2);
     226    ASSERT (func2 (2, -2) == -2);
     227    ASSERT (func2 (3, 0x80000000) == 0x80000000);
     228    {
     229      struct dummy_struct s = { 0L, 4 };
     230      ASSERT (func2 (4, &s) == 4);
     231    }
     232    check_flags ();
     233  
     234    /* Assume std descriptors were provided by invoker, and ignore fds
     235       that might have been inherited.  */
     236    fd = creat (file, 0600);
     237    ASSERT (STDERR_FILENO < fd);
     238    close (fd + 1);
     239    close (fd + 2);
     240  
     241    /* For F_DUPFD*, the source must be valid.  */
     242    errno = 0;
     243    ASSERT (fcntl (-1, F_DUPFD, 0) == -1);
     244    ASSERT (errno == EBADF);
     245    errno = 0;
     246    ASSERT (fcntl (fd + 1, F_DUPFD, 0) == -1);
     247    ASSERT (errno == EBADF);
     248    errno = 0;
     249    ASSERT (fcntl (bad_fd, F_DUPFD, 0) == -1);
     250    ASSERT (errno == EBADF);
     251    errno = 0;
     252    ASSERT (fcntl (-1, F_DUPFD_CLOEXEC, 0) == -1);
     253    ASSERT (errno == EBADF);
     254    errno = 0;
     255    ASSERT (fcntl (fd + 1, F_DUPFD_CLOEXEC, 0) == -1);
     256    ASSERT (errno == EBADF);
     257    errno = 0;
     258    ASSERT (fcntl (bad_fd, F_DUPFD_CLOEXEC, 0) == -1);
     259    ASSERT (errno == EBADF);
     260  
     261    /* For F_DUPFD*, the destination must be valid.  */
     262    errno = 0;
     263    ASSERT (fcntl (fd, F_DUPFD, -1) == -1);
     264    ASSERT (errno == EINVAL);
     265    errno = 0;
     266    ASSERT (fcntl (fd, F_DUPFD, bad_fd) == -1);
     267    ASSERT (errno == EINVAL);
     268    errno = 0;
     269    ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, -1) == -1);
     270    ASSERT (errno == EINVAL);
     271    errno = 0;
     272    ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, bad_fd) == -1);
     273    ASSERT (errno == EINVAL
     274            || errno == EMFILE /* WSL */);
     275  
     276    /* For F_DUPFD*, check for correct inheritance, as well as
     277       preservation of text vs. binary.  */
     278    set_binary_mode (fd, O_BINARY);
     279    ASSERT (is_open (fd));
     280    ASSERT (!is_open (fd + 1));
     281    ASSERT (!is_open (fd + 2));
     282    ASSERT (is_inheritable (fd));
     283    ASSERT (is_mode (fd, O_BINARY));
     284  
     285    ASSERT (fcntl (fd, F_DUPFD, fd) == fd + 1);
     286    ASSERT (is_open (fd));
     287    ASSERT (is_open (fd + 1));
     288    ASSERT (!is_open (fd + 2));
     289    ASSERT (is_inheritable (fd + 1));
     290    ASSERT (is_mode (fd, O_BINARY));
     291    ASSERT (is_mode (fd + 1, O_BINARY));
     292    ASSERT (close (fd + 1) == 0);
     293  
     294    ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, fd + 2) == fd + 2);
     295    ASSERT (is_open (fd));
     296    ASSERT (!is_open (fd + 1));
     297    ASSERT (is_open (fd + 2));
     298    ASSERT (is_inheritable (fd));
     299    ASSERT (!is_inheritable (fd + 2));
     300    ASSERT (is_mode (fd, O_BINARY));
     301    ASSERT (is_mode (fd + 2, O_BINARY));
     302    ASSERT (close (fd) == 0);
     303  
     304    set_binary_mode (fd + 2, O_TEXT);
     305    ASSERT (fcntl (fd + 2, F_DUPFD, fd + 1) == fd + 1);
     306    ASSERT (!is_open (fd));
     307    ASSERT (is_open (fd + 1));
     308    ASSERT (is_open (fd + 2));
     309    ASSERT (is_inheritable (fd + 1));
     310    ASSERT (!is_inheritable (fd + 2));
     311    ASSERT (is_mode (fd + 1, O_TEXT));
     312    ASSERT (is_mode (fd + 2, O_TEXT));
     313    ASSERT (close (fd + 1) == 0);
     314  
     315    ASSERT (fcntl (fd + 2, F_DUPFD_CLOEXEC, 0) == fd);
     316    ASSERT (is_open (fd));
     317    ASSERT (!is_open (fd + 1));
     318    ASSERT (is_open (fd + 2));
     319    ASSERT (!is_inheritable (fd));
     320    ASSERT (!is_inheritable (fd + 2));
     321    ASSERT (is_mode (fd, O_TEXT));
     322    ASSERT (is_mode (fd + 2, O_TEXT));
     323    ASSERT (close (fd + 2) == 0);
     324  
     325    /* Test F_GETFD on invalid file descriptors.  */
     326    errno = 0;
     327    ASSERT (fcntl (-1, F_GETFD) == -1);
     328    ASSERT (errno == EBADF);
     329    errno = 0;
     330    ASSERT (fcntl (fd + 1, F_GETFD) == -1);
     331    ASSERT (errno == EBADF);
     332    errno = 0;
     333    ASSERT (fcntl (bad_fd, F_GETFD) == -1);
     334    ASSERT (errno == EBADF);
     335  
     336    /* Test F_GETFD, the FD_CLOEXEC bit.  */
     337    {
     338      int result = fcntl (fd, F_GETFD);
     339      ASSERT (0 <= result);
     340      ASSERT ((result & FD_CLOEXEC) == FD_CLOEXEC);
     341      ASSERT (dup (fd) == fd + 1);
     342      result = fcntl (fd + 1, F_GETFD);
     343      ASSERT (0 <= result);
     344      ASSERT ((result & FD_CLOEXEC) == 0);
     345      ASSERT (close (fd + 1) == 0);
     346    }
     347  
     348  #ifdef F_SETFD
     349    /* Test F_SETFD on invalid file descriptors.  */
     350    errno = 0;
     351    ASSERT (fcntl (-1, F_SETFD, 0) == -1);
     352    ASSERT (errno == EBADF);
     353    errno = 0;
     354    ASSERT (fcntl (fd + 1, F_SETFD, 0) == -1);
     355    ASSERT (errno == EBADF);
     356    errno = 0;
     357    ASSERT (fcntl (bad_fd, F_SETFD, 0) == -1);
     358    ASSERT (errno == EBADF);
     359  #endif
     360  
     361  #ifdef F_GETFL
     362    /* Test F_GETFL on invalid file descriptors.  */
     363    errno = 0;
     364    ASSERT (fcntl (-1, F_GETFL) == -1);
     365    ASSERT (errno == EBADF);
     366    errno = 0;
     367    ASSERT (fcntl (fd + 1, F_GETFL) == -1);
     368    ASSERT (errno == EBADF);
     369    errno = 0;
     370    ASSERT (fcntl (bad_fd, F_GETFL) == -1);
     371    ASSERT (errno == EBADF);
     372  #endif
     373  
     374  #ifdef F_SETFL
     375    /* Test F_SETFL on invalid file descriptors.  */
     376    errno = 0;
     377    ASSERT (fcntl (-1, F_SETFL, 0) == -1);
     378    ASSERT (errno == EBADF);
     379    errno = 0;
     380    ASSERT (fcntl (fd + 1, F_SETFL, 0) == -1);
     381    ASSERT (errno == EBADF);
     382    errno = 0;
     383    ASSERT (fcntl (bad_fd, F_SETFL, 0) == -1);
     384    ASSERT (errno == EBADF);
     385  #endif
     386  
     387  #ifdef F_GETOWN
     388    /* Test F_GETOWN on invalid file descriptors.  */
     389    errno = 0;
     390    ASSERT (fcntl (-1, F_GETOWN) == -1);
     391    ASSERT (errno == EBADF);
     392    errno = 0;
     393    ASSERT (fcntl (fd + 1, F_GETOWN) == -1);
     394    ASSERT (errno == EBADF);
     395    errno = 0;
     396    ASSERT (fcntl (bad_fd, F_GETOWN) == -1);
     397    ASSERT (errno == EBADF);
     398  #endif
     399  
     400  #ifdef F_SETOWN
     401    /* Test F_SETFL on invalid file descriptors.  */
     402    errno = 0;
     403    ASSERT (fcntl (-1, F_SETOWN, 0) == -1);
     404    ASSERT (errno == EBADF);
     405    errno = 0;
     406    ASSERT (fcntl (fd + 1, F_SETOWN, 0) == -1);
     407    ASSERT (errno == EBADF);
     408    errno = 0;
     409    ASSERT (fcntl (bad_fd, F_SETOWN, 0) == -1);
     410    ASSERT (errno == EBADF);
     411  #endif
     412  
     413    /* Cleanup.  */
     414    ASSERT (close (fd) == 0);
     415    ASSERT (unlink (file) == 0);
     416  
     417    /* Close file descriptors that may have been inherited from the parent
     418       process and that would cause failures below.
     419       Such file descriptors have been seen:
     420         - with GNU make, when invoked as 'make -j N' with j > 1,
     421         - in some versions of the KDE desktop environment,
     422         - on NetBSD,
     423         - in MacPorts with the "trace mode" enabled.
     424     */
     425    (void) close (10);
     426  
     427    /* Test whether F_DUPFD_CLOEXEC is effective.  */
     428    ASSERT (fcntl (1, F_DUPFD_CLOEXEC, 10) >= 0);
     429  #if defined _WIN32 && !defined __CYGWIN__
     430    return _execl ("./test-fcntl", "./test-fcntl", "child", NULL);
     431  #else
     432    return execl ("./test-fcntl", "./test-fcntl", "child", NULL);
     433  #endif
     434  }