Blame gnulib-tests/test-fcntl.c

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