Blame gl/tests/test-cloexec.c

Packit Service 4684c1
/* Test duplicating non-inheritable file descriptors.
Packit Service 4684c1
   Copyright (C) 2009-2020 Free Software Foundation, Inc.
Packit Service 4684c1
Packit Service 4684c1
   This program is free software: you can redistribute it and/or modify
Packit Service 4684c1
   it under the terms of the GNU General Public License as published by
Packit Service 4684c1
   the Free Software Foundation; either version 3 of the License, or
Packit Service 4684c1
   (at your option) any later version.
Packit Service 4684c1
Packit Service 4684c1
   This program is distributed in the hope that it will be useful,
Packit Service 4684c1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 4684c1
   GNU General Public License for more details.
Packit Service 4684c1
Packit Service 4684c1
   You should have received a copy of the GNU General Public License
Packit Service 4684c1
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 4684c1
Packit Service 4684c1
/* Written by Eric Blake <ebb9@byu.net>, 2009.  */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
Packit Service 4684c1
#include "cloexec.h"
Packit Service 4684c1
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <fcntl.h>
Packit Service 4684c1
#include <unistd.h>
Packit Service 4684c1
Packit Service 4684c1
#if defined _WIN32 && ! defined __CYGWIN__
Packit Service 4684c1
/* Get declarations of the native Windows API functions.  */
Packit Service 4684c1
# define WIN32_LEAN_AND_MEAN
Packit Service 4684c1
# include <windows.h>
Packit Service 4684c1
/* Get _get_osfhandle.  */
Packit Service 4684c1
# if GNULIB_MSVC_NOTHROW
Packit Service 4684c1
#  include "msvc-nothrow.h"
Packit Service 4684c1
# else
Packit Service 4684c1
#  include <io.h>
Packit Service 4684c1
# endif
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#include "binary-io.h"
Packit Service 4684c1
#include "macros.h"
Packit Service 4684c1
Packit Service 4684c1
/* Return non-zero if FD is open and inheritable across exec/spawn.  */
Packit Service 4684c1
static int
Packit Service 4684c1
is_inheritable (int fd)
Packit Service 4684c1
{
Packit Service 4684c1
#if defined _WIN32 && ! defined __CYGWIN__
Packit Service 4684c1
  /* On native Windows, the initial state of unassigned standard file
Packit Service 4684c1
     descriptors is that they are open but point to an
Packit Service 4684c1
     INVALID_HANDLE_VALUE, and there is no fcntl.  */
Packit Service 4684c1
  HANDLE h = (HANDLE) _get_osfhandle (fd);
Packit Service 4684c1
  DWORD flags;
Packit Service 4684c1
  if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
Packit Service 4684c1
    return 0;
Packit Service 4684c1
  return (flags & HANDLE_FLAG_INHERIT) != 0;
Packit Service 4684c1
#else
Packit Service 4684c1
# ifndef F_GETFD
Packit Service 4684c1
#  error Please port fcntl to your platform
Packit Service 4684c1
# endif
Packit Service 4684c1
  int i = fcntl (fd, F_GETFD);
Packit Service 4684c1
  return 0 <= i && (i & FD_CLOEXEC) == 0;
Packit Service 4684c1
#endif
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#if !O_BINARY
Packit Service 4684c1
# define setmode(f,m) zero ()
Packit Service 4684c1
static int zero (void) { return 0; }
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
/* Return non-zero if FD is open in the given MODE, which is either
Packit Service 4684c1
   O_TEXT or O_BINARY.  */
Packit Service 4684c1
static int
Packit Service 4684c1
is_mode (int fd, int mode)
Packit Service 4684c1
{
Packit Service 4684c1
  int value = setmode (fd, O_BINARY);
Packit Service 4684c1
  setmode (fd, value);
Packit Service 4684c1
  return mode == value;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
main (void)
Packit Service 4684c1
{
Packit Service 4684c1
  const char *file = "test-cloexec.tmp";
Packit Service 4684c1
  int fd = creat (file, 0600);
Packit Service 4684c1
  int fd2;
Packit Service 4684c1
  int bad_fd = getdtablesize ();
Packit Service 4684c1
Packit Service 4684c1
  /* Assume std descriptors were provided by invoker.  */
Packit Service 4684c1
  ASSERT (STDERR_FILENO < fd);
Packit Service 4684c1
  ASSERT (is_inheritable (fd));
Packit Service 4684c1
Packit Service 4684c1
  /* Normal use of set_cloexec_flag.  */
Packit Service 4684c1
  ASSERT (set_cloexec_flag (fd, true) == 0);
Packit Service 4684c1
#if !(defined _WIN32 && ! defined __CYGWIN__)
Packit Service 4684c1
  ASSERT (!is_inheritable (fd));
Packit Service 4684c1
#endif
Packit Service 4684c1
  ASSERT (set_cloexec_flag (fd, false) == 0);
Packit Service 4684c1
  ASSERT (is_inheritable (fd));
Packit Service 4684c1
Packit Service 4684c1
  /* Normal use of dup_cloexec.  */
Packit Service 4684c1
  fd2 = dup_cloexec (fd);
Packit Service 4684c1
  ASSERT (fd < fd2);
Packit Service 4684c1
  ASSERT (!is_inheritable (fd2));
Packit Service 4684c1
  ASSERT (close (fd) == 0);
Packit Service 4684c1
  ASSERT (dup_cloexec (fd2) == fd);
Packit Service 4684c1
  ASSERT (!is_inheritable (fd));
Packit Service 4684c1
  ASSERT (close (fd2) == 0);
Packit Service 4684c1
Packit Service 4684c1
  /* On systems that distinguish between text and binary mode,
Packit Service 4684c1
     dup_cloexec reuses the mode of the source.  */
Packit Service 4684c1
  setmode (fd, O_BINARY);
Packit Service 4684c1
  ASSERT (is_mode (fd, O_BINARY));
Packit Service 4684c1
  fd2 = dup_cloexec (fd);
Packit Service 4684c1
  ASSERT (fd < fd2);
Packit Service 4684c1
  ASSERT (is_mode (fd2, O_BINARY));
Packit Service 4684c1
  ASSERT (close (fd2) == 0);
Packit Service 4684c1
  setmode (fd, O_TEXT);
Packit Service 4684c1
  ASSERT (is_mode (fd, O_TEXT));
Packit Service 4684c1
  fd2 = dup_cloexec (fd);
Packit Service 4684c1
  ASSERT (fd < fd2);
Packit Service 4684c1
  ASSERT (is_mode (fd2, O_TEXT));
Packit Service 4684c1
  ASSERT (close (fd2) == 0);
Packit Service 4684c1
Packit Service 4684c1
  /* Test error handling.  */
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (set_cloexec_flag (-1, false) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (set_cloexec_flag (bad_fd, false) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (set_cloexec_flag (fd2, false) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (dup_cloexec (-1) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (dup_cloexec (bad_fd) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
  errno = 0;
Packit Service 4684c1
  ASSERT (dup_cloexec (fd2) == -1);
Packit Service 4684c1
  ASSERT (errno == EBADF);
Packit Service 4684c1
Packit Service 4684c1
  /* Clean up.  */
Packit Service 4684c1
  ASSERT (close (fd) == 0);
Packit Service 4684c1
  ASSERT (unlink (file) == 0);
Packit Service 4684c1
Packit Service 4684c1
  return 0;
Packit Service 4684c1
}