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