Blame posix/test-errno.c

Packit 6c4009
/* Test that failing system calls do set errno to the correct value.
Packit 6c4009
Packit 6c4009
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <grp.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/ioctl.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <sys/resource.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/statfs.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
Packit 6c4009
/* This is not an exhaustive test: only system calls that can be
Packit 6c4009
   persuaded to fail with a consistent error code and no side effects
Packit 6c4009
   are included.  Usually these are failures due to invalid arguments,
Packit 6c4009
   with errno code EBADF or EINVAL.  The order of argument checks is
Packit 6c4009
   unspecified, so we must take care to provide arguments that only
Packit 6c4009
   allow _one_ failure mode.
Packit 6c4009
Packit 6c4009
   Note that all system calls that can fail with EFAULT are permitted
Packit 6c4009
   to deliver a SIGSEGV signal instead, so we avoid supplying invalid
Packit 6c4009
   pointers in general, and we do not attempt to test system calls
Packit 6c4009
   that can only fail with EFAULT (e.g. gettimeofday, gethostname).
Packit 6c4009
Packit 6c4009
   Also note that root-only system calls (e.g. acct, reboot) may, when
Packit 6c4009
   the test is run as an unprivileged user, fail due to insufficient
Packit 6c4009
   privileges before bothering to do argument checks, so those are not
Packit 6c4009
   tested either.
Packit 6c4009
Packit 6c4009
   Also, system calls that take enum or a set of flags as argument is
Packit 6c4009
   not tested if POSIX doesn't specify exact binary values for all
Packit 6c4009
   flags, and so any value passed to flags may become valid.
Packit 6c4009
Packit 6c4009
   Some tests assume "/bin/sh" names a file that exists and is not a
Packit 6c4009
   directory.  */
Packit 6c4009
Packit 6c4009
#define test_wrp_rv(rtype, prtype, experr, syscall, ...)	\
Packit 6c4009
  (__extension__ ({						\
Packit 6c4009
    errno = 0xdead;						\
Packit 6c4009
    rtype ret = syscall (__VA_ARGS__);				\
Packit 6c4009
    int err = errno;						\
Packit 6c4009
    int fail;							\
Packit 6c4009
    if (ret == (rtype) -1 && err == experr)			\
Packit 6c4009
      fail = 0;							\
Packit 6c4009
    else							\
Packit 6c4009
      {								\
Packit 6c4009
        fail = 1;						\
Packit 6c4009
        if (ret != (rtype) -1)					\
Packit 6c4009
          printf ("FAIL: " #syscall ": didn't fail as expected"	\
Packit 6c4009
               " (return "prtype")\n", ret);			\
Packit 6c4009
        else if (err == 0xdead)					\
Packit 6c4009
          puts("FAIL: " #syscall ": didn't update errno\n");	\
Packit 6c4009
        else if (err != experr)					\
Packit 6c4009
          printf ("FAIL: " #syscall				\
Packit 6c4009
               ": errno is: %d (%s) expected: %d (%s)\n",	\
Packit 6c4009
               err, strerror (err), experr, strerror (experr));	\
Packit 6c4009
      }								\
Packit 6c4009
    fail;							\
Packit 6c4009
  }))
Packit 6c4009
Packit 6c4009
#define test_wrp(experr, syscall, ...)				\
Packit 6c4009
  test_wrp_rv(int, "%d", experr, syscall, __VA_ARGS__)
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  size_t pagesize = sysconf (_SC_PAGESIZE);
Packit 6c4009
  struct statfs sfs;
Packit 6c4009
  struct sockaddr sa;
Packit 6c4009
  socklen_t sl;
Packit 6c4009
  char buf[1];
Packit 6c4009
  struct iovec iov[1] = { { buf, 1 } };
Packit 6c4009
  struct sockaddr_in sin;
Packit 6c4009
  sin.sin_family = AF_INET;
Packit 6c4009
  sin.sin_port = htons (1026);
Packit 6c4009
  sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
Packit 6c4009
  struct msghdr msg;
Packit 6c4009
  memset(&msg, 0, sizeof msg);
Packit 6c4009
  msg.msg_iov = iov;
Packit 6c4009
  msg.msg_iovlen = 1;
Packit 6c4009
Packit 6c4009
  int fails = 0;
Packit 6c4009
  fails |= test_wrp (EBADF, accept, -1, &sa, &sl);
Packit 6c4009
  fails |= test_wrp (EINVAL, access, "/", -1);
Packit 6c4009
  fails |= test_wrp (EBADF, bind, -1, (struct sockaddr *)&sin, sizeof sin);
Packit 6c4009
  fails |= test_wrp (ENOTDIR, chdir, "/bin/sh");
Packit 6c4009
  fails |= test_wrp (EBADF, close, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, connect, -1, (struct sockaddr *)&sin, sizeof sin);
Packit 6c4009
  fails |= test_wrp (EBADF, dup, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, dup2, -1, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, fchdir, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, fchmod, -1, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, fcntl, -1, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, fstatfs, -1, &sfs;;
Packit 6c4009
  fails |= test_wrp (EBADF, fsync, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, ftruncate, -1, 0);
Packit 6c4009
  fails |= test_wrp (EINVAL, getgroups, -1, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, getpeername, -1, &sa, &sl);
Packit 6c4009
  fails |= test_wrp (EBADF, getsockname, -1, &sa, &sl);
Packit 6c4009
  fails |= test_wrp (EBADF, getsockopt, -1, 0, 0, buf, &sl);
Packit 6c4009
  fails |= test_wrp (EBADF, ioctl, -1, TIOCNOTTY);
Packit 6c4009
  fails |= test_wrp (EBADF, listen, -1, 1);
Packit 6c4009
  fails |= test_wrp (EBADF, lseek, -1, 0, 0);
Packit 6c4009
  fails |= test_wrp (EINVAL, madvise, (void *) -1, -1, 0);
Packit 6c4009
  fails |= test_wrp_rv (void *, "%p", EBADF,
Packit 6c4009
                        mmap, 0, pagesize, PROT_READ, MAP_PRIVATE, -1, 0);
Packit 6c4009
  fails |= test_wrp (EINVAL, mprotect, (void *) -1, pagesize, -1);
Packit 6c4009
  fails |= test_wrp (EINVAL, msync, (void *) -1, pagesize, -1);
Packit 6c4009
  fails |= test_wrp (EINVAL, munmap, (void *) -1, 0);
Packit 6c4009
  fails |= test_wrp (EISDIR, open, "/bin", EISDIR, O_WRONLY);
Packit 6c4009
  fails |= test_wrp (EBADF, read, -1, buf, 1);
Packit 6c4009
  fails |= test_wrp (EINVAL, readlink, "/", buf, -1);
Packit 6c4009
  fails |= test_wrp (EBADF, readv, -1, iov, 1);
Packit 6c4009
  fails |= test_wrp (EBADF, recv, -1, buf, 1, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, recvfrom, -1, buf, 1, 0, &sa, &sl);
Packit 6c4009
  fails |= test_wrp (EBADF, recvmsg, -1, &msg, 0);
Packit 6c4009
  fails |= test_wrp (EINVAL, select, -1, 0, 0, 0, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, send, -1, buf, 1, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, sendmsg, -1, &msg, 0);
Packit 6c4009
  fails |= test_wrp (EBADF, sendto, -1, buf, 1, 0, &sa, sl);
Packit 6c4009
  fails |= test_wrp (EBADF, setsockopt, -1, 0, 0, buf, sizeof (*buf));
Packit 6c4009
  fails |= test_wrp (EBADF, shutdown, -1, SHUT_RD);
Packit 6c4009
  fails |= test_wrp (EBADF, write, -1, "Hello", sizeof ("Hello") );
Packit 6c4009
  fails |= test_wrp (EBADF, writev, -1, iov, 1 );
Packit 6c4009
Packit 6c4009
  return fails;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include "support/test-driver.c"