From: Bruno Haible Date: Sun, 23 Aug 2009 22:19:10 +0000 (+0200) Subject: Tests for module 'dup3'. X-Git-Tag: v0.1~5600 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=b6dfa79ff86b50398ad397c4c43954d005866ce9;p=gnulib.git Tests for module 'dup3'. --- diff --git a/ChangeLog b/ChangeLog index 80a2e9687..9c9e8270e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-08-23 Bruno Haible + Tests for module 'dup3'. + * modules/dup3-tests: New file. + * tests/test-dup3.c: New file. + New module 'dup3'. * lib/unistd.in.h (dup3): New declaration. * lib/dup3.c: New file. diff --git a/modules/dup3-tests b/modules/dup3-tests new file mode 100644 index 000000000..3f4d96fa5 --- /dev/null +++ b/modules/dup3-tests @@ -0,0 +1,11 @@ +Files: +tests/test-dup3.c + +Depends-on: +open + +configure.ac: + +Makefile.am: +TESTS += test-dup3 +check_PROGRAMS += test-dup3 diff --git a/tests/test-dup3.c b/tests/test-dup3.c new file mode 100644 index 000000000..9c88e75b1 --- /dev/null +++ b/tests/test-dup3.c @@ -0,0 +1,167 @@ +/* Test duplicating file descriptors. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Eric Blake , 2009, + and Bruno Haible , 2009. */ + +#include + +#include + +#include +#include +#include +#include +#include + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Get declarations of the Win32 API functions. */ +# define WIN32_LEAN_AND_MEAN +# include +#endif + +#include "binary-io.h" + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +/* Return true if FD is open. */ +static bool +is_open (int fd) +{ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* On Win32, the initial state of unassigned standard file + descriptors is that they are open but point to an + INVALID_HANDLE_VALUE, and there is no fcntl. */ + return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE; +#else +# ifndef F_GETFL +# error Please port fcntl to your platform +# endif + return 0 <= fcntl (fd, F_GETFL); +#endif +} + +/* Return true if FD is not inherited to child processes. */ +static bool +is_cloexec (int fd) +{ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + HANDLE h = (HANDLE) _get_osfhandle (fd); + DWORD flags; + ASSERT (GetHandleInformation (h, &flags)); + return (flags & HANDLE_FLAG_INHERIT) == 0; +#else + int flags; + ASSERT ((flags = fcntl (fd, F_GETFD)) >= 0); + return (flags & FD_CLOEXEC) != 0; +#endif +} + +int +main () +{ + int use_cloexec; + +#if defined O_CLOEXEC + for (use_cloexec = 0; use_cloexec <= 1; use_cloexec++) +#else + use_cloexec = 0; +#endif + { + const char *file = "test-dup3.tmp"; + int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600); + int o_flags; + char buffer[1]; + + o_flags = 0; +#if defined O_CLOEXEC + if (use_cloexec) + o_flags |= O_CLOEXEC; +#endif + + /* Assume std descriptors were provided by invoker. */ + ASSERT (STDERR_FILENO < fd); + ASSERT (is_open (fd)); + /* Ignore any other fd's leaked into this process. */ + close (fd + 1); + close (fd + 2); + ASSERT (!is_open (fd + 1)); + ASSERT (!is_open (fd + 2)); + + /* Assigning to self is invalid. */ + errno = 0; + ASSERT (dup3 (fd, fd, o_flags) == -1); + ASSERT (errno == EINVAL); + ASSERT (is_open (fd)); + + /* If the source is not open, then the destination is unaffected. */ + errno = 0; + ASSERT (dup3 (fd + 1, fd + 2, o_flags) == -1); + ASSERT (errno == EBADF); + ASSERT (!is_open (fd + 2)); + errno = 0; + ASSERT (dup3 (fd + 1, fd, o_flags) == -1); + ASSERT (errno == EBADF); + ASSERT (is_open (fd)); + + /* The destination must be valid. */ + errno = 0; + ASSERT (dup3 (fd, -2, o_flags) == -1); + ASSERT (errno == EBADF); + errno = 0; + ASSERT (dup3 (fd, 10000000, o_flags) == -1); + ASSERT (errno == EBADF); + + /* Using dup3 can skip fds. */ + ASSERT (dup3 (fd, fd + 2, o_flags) == fd + 2); + ASSERT (is_open (fd)); + ASSERT (!is_open (fd + 1)); + ASSERT (is_open (fd + 2)); + if (use_cloexec) + ASSERT (is_cloexec (fd + 2)); + else + ASSERT (!is_cloexec (fd + 2)); + + /* Verify that dup3 closes the previous occupant of a fd. */ + ASSERT (open ("/dev/null", O_WRONLY, 0600) == fd + 1); + ASSERT (dup3 (fd + 1, fd, o_flags) == fd); + ASSERT (close (fd + 1) == 0); + ASSERT (write (fd, "1", 1) == 1); + ASSERT (dup3 (fd + 2, fd, o_flags) == fd); + ASSERT (lseek (fd, 0, SEEK_END) == 0); + ASSERT (write (fd + 2, "2", 1) == 1); + ASSERT (lseek (fd, 0, SEEK_SET) == 0); + ASSERT (read (fd, buffer, 1) == 1); + ASSERT (*buffer == '2'); + + /* Clean up. */ + ASSERT (close (fd + 2) == 0); + ASSERT (close (fd) == 0); + ASSERT (unlink (file) == 0); + } + + return 0; +}