Blame gl/tests/test-fcntl.c

Packit aea12f
/* Test of fcntl(2).
Packit Service 991b93
   Copyright (C) 2009-2020 Free Software Foundation, Inc.
Packit aea12f
Packit aea12f
   This program is free software: you can redistribute it and/or modify
Packit aea12f
   it under the terms of the GNU General Public License as published by
Packit aea12f
   the Free Software Foundation; either version 3 of the License, or
Packit aea12f
   (at your option) any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit aea12f
   GNU General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License
Packit aea12f
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
/* Written by Eric Blake <ebb9@byu.net>, 2009.  */
Packit aea12f
Packit aea12f
#include <config.h>
Packit aea12f
Packit aea12f
/* Specification.  */
Packit aea12f
#include <fcntl.h>
Packit aea12f
Packit aea12f
#include "signature.h"
Packit aea12f
SIGNATURE_CHECK (fcntl, int, (int, int, ...));
Packit aea12f
Packit aea12f
/* Helpers.  */
Packit aea12f
#include <errno.h>
Packit aea12f
#include <stdarg.h>
Packit aea12f
#include <stdbool.h>
Packit aea12f
#include <unistd.h>
Packit aea12f
Packit aea12f
#if defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
/* Get declarations of the native Windows API functions.  */
Packit aea12f
# define WIN32_LEAN_AND_MEAN
Packit aea12f
# include <windows.h>
Packit aea12f
/* Get _get_osfhandle.  */
Packit aea12f
# if GNULIB_MSVC_NOTHROW
Packit aea12f
#  include "msvc-nothrow.h"
Packit aea12f
# else
Packit aea12f
#  include <io.h>
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#include "binary-io.h"
Packit aea12f
#include "macros.h"
Packit aea12f
Packit aea12f
#if !O_BINARY
Packit aea12f
# define setmode(f,m) zero ()
Packit aea12f
static int zero (void) { return 0; }
Packit aea12f
#endif
Packit aea12f
Packit aea12f
/* Return true if FD is open.  */
Packit aea12f
static bool
Packit aea12f
is_open (int fd)
Packit aea12f
{
Packit aea12f
#if defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
  /* On native Windows, the initial state of unassigned standard file
Packit aea12f
     descriptors is that they are open but point to an
Packit aea12f
     INVALID_HANDLE_VALUE, and there is no fcntl.  */
Packit aea12f
  return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
Packit aea12f
#else
Packit aea12f
# ifndef F_GETFL
Packit aea12f
#  error Please port fcntl to your platform
Packit aea12f
# endif
Packit aea12f
  return 0 <= fcntl (fd, F_GETFL);
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return true if FD is open and inheritable across exec/spawn.  */
Packit aea12f
static bool
Packit aea12f
is_inheritable (int fd)
Packit aea12f
{
Packit aea12f
#if defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
  /* On native Windows, the initial state of unassigned standard file
Packit aea12f
     descriptors is that they are open but point to an
Packit aea12f
     INVALID_HANDLE_VALUE, and there is no fcntl.  */
Packit aea12f
  HANDLE h = (HANDLE) _get_osfhandle (fd);
Packit aea12f
  DWORD flags;
Packit aea12f
  if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
Packit aea12f
    return false;
Packit aea12f
  return (flags & HANDLE_FLAG_INHERIT) != 0;
Packit aea12f
#else
Packit aea12f
# ifndef F_GETFD
Packit aea12f
#  error Please port fcntl to your platform
Packit aea12f
# endif
Packit aea12f
  int i = fcntl (fd, F_GETFD);
Packit aea12f
  return 0 <= i && (i & FD_CLOEXEC) == 0;
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Return non-zero if FD is open in the given MODE, which is either
Packit aea12f
   O_TEXT or O_BINARY.  */
Packit aea12f
static bool
Packit aea12f
is_mode (int fd, int mode)
Packit aea12f
{
Packit aea12f
  int value = setmode (fd, O_BINARY);
Packit aea12f
  setmode (fd, value);
Packit aea12f
  return mode == value;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Since native fcntl can have more supported operations than our
Packit aea12f
   replacement is aware of, and since various operations assign
Packit aea12f
   different types to the vararg argument, a wrapper around fcntl must
Packit aea12f
   be able to pass a vararg of unknown type on through to the original
Packit aea12f
   fcntl.  Make sure that this works properly: func1 behaves like the
Packit aea12f
   original fcntl interpreting the vararg as an int or a pointer to a
Packit aea12f
   struct, and func2 behaves like rpl_fcntl that doesn't know what
Packit aea12f
   type to forward.  */
Packit aea12f
struct dummy_struct
Packit aea12f
{
Packit aea12f
  long filler;
Packit aea12f
  int value;
Packit aea12f
};
Packit aea12f
static int
Packit aea12f
func1 (int a, ...)
Packit aea12f
{
Packit aea12f
  va_list arg;
Packit aea12f
  int i;
Packit aea12f
  va_start (arg, a);
Packit aea12f
  if (a < 4)
Packit aea12f
    i = va_arg (arg, int);
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      struct dummy_struct *s = va_arg (arg, struct dummy_struct *);
Packit aea12f
      i = s->value;
Packit aea12f
    }
Packit aea12f
  va_end (arg);
Packit aea12f
  return i;
Packit aea12f
}
Packit aea12f
static int
Packit aea12f
func2 (int a, ...)
Packit aea12f
{
Packit aea12f
  va_list arg;
Packit aea12f
  void *p;
Packit aea12f
  va_start (arg, a);
Packit aea12f
  p = va_arg (arg, void *);
Packit aea12f
  va_end (arg);
Packit aea12f
  return func1 (a, p);
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Ensure that all supported fcntl actions are distinct, and
Packit aea12f
   usable in preprocessor expressions.  */
Packit aea12f
static void
Packit aea12f
check_flags (void)
Packit aea12f
{
Packit aea12f
  switch (0)
Packit aea12f
    {
Packit aea12f
    case F_DUPFD:
Packit aea12f
#if F_DUPFD
Packit aea12f
#endif
Packit aea12f
Packit aea12f
    case F_DUPFD_CLOEXEC:
Packit aea12f
#if F_DUPFD_CLOEXEC
Packit aea12f
#endif
Packit aea12f
Packit aea12f
    case F_GETFD:
Packit aea12f
#if F_GETFD
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETFD
Packit aea12f
    case F_SETFD:
Packit aea12f
# if F_SETFD
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_GETFL
Packit aea12f
    case F_GETFL:
Packit aea12f
# if F_GETFL
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETFL
Packit aea12f
    case F_SETFL:
Packit aea12f
# if F_SETFL
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_GETOWN
Packit aea12f
    case F_GETOWN:
Packit aea12f
# if F_GETOWN
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETOWN
Packit aea12f
    case F_SETOWN:
Packit aea12f
# if F_SETOWN
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_GETLK
Packit aea12f
    case F_GETLK:
Packit aea12f
# if F_GETLK
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETLK
Packit aea12f
    case F_SETLK:
Packit aea12f
# if F_SETLK
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETLKW
Packit aea12f
    case F_SETLKW:
Packit aea12f
# if F_SETLKW
Packit aea12f
# endif
Packit aea12f
#endif
Packit aea12f
Packit aea12f
      ;
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
Packit aea12f
int
Packit aea12f
main (void)
Packit aea12f
{
Packit aea12f
  const char *file = "test-fcntl.tmp";
Packit aea12f
  int fd;
Packit aea12f
  int bad_fd = getdtablesize ();
Packit aea12f
Packit aea12f
  /* Sanity check that rpl_fcntl is likely to work.  */
Packit aea12f
  ASSERT (func2 (1, 2) == 2);
Packit aea12f
  ASSERT (func2 (2, -2) == -2);
Packit aea12f
  ASSERT (func2 (3, 0x80000000) == 0x80000000);
Packit aea12f
  {
Packit aea12f
    struct dummy_struct s = { 0L, 4 };
Packit aea12f
    ASSERT (func2 (4, &s) == 4);
Packit aea12f
  }
Packit aea12f
  check_flags ();
Packit aea12f
Packit aea12f
  /* Assume std descriptors were provided by invoker, and ignore fds
Packit aea12f
     that might have been inherited.  */
Packit aea12f
  fd = creat (file, 0600);
Packit aea12f
  ASSERT (STDERR_FILENO < fd);
Packit aea12f
  close (fd + 1);
Packit aea12f
  close (fd + 2);
Packit aea12f
Packit aea12f
  /* For F_DUPFD*, the source must be valid.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_DUPFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_DUPFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_DUPFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_DUPFD_CLOEXEC, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_DUPFD_CLOEXEC, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_DUPFD_CLOEXEC, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
Packit aea12f
  /* For F_DUPFD*, the destination must be valid.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD, -1) == -1);
Packit aea12f
  ASSERT (errno == EINVAL);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD, bad_fd) == -1);
Packit aea12f
  ASSERT (errno == EINVAL);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, -1) == -1);
Packit aea12f
  ASSERT (errno == EINVAL);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, bad_fd) == -1);
Packit aea12f
  ASSERT (errno == EINVAL
Packit aea12f
          || errno == EMFILE /* WSL */);
Packit aea12f
Packit aea12f
  /* For F_DUPFD*, check for correct inheritance, as well as
Packit aea12f
     preservation of text vs. binary.  */
Packit aea12f
  setmode (fd, O_BINARY);
Packit aea12f
  ASSERT (is_open (fd));
Packit aea12f
  ASSERT (!is_open (fd + 1));
Packit aea12f
  ASSERT (!is_open (fd + 2));
Packit aea12f
  ASSERT (is_inheritable (fd));
Packit aea12f
  ASSERT (is_mode (fd, O_BINARY));
Packit aea12f
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD, fd) == fd + 1);
Packit aea12f
  ASSERT (is_open (fd));
Packit aea12f
  ASSERT (is_open (fd + 1));
Packit aea12f
  ASSERT (!is_open (fd + 2));
Packit aea12f
  ASSERT (is_inheritable (fd + 1));
Packit aea12f
  ASSERT (is_mode (fd, O_BINARY));
Packit aea12f
  ASSERT (is_mode (fd + 1, O_BINARY));
Packit aea12f
  ASSERT (close (fd + 1) == 0);
Packit aea12f
Packit aea12f
  ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, fd + 2) == fd + 2);
Packit aea12f
  ASSERT (is_open (fd));
Packit aea12f
  ASSERT (!is_open (fd + 1));
Packit aea12f
  ASSERT (is_open (fd + 2));
Packit aea12f
  ASSERT (is_inheritable (fd));
Packit aea12f
  ASSERT (!is_inheritable (fd + 2));
Packit aea12f
  ASSERT (is_mode (fd, O_BINARY));
Packit aea12f
  ASSERT (is_mode (fd + 2, O_BINARY));
Packit aea12f
  ASSERT (close (fd) == 0);
Packit aea12f
Packit aea12f
  setmode (fd + 2, O_TEXT);
Packit aea12f
  ASSERT (fcntl (fd + 2, F_DUPFD, fd + 1) == fd + 1);
Packit aea12f
  ASSERT (!is_open (fd));
Packit aea12f
  ASSERT (is_open (fd + 1));
Packit aea12f
  ASSERT (is_open (fd + 2));
Packit aea12f
  ASSERT (is_inheritable (fd + 1));
Packit aea12f
  ASSERT (!is_inheritable (fd + 2));
Packit aea12f
  ASSERT (is_mode (fd + 1, O_TEXT));
Packit aea12f
  ASSERT (is_mode (fd + 2, O_TEXT));
Packit aea12f
  ASSERT (close (fd + 1) == 0);
Packit aea12f
Packit aea12f
  ASSERT (fcntl (fd + 2, F_DUPFD_CLOEXEC, 0) == fd);
Packit aea12f
  ASSERT (is_open (fd));
Packit aea12f
  ASSERT (!is_open (fd + 1));
Packit aea12f
  ASSERT (is_open (fd + 2));
Packit aea12f
  ASSERT (!is_inheritable (fd));
Packit aea12f
  ASSERT (!is_inheritable (fd + 2));
Packit aea12f
  ASSERT (is_mode (fd, O_TEXT));
Packit aea12f
  ASSERT (is_mode (fd + 2, O_TEXT));
Packit aea12f
  ASSERT (close (fd + 2) == 0);
Packit aea12f
Packit aea12f
  /* Test F_GETFD on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_GETFD) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_GETFD) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_GETFD) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
Packit aea12f
  /* Test F_GETFD, the FD_CLOEXEC bit.  */
Packit aea12f
  {
Packit aea12f
    int result = fcntl (fd, F_GETFD);
Packit aea12f
    ASSERT (0 <= result);
Packit aea12f
    ASSERT ((result & FD_CLOEXEC) == FD_CLOEXEC);
Packit aea12f
    ASSERT (dup (fd) == fd + 1);
Packit aea12f
    result = fcntl (fd + 1, F_GETFD);
Packit aea12f
    ASSERT (0 <= result);
Packit aea12f
    ASSERT ((result & FD_CLOEXEC) == 0);
Packit aea12f
    ASSERT (close (fd + 1) == 0);
Packit aea12f
  }
Packit aea12f
Packit aea12f
#ifdef F_SETFD
Packit aea12f
  /* Test F_SETFD on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_SETFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_SETFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_SETFD, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_GETFL
Packit aea12f
  /* Test F_GETFL on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_GETFL) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_GETFL) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_GETFL) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETFL
Packit aea12f
  /* Test F_SETFL on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_SETFL, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_SETFL, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_SETFL, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_GETOWN
Packit aea12f
  /* Test F_GETOWN on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_GETOWN) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_GETOWN) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_GETOWN) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#ifdef F_SETOWN
Packit aea12f
  /* Test F_SETFL on invalid file descriptors.  */
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (-1, F_SETOWN, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (fd + 1, F_SETOWN, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
  errno = 0;
Packit aea12f
  ASSERT (fcntl (bad_fd, F_SETOWN, 0) == -1);
Packit aea12f
  ASSERT (errno == EBADF);
Packit aea12f
#endif
Packit aea12f
Packit aea12f
  /* Cleanup.  */
Packit aea12f
  ASSERT (close (fd) == 0);
Packit aea12f
  ASSERT (unlink (file) == 0);
Packit aea12f
Packit aea12f
  return 0;
Packit aea12f
}