Blame gnulib-tests/test-fcntl.c

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