summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/socket-client.h57
-rw-r--r--tests/socket-server.h117
-rw-r--r--tests/test-chown.h4
-rw-r--r--tests/test-fclose.c93
-rw-r--r--tests/test-fcntl-h.c82
-rw-r--r--tests/test-getaddrinfo.c2
-rw-r--r--tests/test-getcwd-lgpl.c87
-rw-r--r--tests/test-getcwd.c225
-rw-r--r--tests/test-hash.c14
-rw-r--r--tests/test-lchown.h2
-rw-r--r--tests/test-linkat.c10
-rw-r--r--tests/test-netdb-c++.cc42
-rw-r--r--tests/test-nonblocking-misc.h108
-rw-r--r--tests/test-nonblocking-pipe-child.c50
-rw-r--r--tests/test-nonblocking-pipe-main.c110
-rw-r--r--tests/test-nonblocking-pipe.h38
-rwxr-xr-xtests/test-nonblocking-pipe.sh17
-rw-r--r--tests/test-nonblocking-reader.h200
-rw-r--r--tests/test-nonblocking-socket-child.c52
-rw-r--r--tests/test-nonblocking-socket-main.c121
-rw-r--r--tests/test-nonblocking-socket.h51
-rwxr-xr-xtests/test-nonblocking-socket.sh13
-rw-r--r--tests/test-nonblocking-writer.h186
-rw-r--r--tests/test-nonblocking.c52
-rw-r--r--tests/test-open.h6
-rw-r--r--tests/test-passfd.c19
-rw-r--r--tests/test-pipe2.c40
-rw-r--r--tests/test-renameat.c4
-rw-r--r--tests/test-stdio-c++.cc42
-rw-r--r--tests/test-sys_socket.c14
-rw-r--r--tests/test-sys_uio.c32
31 files changed, 1772 insertions, 118 deletions
diff --git a/tests/socket-client.h b/tests/socket-client.h
new file mode 100644
index 0000000000..ac82463ce1
--- /dev/null
+++ b/tests/socket-client.h
@@ -0,0 +1,57 @@
+/* Create sockets for use in tests (client side).
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2011. */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Creates a client socket, by connecting to a server on the given port. */
+static int
+create_client_socket (int port)
+{
+ int client_socket;
+
+ /* Create a client socket. */
+ client_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ASSERT (client_socket >= 0);
+ /* Connect to the server process at the specified port. */
+ {
+ struct sockaddr_in addr;
+
+ memset (&addr, 0, sizeof (addr)); /* needed on AIX and OSF/1 */
+ addr.sin_family = AF_INET;
+ #if 0 /* Unoptimized */
+ inet_pton (AF_INET, "127.0.0.1", &addr.sin_addr);
+ #elif 0 /* Nearly optimized */
+ addr.sin_addr.s_addr = htonl (0x7F000001); /* 127.0.0.1 */
+ #else /* Fully optimized */
+ {
+ unsigned char dotted[4] = { 127, 0, 0, 1 }; /* 127.0.0.1 */
+ memcpy (&addr.sin_addr.s_addr, dotted, 4);
+ }
+ #endif
+ addr.sin_port = htons (port);
+
+ ASSERT (connect (client_socket,
+ (const struct sockaddr *) &addr, sizeof (addr))
+ == 0);
+ }
+
+ return client_socket;
+}
diff --git a/tests/socket-server.h b/tests/socket-server.h
new file mode 100644
index 0000000000..283ef2fc2a
--- /dev/null
+++ b/tests/socket-server.h
@@ -0,0 +1,117 @@
+/* Create sockets for use in tests (server side).
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2011. */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Creates a server that can be used to listen on incoming
+ connections. It uses the IPv4 protocol.
+ If PORT is 0, a port is assigned by the kernel.
+ Returns the server. Returns the chosen port in *PPORT. */
+static int
+create_server (int port, unsigned int max_backlog, int *pport)
+{
+ int server;
+
+ /* Create a server socket. */
+ server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (server < 0)
+ {
+ fputs ("Skipping test: cannot create server socket: socket() failed\n",
+ stderr);
+ exit (77);
+ }
+ /* Bind it to a local IPv4 address. */
+ if (port != 0)
+ {
+ /* Set an option for the next bind() call: Avoid an EADDRINUSE error
+ in case there are TIME_WAIT or CLOSE_WAIT sockets hanging around on
+ the port. (Sockets in LISTEN or ESTABLISHED state on the same port
+ will still yield an error.) */
+ unsigned int flag = 1;
+ if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR, &flag,
+ sizeof (flag))
+ < 0)
+ {
+ fputs ("Skipping test: cannot create server socket: setsockopt() failed\n",
+ stderr);
+ exit (77);
+ }
+ }
+ {
+ struct sockaddr_in addr;
+
+ memset (&addr, 0, sizeof (addr)); /* needed on AIX and OSF/1 */
+ addr.sin_family = AF_INET;
+ #if 0 /* Unoptimized */
+ inet_pton (AF_INET, "127.0.0.1", &addr.sin_addr);
+ #elif 0 /* Nearly optimized */
+ addr.sin_addr.s_addr = htonl (0x7F000001); /* 127.0.0.1 */
+ #else /* Fully optimized */
+ {
+ unsigned char dotted[4] = { 127, 0, 0, 1 }; /* 127.0.0.1 */
+ memcpy (&addr.sin_addr.s_addr, dotted, 4);
+ }
+ #endif
+ addr.sin_port = htons (port);
+
+ if (bind (server, (const struct sockaddr *) &addr, sizeof (addr)) < 0)
+ {
+ fputs ("Skipping test: cannot create server socket: bind() failed\n",
+ stderr);
+ exit (77);
+ }
+ }
+ if (port == 0)
+ {
+ /* Get the port that was assigned by bind(). */
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof (addr);
+
+ if (getsockname (server, (struct sockaddr *) &addr, &addrlen) < 0)
+ {
+ fputs ("Skipping test: cannot create server socket: getsockname() failed\n",
+ stderr);
+ exit (77);
+ }
+ port = ntohs (addr.sin_port);
+ }
+ /* Start listening for a connection from the child process. */
+ if (listen (server, max_backlog) < 0)
+ {
+ fputs ("Skipping test: cannot create server socket: listen() failed\n",
+ stderr);
+ exit (77);
+ }
+
+ *pport = port;
+ return server;
+}
+
+/* Creates a server socket, by accepting a connection to a server. */
+static int
+create_server_socket (int server)
+{
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof (addr);
+ int connected_socket = accept (server, (struct sockaddr *) &addr, &addrlen);
+ ASSERT (connected_socket >= 0);
+ return connected_socket;
+}
diff --git a/tests/test-chown.h b/tests/test-chown.h
index 7630de48da..85cbb5afc9 100644
--- a/tests/test-chown.h
+++ b/tests/test-chown.h
@@ -38,7 +38,7 @@ test_chown (int (*func) (char const *, uid_t, gid_t), bool print)
int result;
/* Solaris 8 is interesting - if the current process belongs to
- multiple groups, the current directory is owned by a a group that
+ multiple groups, the current directory is owned by a group that
the current process belongs to but different than getegid(), and
the current directory does not have the S_ISGID bit, then regular
files created in the directory belong to the directory's group,
@@ -71,7 +71,7 @@ test_chown (int (*func) (char const *, uid_t, gid_t), bool print)
ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
ASSERT (stat (BASE "dir/file", &st1) == 0);
ASSERT (st1.st_uid != (uid_t) -1);
- ASSERT (st1.st_gid != (uid_t) -1);
+ ASSERT (st1.st_gid != (gid_t) -1);
ASSERT (st1.st_gid == getegid ());
/* Sanity check of error cases. */
diff --git a/tests/test-fclose.c b/tests/test-fclose.c
new file mode 100644
index 0000000000..d9b940619b
--- /dev/null
+++ b/tests/test-fclose.c
@@ -0,0 +1,93 @@
+/* Test of fclose module.
+ Copyright (C) 2011 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, 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, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Eric Blake. */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (fclose, int, (FILE *));
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "macros.h"
+
+#define BASE "test-fclose.t"
+
+int
+main (int argc, char **argv)
+{
+ const char buf[] = "hello world";
+ int fd;
+ int fd2;
+ FILE *f;
+
+ /* Prepare a seekable file. */
+ fd = open (BASE, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ ASSERT (0 <= fd);
+ ASSERT (write (fd, buf, sizeof buf) == sizeof buf);
+ ASSERT (lseek (fd, 1, SEEK_SET) == 1);
+
+ /* Create an output stream visiting the file; when it is closed, all
+ other file descriptors visiting the file must see the new file
+ position. */
+ fd2 = dup (fd);
+ ASSERT (0 <= fd2);
+ f = fdopen (fd2, "w");
+ ASSERT (f);
+ ASSERT (fputc (buf[1], f) == buf[1]);
+ ASSERT (fclose (f) == 0);
+ errno = 0;
+ ASSERT (lseek (fd2, 0, SEEK_CUR) == -1);
+ ASSERT (errno == EBADF);
+ ASSERT (lseek (fd, 0, SEEK_CUR) == 2);
+
+#if GNULIB_FFLUSH
+ /* Likewise for an input stream, but only when we know fflush works
+ on input streams. */
+ fd2 = dup (fd);
+ ASSERT (0 <= fd2);
+ f = fdopen (fd2, "r");
+ ASSERT (f);
+ ASSERT (fgetc (f) == buf[2]);
+ ASSERT (fclose (f) == 0);
+ errno = 0;
+ ASSERT (lseek (fd2, 0, SEEK_CUR) == -1);
+ ASSERT (errno == EBADF);
+ ASSERT (lseek (fd, 0, SEEK_CUR) == 3);
+#endif
+
+ /* Test that fclose() sets errno if someone else closes the stream
+ fd behind the back of stdio. */
+ f = fdopen (fd, "w+");
+ ASSERT (f);
+ ASSERT (close (fd) == 0);
+ errno = 0;
+ ASSERT (fclose (f) == EOF);
+ ASSERT (errno == EBADF);
+
+ /* Clean up. */
+ ASSERT (remove (BASE) == 0);
+
+ return 0;
+}
diff --git a/tests/test-fcntl-h.c b/tests/test-fcntl-h.c
index dd20fbb406..648701ef4b 100644
--- a/tests/test-fcntl-h.c
+++ b/tests/test-fcntl-h.c
@@ -29,10 +29,88 @@ int o = O_DIRECT | O_DIRECTORY | O_DSYNC | O_NDELAY | O_NOATIME | O_NONBLOCK
int sk[] = { SEEK_CUR, SEEK_END, SEEK_SET };
/* Check that the FD_* macros are defined. */
-int fd = FD_CLOEXEC;
+int i = FD_CLOEXEC;
int
main (void)
{
- return 0;
+ /* Ensure no overlap in SEEK_*. */
+ switch (0)
+ {
+ case SEEK_CUR:
+ case SEEK_END:
+ case SEEK_SET:
+ ;
+ }
+
+ /* Ensure no dangerous overlap in non-zero gnulib-defined replacements. */
+ switch (O_RDONLY)
+ {
+ /* Access modes */
+ case O_RDONLY:
+ case O_WRONLY:
+ case O_RDWR:
+#if O_EXEC && O_EXEC != O_RDONLY
+ case O_EXEC:
+#endif
+#if O_SEARCH && O_EXEC != O_SEARCH && O_SEARCH != O_RDONLY
+ case O_SEARCH:
+#endif
+ i = O_ACCMODE == (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH);
+ break;
+
+ /* Everyone should have these */
+ case O_CREAT:
+ case O_EXCL:
+ case O_TRUNC:
+ case O_APPEND:
+ break;
+
+ /* These might be 0 or O_RDONLY, only test non-zero versions. */
+#if O_CLOEXEC
+ case O_CLOEXEC:
+#endif
+#if O_DIRECT
+ case O_DIRECT:
+#endif
+#if O_DIRECTORY
+ case O_DIRECTORY:
+#endif
+#if O_DSYNC
+ case O_DSYNC:
+#endif
+#if O_NOATIME
+ case O_NOATIME:
+#endif
+#if O_NONBLOCK
+ case O_NONBLOCK:
+#endif
+#if O_NOCTTY
+ case O_NOCTTY:
+#endif
+#if O_NOFOLLOW
+ case O_NOFOLLOW:
+#endif
+#if O_NOLINKS
+ case O_NOLINKS:
+#endif
+#if O_RSYNC && O_RSYNC != O_DSYNC
+ case O_RSYNC:
+#endif
+#if O_SYNC && O_SYNC != O_RSYNC
+ case O_SYNC:
+#endif
+#if O_TTY_INIT
+ case O_TTY_INIT:
+#endif
+#if O_BINARY
+ case O_BINARY:
+#endif
+#if O_TEXT
+ case O_TEXT:
+#endif
+ ;
+ }
+
+ return !i;
}
diff --git a/tests/test-getaddrinfo.c b/tests/test-getaddrinfo.c
index 482698937a..d2984e226b 100644
--- a/tests/test-getaddrinfo.c
+++ b/tests/test-getaddrinfo.c
@@ -107,7 +107,7 @@ simple (char const *host, char const *service)
#endif
/* Provide details if errno was set. */
if (res == EAI_SYSTEM)
- dbgprintf ("system error: %s\n", strerror (err));
+ fprintf (stderr, "system error: %s\n", strerror (err));
return 1;
}
diff --git a/tests/test-getcwd-lgpl.c b/tests/test-getcwd-lgpl.c
new file mode 100644
index 0000000000..67ee66d539
--- /dev/null
+++ b/tests/test-getcwd-lgpl.c
@@ -0,0 +1,87 @@
+/* Test of getcwd() function.
+ Copyright (C) 2009-2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (getcwd, char *, (char *, size_t));
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macros.h"
+
+int
+main (int argc, char **argv)
+{
+ char *pwd1;
+ char *pwd2;
+ /* If the user provides an argument, attempt to chdir there first. */
+ if (1 < argc)
+ {
+ if (chdir (argv[1]) == 0)
+ printf ("changed to directory %s\n", argv[1]);
+ }
+
+ pwd1 = getcwd (NULL, 0);
+ ASSERT (pwd1 && *pwd1);
+ if (1 < argc)
+ printf ("cwd=%s\n", pwd1);
+
+ /* Make sure the result is usable. */
+ ASSERT (chdir (pwd1) == 0);
+ ASSERT (chdir (".//./.") == 0);
+
+ /* Make sure that result is normalized. */
+ pwd2 = getcwd (NULL, 0);
+ ASSERT (pwd2);
+ ASSERT (strcmp (pwd1, pwd2) == 0);
+ free (pwd2);
+ {
+ size_t len = strlen (pwd1);
+ ssize_t i = len - 10;
+ if (i < 1)
+ i = 1;
+ pwd2 = getcwd (NULL, len + 1);
+ ASSERT (pwd2);
+ free (pwd2);
+ pwd2 = malloc (len + 2);
+ for ( ; i <= len; i++)
+ {
+ errno = 0;
+ ASSERT (getcwd (pwd2, i) == NULL);
+ ASSERT (errno == ERANGE);
+ errno = 0;
+ ASSERT (getcwd (NULL, i) == NULL);
+ ASSERT (errno == ERANGE);
+ }
+ ASSERT (getcwd (pwd2, len + 1) == pwd2);
+ pwd2[len] = '/';
+ pwd2[len + 1] = '\0';
+ }
+ ASSERT (strstr (pwd2, "/./") == NULL);
+ ASSERT (strstr (pwd2, "/../") == NULL);
+ ASSERT (strstr (pwd2 + 1 + (pwd2[1] == '/'), "//") == NULL);
+
+ free (pwd1);
+ free (pwd2);
+
+ return 0;
+}
diff --git a/tests/test-getcwd.c b/tests/test-getcwd.c
index 18fc74f94b..14a526f65e 100644
--- a/tests/test-getcwd.c
+++ b/tests/test-getcwd.c
@@ -18,59 +18,206 @@
#include <unistd.h>
-#include "signature.h"
-SIGNATURE_CHECK (getcwd, char *, (char *, size_t));
-
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include "macros.h"
-int
-main (int argc, char **argv)
+#if ! HAVE_GETPAGESIZE
+# define getpagesize() 0
+#endif
+
+/* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
+ the 16kB pagesize on ia64 linux. Those conditions make the code below
+ trigger a bug in glibc's getcwd implementation before 2.4.90-10. */
+#define TARGET_LEN (5 * 1024)
+
+/* Keep this test in sync with m4/getcwd-abort-bug.m4. */
+static int
+test_abort_bug (void)
{
- char *pwd1;
- char *pwd2;
- /* If the user provides an argument, attempt to chdir there first. */
- if (1 < argc)
+ char const *dir_name = "confdir-14B---";
+ char *cwd;
+ size_t initial_cwd_len;
+ int fail = 0;
+ size_t desired_depth;
+ size_t d;
+
+ /* The bug is triggered when PATH_MAX < getpagesize (), so skip
+ this relatively expensive and invasive test if that's not true. */
+ if (getpagesize () <= PATH_MAX)
+ return 0;
+
+ cwd = getcwd (NULL, 0);
+ if (cwd == NULL)
+ return 2;
+
+ initial_cwd_len = strlen (cwd);
+ free (cwd);
+ desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
+ / (1 + strlen (dir_name)));
+ for (d = 0; d < desired_depth; d++)
{
- if (chdir (argv[1]) == 0)
- printf ("changed to directory %s\n", argv[1]);
+ if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
+ {
+ fail = 3; /* Unable to construct deep hierarchy. */
+ break;
+ }
}
- pwd1 = getcwd (NULL, 0);
- ASSERT (pwd1 && *pwd1);
- if (1 < argc)
- printf ("cwd=%s\n", pwd1);
+ /* If libc has the bug in question, this invocation of getcwd
+ results in a failed assertion. */
+ cwd = getcwd (NULL, 0);
+ if (cwd == NULL)
+ fail = 4; /* getcwd failed. This is ok, and expected. */
+ free (cwd);
+
+ /* Call rmdir first, in case the above chdir failed. */
+ rmdir (dir_name);
+ while (0 < d--)
+ {
+ if (chdir ("..") < 0)
+ {
+ fail = 5;
+ break;
+ }
+ rmdir (dir_name);
+ }
+
+ return fail;
+}
+
+/* The length of this name must be 8. */
+#define DIR_NAME "confdir3"
+#define DIR_NAME_LEN 8
+#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
+
+/* The length of "../". */
+#define DOTDOTSLASH_LEN 3
+
+/* Leftover bytes in the buffer, to work around library or OS bugs. */
+#define BUF_SLOP 20
+
+/* Keep this test in sync with m4/getcwd-path-max.m4. */
+static int
+test_long_name (void)
+{
+#ifndef PATH_MAX
+ /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
+ at least not on a local file system. And if we were to start worrying
+ about remote file systems, we'd have to enable the wrapper function
+ all of the time, just to be safe. That's not worth the cost. */
+ return 0;
+#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
+ - DIR_NAME_SIZE - BUF_SLOP) \
+ <= PATH_MAX)
+ /* FIXME: Assuming there's a system for which this is true,
+ this should be done in a compile test. */
+ return 0;
+#else
+ char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
+ + DIR_NAME_SIZE + BUF_SLOP];
+ char *cwd = getcwd (buf, PATH_MAX);
+ size_t initial_cwd_len;
+ size_t cwd_len;
+ int fail = 0;
+ size_t n_chdirs = 0;
+
+ if (cwd == NULL)
+ return 10;
+
+ cwd_len = initial_cwd_len = strlen (cwd);
+
+ while (1)
+ {
+ size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
+ char *c = NULL;
+
+ cwd_len += DIR_NAME_SIZE;
+ /* If mkdir or chdir fails, it could be that this system cannot create
+ any file with an absolute name longer than PATH_MAX, such as cygwin.
+ If so, leave fail as 0, because the current working directory can't
+ be too long for getcwd if it can't even be created. For other
+ errors, be pessimistic and consider that as a failure, too. */
+ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
+ {
+ if (! (errno == ERANGE || errno == ENAMETOOLONG))
+ fail = 20;
+ break;
+ }
+
+ if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
+ {
+ c = getcwd (buf, PATH_MAX);
+ if (!c && errno == ENOENT)
+ {
+ fail = 11;
+ break;
+ }
+ if (c || ! (errno == ERANGE || errno == ENAMETOOLONG))
+ {
+ fail = 21;
+ break;
+ }
+ }
- /* Make sure the result is usable. */
- ASSERT (chdir (pwd1) == 0);
- ASSERT (chdir ("././.") == 0);
+ if (dotdot_max <= cwd_len - initial_cwd_len)
+ {
+ if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
+ break;
+ c = getcwd (buf, cwd_len + 1);
+ if (!c)
+ {
+ if (! (errno == ERANGE || errno == ENOENT
+ || errno == ENAMETOOLONG))
+ {
+ fail = 22;
+ break;
+ }
+ if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
+ {
+ fail = 12;
+ break;
+ }
+ }
+ }
- /* Make sure that result is normalized. */
- pwd2 = getcwd (NULL, 0);
- ASSERT (pwd2);
- ASSERT (strcmp (pwd1, pwd2) == 0);
- free (pwd2);
+ if (c && strlen (c) != cwd_len)
+ {
+ fail = 23;
+ break;
+ }
+ ++n_chdirs;
+ }
+
+ /* Leaving behind such a deep directory is not polite.
+ So clean up here, right away, even though the driving
+ shell script would also clean up. */
{
- size_t len = strlen (pwd1);
- ssize_t i = len - 10;
- if (i < 0)
- i = 0;
- pwd2 = malloc (len + 2);
- for ( ; i < len; i++)
- ASSERT (getcwd (pwd2, i) == NULL);
- pwd2 = getcwd (pwd2, len + 1);
- ASSERT (pwd2);
- pwd2[len] = '/';
- pwd2[len + 1] = '\0';
+ size_t i;
+
+ /* Try rmdir first, in case the chdir failed. */
+ rmdir (DIR_NAME);
+ for (i = 0; i <= n_chdirs; i++)
+ {
+ if (chdir ("..") < 0)
+ break;
+ if (rmdir (DIR_NAME) != 0)
+ break;
+ }
}
- ASSERT (strstr (pwd2, "/./") == NULL);
- ASSERT (strstr (pwd2, "/../") == NULL);
- free (pwd1);
- free (pwd2);
+ return fail;
+#endif
+}
- return 0;
+int
+main (int argc, char **argv)
+{
+ return test_abort_bug () + test_long_name ();
}
diff --git a/tests/test-hash.c b/tests/test-hash.c
index 108daefdf4..4a8a3bef37 100644
--- a/tests/test-hash.c
+++ b/tests/test-hash.c
@@ -20,7 +20,6 @@
#include "hash.h"
#include "hash-pjw.h"
#include "inttostr.h"
-#include "xalloc.h"
#include <stdio.h>
#include <stdlib.h>
@@ -114,8 +113,10 @@ main (int argc, char **argv)
ASSERT (ht);
insert_new (ht, "a");
{
- char *str1 = xstrdup ("a");
- char *str2 = hash_insert (ht, str1);
+ char *str1 = strdup ("a");
+ char *str2;
+ ASSERT (str1);
+ str2 = hash_insert (ht, str1);
ASSERT (str1 != str2);
ASSERT (STREQ (str1, str2));
free (str1);
@@ -161,7 +162,8 @@ main (int argc, char **argv)
ht = hash_initialize (sz, NULL, NULL, NULL, NULL);
ASSERT (ht);
{
- char *str = xstrdup ("a");
+ char *str = strdup ("a");
+ ASSERT (str);
insert_new (ht, "a");
insert_new (ht, str);
ASSERT (hash_lookup (ht, str) == str);
@@ -206,7 +208,9 @@ main (int argc, char **argv)
{
char buf[50];
char const *p = uinttostr (i, buf);
- insert_new (ht, xstrdup (p));
+ char *p_dup = strdup (p);
+ ASSERT (p_dup);
+ insert_new (ht, p_dup);
}
break;
diff --git a/tests/test-lchown.h b/tests/test-lchown.h
index aa10674187..229ed6b01b 100644
--- a/tests/test-lchown.h
+++ b/tests/test-lchown.h
@@ -46,7 +46,7 @@ test_lchown (int (*func) (char const *, uid_t, gid_t), bool print)
int result;
/* Solaris 8 is interesting - if the current process belongs to
- multiple groups, the current directory is owned by a a group that
+ multiple groups, the current directory is owned by a group that
the current process belongs to but different than getegid(), and
the current directory does not have the S_ISGID bit, then regular
files created in the directory belong to the directory's group,
diff --git a/tests/test-linkat.c b/tests/test-linkat.c
index 8d179e2faf..2bf1790524 100644
--- a/tests/test-linkat.c
+++ b/tests/test-linkat.c
@@ -34,7 +34,6 @@ SIGNATURE_CHECK (linkat, int, (int, char const *, int, char const *, int));
#include "areadlink.h"
#include "filenamecat.h"
#include "same-inode.h"
-#include "xgetcwd.h"
#include "ignore-value.h"
#include "macros.h"
@@ -119,7 +118,8 @@ main (void)
ASSERT (mkdir (BASE "sub1", 0700) == 0);
ASSERT (mkdir (BASE "sub2", 0700) == 0);
ASSERT (close (creat (BASE "00", 0600)) == 0);
- cwd = xgetcwd ();
+ cwd = getcwd (NULL, 0);
+ ASSERT (cwd);
dfd = open (BASE "sub1", O_RDONLY);
ASSERT (0 <= dfd);
@@ -140,9 +140,11 @@ main (void)
for (i = 0; i < 32; i++)
{
int fd1 = (i & 8) ? dfd : AT_FDCWD;
- char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
+ char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
int fd2 = (i & 2) ? dfd : AT_FDCWD;
- char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
+ char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
+ ASSERT (file1);
+ ASSERT (file2);
flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
diff --git a/tests/test-netdb-c++.cc b/tests/test-netdb-c++.cc
new file mode 100644
index 0000000000..0dc47b9ae7
--- /dev/null
+++ b/tests/test-netdb-c++.cc
@@ -0,0 +1,42 @@
+/* Test of <netdb.h> substitute in C++ mode.
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2011. */
+
+#define GNULIB_NAMESPACE gnulib
+#include <config.h>
+
+#include <netdb.h>
+
+#include "signature.h"
+
+
+#if GNULIB_TEST_GETADDRINFO
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getaddrinfo, int,
+ (const char *, const char *, const struct addrinfo *,
+ struct addrinfo **));
+SIGNATURE_CHECK (GNULIB_NAMESPACE::freeaddrinfo, void, (struct addrinfo *));
+SIGNATURE_CHECK (GNULIB_NAMESPACE::gai_strerror, const char *, (int));
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getnameinfo, int,
+ (const struct sockaddr *, socklen_t, char *, socklen_t,
+ char *, socklen_t, int));
+#endif
+
+
+int
+main ()
+{
+}
diff --git a/tests/test-nonblocking-misc.h b/tests/test-nonblocking-misc.h
new file mode 100644
index 0000000000..66a13e47e4
--- /dev/null
+++ b/tests/test-nonblocking-misc.h
@@ -0,0 +1,108 @@
+/* Test for nonblocking read and write.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Whether to print debugging messages. */
+#define ENABLE_DEBUGGING 0
+
+/* Delay (in microseconds) to sleep when write() or read() returned -1 with
+ errno = EAGAIN. */
+#define SMALL_DELAY 10000
+
+/* Return a memory area, filled with the data to be transferred. */
+static unsigned char *
+init_data (size_t data_block_size)
+{
+ unsigned char *data;
+ unsigned int i;
+
+ data = (unsigned char *) malloc (2 * data_block_size);
+ ASSERT (data != NULL);
+
+ for (i = 0; i < 2 * data_block_size; i++)
+ data[i] = (unsigned char) (i * i + (7 * i) % 61 + 4);
+
+ return data;
+}
+
+#if ENABLE_DEBUGGING
+# include <stdarg.h>
+static int dbgfprintf (FILE *fp, const char *format, ...)
+ _GL_ATTRIBUTE_FORMAT_PRINTF (2, 3);
+static int
+dbgfprintf (FILE *fp, const char *format, ...)
+{
+ /* Accumulate the entire line in a buffer, so that the output on fp
+ is done atomically. */
+ char line[1024];
+ size_t line_len;
+ struct timeval current_time;
+ va_list args;
+ int ret;
+
+ line_len = 0;
+ gettimeofday (&current_time, NULL);
+ ret = snprintf (line, sizeof (line), "%.6f ",
+ current_time.tv_sec + (double) current_time.tv_usec * 1e-6);
+ if (ret < 0)
+ return -1;
+ line_len = strlen (line);
+
+ va_start (args, format);
+ ret = vsnprintf (line + line_len, sizeof (line) - line_len, format, args);
+ va_end (args);
+ if (ret < 0)
+ return -1;
+ line_len += strlen (line + line_len);
+
+ ret = fwrite (line, 1, line_len, fp);
+
+ /* Make sure the debugging information is output, so that the order of the
+ messages reflects the timeline of events, and so that the output is not
+ lost if the program crashes afterwards (relevant on mingw). */
+ fflush (fp);
+ return ret;
+}
+#else
+# define dbgfprintf if (1) ; else fprintf
+#endif
+
+/* Return a textual description of the error code ERR, if FAILED is true.
+ Return an empty string if FAILED is false. */
+static const char *
+dbgstrerror (bool failed, int err)
+{
+ static char buf[256];
+ if (failed)
+ {
+ sprintf (buf, " %d %s", err, strerror (err));
+ return buf;
+ }
+ else
+ return "";
+}
+
+#define TIMING_DECLS \
+ struct timeval before_time; \
+ struct timeval after_time; \
+ double spent_time;
+#define START_TIMING \
+ gettimeofday (&before_time, NULL);
+#define END_TIMING \
+ gettimeofday (&after_time, NULL); \
+ spent_time = \
+ (after_time.tv_sec - before_time.tv_sec) \
+ + ((double) after_time.tv_usec - (double) before_time.tv_usec) * 1e-6;
diff --git a/tests/test-nonblocking-pipe-child.c b/tests/test-nonblocking-pipe-child.c
new file mode 100644
index 0000000000..d12a6e0ce5
--- /dev/null
+++ b/tests/test-nonblocking-pipe-child.c
@@ -0,0 +1,50 @@
+/* Child program invoked by test-nonblocking-pipe-main.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "binary-io.h"
+
+#include "macros.h"
+#include "test-nonblocking-pipe.h"
+#define PROG_ROLE "child"
+#include "test-nonblocking-reader.h"
+
+int
+main (int argc, char *argv[])
+{
+ int test = atoi (argv[1]);
+
+ /* Close unused file descriptors. */
+ close (STDOUT_FILENO);
+
+ /* STDIN_FILENO was created as binary in the parent process. But since an
+ fd's mode is stored in the process, not in the kernel, on native Windows
+ we need to set it as binary in the child process again. */
+ SET_BINARY (STDIN_FILENO);
+
+ main_reader_loop (test, PIPE_DATA_BLOCK_SIZE, STDIN_FILENO);
+
+ return 0;
+}
diff --git a/tests/test-nonblocking-pipe-main.c b/tests/test-nonblocking-pipe-main.c
new file mode 100644
index 0000000000..e61269ce5d
--- /dev/null
+++ b/tests/test-nonblocking-pipe-main.c
@@ -0,0 +1,110 @@
+/* Test for nonblocking read and write on pipes.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# include <process.h>
+#else
+# include <spawn.h>
+#endif
+
+#include "nonblocking.h"
+#include "wait-process.h"
+
+#include "macros.h"
+#include "test-nonblocking-pipe.h"
+#define PROG_ROLE "main"
+#include "test-nonblocking-writer.h"
+
+int
+main (int argc, char *argv[])
+{
+ const char *child_path = argv[1];
+ int test = atoi (argv[2]);
+ int fd[2];
+ int child;
+ int exitcode;
+
+ /* Create a pipe. */
+ ASSERT (pipe (fd) >= 0);
+
+ /* Map fd[0] to STDIN_FILENO and fd[1] to STDOUT_FILENO, because on Windows,
+ the only three file descriptors that are inherited by child processes are
+ STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. */
+ if (fd[0] != STDIN_FILENO)
+ {
+ ASSERT (dup2 (fd[0], STDIN_FILENO) >= 0);
+ close (fd[0]);
+ }
+ if (fd[1] != STDOUT_FILENO)
+ {
+ ASSERT (dup2 (fd[1], STDOUT_FILENO) >= 0);
+ close (fd[1]);
+ }
+
+ /* Prepare the file descriptors. */
+ if (test & 1)
+ ASSERT (set_nonblocking_flag (STDOUT_FILENO, true) >= 0);
+ if (test & 2)
+ ASSERT (set_nonblocking_flag (STDIN_FILENO, true) >= 0);
+
+ /* Spawn the child process. */
+ {
+ const char *child_argv[3];
+
+ child_argv[0] = child_path;
+ child_argv[1] = argv[2];
+ child_argv[2] = NULL;
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ child = spawnvpe (P_NOWAIT, child_path, child_argv,
+ (const char **) environ);
+ ASSERT (child >= 0);
+#else
+ {
+ pid_t child_pid;
+ int err =
+ posix_spawnp (&child_pid, child_path, NULL, NULL, (char **) child_argv,
+ environ);
+ ASSERT (err == 0);
+ child = child_pid;
+ }
+#endif
+ }
+
+ /* Close unused file descriptors. */
+ close (STDIN_FILENO);
+
+ exitcode =
+ main_writer_loop (test, PIPE_DATA_BLOCK_SIZE, STDOUT_FILENO, false);
+
+ {
+ int err =
+ wait_subprocess (child, child_path, false, false, false, false, NULL);
+ ASSERT (err == 0);
+ }
+
+ return exitcode;
+}
diff --git a/tests/test-nonblocking-pipe.h b/tests/test-nonblocking-pipe.h
new file mode 100644
index 0000000000..c4e65616a4
--- /dev/null
+++ b/tests/test-nonblocking-pipe.h
@@ -0,0 +1,38 @@
+/* Test for nonblocking read and write.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* A data block ought to be larger than the size of the in-kernel buffer.
+ Working values of PIPE_DATA_BLOCK_SIZE, depending on kernel:
+
+ Platform PIPE_DATA_BLOCK_SIZE
+
+ Linux >= 63489
+ FreeBSD, OpenBSD, MacOS X >= 65537
+ AIX >= 32769
+ HP-UX >= 8193
+ IRIX >= 10241
+ OSF/1 >= 262145
+ Solaris <= 7 >= 10241
+ Solaris >= 8 >= 20481
+ Cygwin >= 65537
+ native Win32 >= 4097 (depends on the _pipe argument)
+ */
+#if defined __osf__
+# define PIPE_DATA_BLOCK_SIZE 270000
+#else
+# define PIPE_DATA_BLOCK_SIZE 70000
+#endif
diff --git a/tests/test-nonblocking-pipe.sh b/tests/test-nonblocking-pipe.sh
new file mode 100755
index 0000000000..dd692be7ee
--- /dev/null
+++ b/tests/test-nonblocking-pipe.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Note: This test fails on Cygwin 1.5.x, because the non-blocking flag has
+# apparently no effect on STDOUT_FILENO. It is fixed in Cygwin 1.7.
+
+# Test blocking write() with blocking read().
+# Commented out because this test succeeds on all platforms anyway.
+#./test-nonblocking-pipe-main${EXEEXT} ./test-nonblocking-pipe-child${EXEEXT} 0 || exit 1
+
+# Test non-blocking write() with blocking read().
+./test-nonblocking-pipe-main${EXEEXT} ./test-nonblocking-pipe-child${EXEEXT} 1 || exit 1
+
+# Test blocking write() with non-blocking read().
+./test-nonblocking-pipe-main${EXEEXT} ./test-nonblocking-pipe-child${EXEEXT} 2 || exit 1
+
+# Test non-blocking write() with non-blocking read().
+./test-nonblocking-pipe-main${EXEEXT} ./test-nonblocking-pipe-child${EXEEXT} 3 || exit 1
diff --git a/tests/test-nonblocking-reader.h b/tests/test-nonblocking-reader.h
new file mode 100644
index 0000000000..220862ff2d
--- /dev/null
+++ b/tests/test-nonblocking-reader.h
@@ -0,0 +1,200 @@
+/* The reader part of a test program for non-blocking communication.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* This program implements 4 tests:
+
+ test == 0:
+ Test blocking write() with blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ 1 s write(20000) Return from read(10000)
+ 2 s Next read(10000)
+ 2 s Return from write(20000) Return from read(10000)
+
+ test == 1:
+ Test non-blocking write() with blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ 1 s write(20000) Return from read(10000)
+ Return with at least 10000,
+ Repeatedly continue
+ write() of the rest
+ 2 s Next read(10000)
+ 2 s Return from write(10000) Return from read(10000)
+
+ test == 2:
+ Test blocking write() with non-blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ repeatedly polling
+ 1 s write(20000) Return from read(10000)
+ 2 s Next read(10000)
+ 2 s Return from write(20000) Return from read(10000)
+
+ test == 3:
+ Test non-blocking write() with non-blocking read().
+ */
+
+#include "test-nonblocking-misc.h"
+
+static ssize_t
+full_read (size_t fd, void *buf, size_t count)
+{
+ size_t bytes_read;
+
+ bytes_read = 0;
+ while (bytes_read < count)
+ {
+ TIMING_DECLS
+ ssize_t ret;
+ int saved_errno;
+
+ dbgfprintf (stderr, "%s: >> read (%lu)\n", PROG_ROLE,
+ (unsigned long) (count - bytes_read));
+ START_TIMING
+ ret = read (fd, (char *) buf + bytes_read, count - bytes_read);
+ saved_errno = errno;
+ END_TIMING
+ dbgfprintf (stderr, "%s: << read -> %ld%s\n", PROG_ROLE,
+ (long) ret, dbgstrerror (ret < 0, saved_errno));
+ if (ret < 0)
+ return -1;
+ else
+ {
+ ASSERT (ret > 0);
+ bytes_read += ret;
+ }
+ }
+ return bytes_read;
+}
+
+static ssize_t
+full_read_from_nonblocking_fd (size_t fd, void *buf, size_t count)
+{
+ size_t bytes_read;
+
+ bytes_read = 0;
+ while (bytes_read < count)
+ {
+ TIMING_DECLS
+ ssize_t ret;
+ int saved_errno;
+
+ dbgfprintf (stderr, "%s: >> read (%lu)\n", PROG_ROLE,
+ (unsigned long) (count - bytes_read));
+ START_TIMING
+ ret = read (fd, (char *) buf + bytes_read, count - bytes_read);
+ saved_errno = errno;
+ END_TIMING
+ dbgfprintf (stderr, "%s: << read -> %ld%s\n", PROG_ROLE,
+ (long) ret, dbgstrerror (ret < 0, saved_errno));
+ /* This assertion fails if the non-blocking flag is effectively not set
+ on fd. */
+ ASSERT (spent_time < 0.5);
+ if (ret < 0)
+ {
+ ASSERT (saved_errno == EAGAIN);
+ usleep (SMALL_DELAY);
+ }
+ else
+ {
+ ASSERT (ret > 0);
+ bytes_read += ret;
+ }
+ }
+ return bytes_read;
+}
+
+/* Execute the reader loop. */
+static void
+main_reader_loop (int test, size_t data_block_size, int fd)
+{
+ unsigned char *expected;
+ unsigned char *data;
+
+ /* Set up the expected data. */
+ expected = init_data (data_block_size);
+
+ data = (unsigned char *) malloc (2 * data_block_size);
+ ASSERT (data != NULL);
+
+ switch (test)
+ {
+ TIMING_DECLS
+ ssize_t ret;
+
+ case 0: /* Test blocking write() with blocking read(). */
+ case 1: /* Test non-blocking write() with blocking read(). */
+ START_TIMING
+ ret = full_read (fd, data, data_block_size);
+ END_TIMING
+ ASSERT (ret == data_block_size);
+ ASSERT (memcmp (data, expected, data_block_size) == 0);
+ ASSERT (spent_time > 0.5);
+ /* This assertion fails if data_block_size is very large and
+ ENABLE_DEBUGGING is 1. */
+ ASSERT (spent_time < 1.5);
+
+ usleep (1000000);
+
+ START_TIMING
+ ret = full_read (fd, data, data_block_size);
+ END_TIMING
+ ASSERT (ret == data_block_size);
+ ASSERT (memcmp (data, expected + data_block_size, data_block_size) == 0);
+ /* This assertion fails if data_block_size is much larger than needed
+ and SMALL_DELAY is too large. */
+ ASSERT (spent_time < 0.5);
+
+ break;
+
+ case 2: /* Test blocking write() with non-blocking read(). */
+ case 3: /* Test non-blocking write() with non-blocking read(). */
+ START_TIMING
+ ret = full_read_from_nonblocking_fd (fd, data, data_block_size);
+ END_TIMING
+ ASSERT (ret == data_block_size);
+ ASSERT (memcmp (data, expected, data_block_size) == 0);
+ ASSERT (spent_time > 0.5);
+ /* This assertion fails if data_block_size is much larger than needed
+ and SMALL_DELAY is too large, or if data_block_size is very large and
+ ENABLE_DEBUGGING is 1. */
+ ASSERT (spent_time < 1.5);
+
+ usleep (1000000);
+
+ START_TIMING
+ ret = full_read_from_nonblocking_fd (fd, data, data_block_size);
+ END_TIMING
+ ASSERT (ret == data_block_size);
+ ASSERT (memcmp (data, expected + data_block_size, data_block_size) == 0);
+ /* This assertion fails if data_block_size is much larger than needed
+ and SMALL_DELAY is too large. */
+ ASSERT (spent_time < 0.5);
+
+ break;
+
+ default:
+ abort ();
+ }
+
+ free (data);
+ free (expected);
+}
diff --git a/tests/test-nonblocking-socket-child.c b/tests/test-nonblocking-socket-child.c
new file mode 100644
index 0000000000..17545cf644
--- /dev/null
+++ b/tests/test-nonblocking-socket-child.c
@@ -0,0 +1,52 @@
+/* Child program invoked by test-nonblocking-socket-main.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "nonblocking.h"
+
+#include "macros.h"
+#include "socket-client.h"
+#include "test-nonblocking-socket.h"
+#define PROG_ROLE "child"
+#include "test-nonblocking-reader.h"
+
+int
+main (int argc, char *argv[])
+{
+ int test = atoi (argv[1]);
+ int port = atoi (argv[2]);
+ int client_socket;
+
+ /* Create a client socket. */
+ client_socket = create_client_socket (port);
+
+ /* Prepare the file descriptor. */
+ if (test & 2)
+ ASSERT (set_nonblocking_flag (client_socket, true) >= 0);
+
+ main_reader_loop (test, SOCKET_DATA_BLOCK_SIZE, client_socket);
+
+ return 0;
+}
diff --git a/tests/test-nonblocking-socket-main.c b/tests/test-nonblocking-socket-main.c
new file mode 100644
index 0000000000..034873d5d2
--- /dev/null
+++ b/tests/test-nonblocking-socket-main.c
@@ -0,0 +1,121 @@
+/* Test for nonblocking read and write on sockets.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# include <process.h>
+#else
+# include <spawn.h>
+#endif
+
+#include "nonblocking.h"
+#include "wait-process.h"
+
+#include "macros.h"
+#include "socket-server.h"
+#include "test-nonblocking-socket.h"
+#define PROG_ROLE "main"
+#include "test-nonblocking-writer.h"
+
+int
+main (int argc, char *argv[])
+{
+ const char *child_path = argv[1];
+ int test = atoi (argv[2]);
+ int server;
+ int port;
+ int child;
+ int server_socket;
+ int exitcode;
+
+ /* Create a server socket. */
+ server = create_server (0, 1, &port);
+
+ /* Spawn the child process. */
+ {
+ char port_arg[10+1];
+ const char *child_argv[4];
+
+ sprintf (port_arg, "%u", port);
+ child_argv[0] = child_path;
+ child_argv[1] = argv[2];
+ child_argv[2] = port_arg;
+ child_argv[3] = NULL;
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ child = spawnvpe (P_NOWAIT, child_path, child_argv,
+ (const char **) environ);
+ ASSERT (child >= 0);
+#else
+ {
+ pid_t child_pid;
+ int err =
+ posix_spawnp (&child_pid, child_path, NULL, NULL, (char **) child_argv,
+ environ);
+ ASSERT (err == 0);
+ child = child_pid;
+ }
+#endif
+ }
+
+ /* Accept a connection from the child process. */
+ server_socket = create_server_socket (server);
+
+ /* Prepare the file descriptor. */
+ if (test & 1)
+ ASSERT (set_nonblocking_flag (server_socket, true) >= 0);
+
+#if ENABLE_DEBUGGING
+# ifdef SO_SNDBUF
+ {
+ int value;
+ socklen_t value_len = sizeof (value);
+ if (getsockopt (server_socket, SOL_SOCKET, SO_SNDBUF, &value, &value_len) >= 0)
+ fprintf (stderr, "SO_SNDBUF = %d\n", value);
+ }
+# endif
+# ifdef SO_RCVBUF
+ {
+ int value;
+ socklen_t value_len = sizeof (value);
+ if (getsockopt (server_socket, SOL_SOCKET, SO_RCVBUF, &value, &value_len) >= 0)
+ fprintf (stderr, "SO_RCVBUF = %d\n", value);
+ }
+# endif
+#endif
+
+ exitcode =
+ main_writer_loop (test, SOCKET_DATA_BLOCK_SIZE, server_socket,
+ SOCKET_HAS_LARGE_BUFFER);
+
+ {
+ int err =
+ wait_subprocess (child, child_path, false, false, false, false, NULL);
+ ASSERT (err == 0);
+ }
+
+ return exitcode;
+}
diff --git a/tests/test-nonblocking-socket.h b/tests/test-nonblocking-socket.h
new file mode 100644
index 0000000000..5f2268d9c3
--- /dev/null
+++ b/tests/test-nonblocking-socket.h
@@ -0,0 +1,51 @@
+/* Test for nonblocking read and write.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* A data block ought to be larger than the size of the in-kernel buffer.
+ Working values of SOCKET_DATA_BLOCK_SIZE, depending on kernel:
+
+ Platform SOCKET_DATA_BLOCK_SIZE
+
+ Linux >= 7350000 (depends on circumstances)
+ FreeBSD >= 107521
+ OpenBSD >= 28673
+ MacOS X >= 680000 (depends on circumstances)
+ AIX 5.1 >= 125713
+ AIX 7.1 >= 200000 (depends on circumstances)
+ HP-UX >= 114689
+ IRIX >= 61089
+ OSF/1 >= 122881
+ Solaris 7 >= 63000 (depends on circumstances)
+ Solaris 8 >= 49153
+ Solaris 9 >= 73729
+ Solaris 10 >= 98305
+ Solaris 11 2010-11 >= 73729
+ Cygwin 1.5.x >= 66294401 but then write() fails with ENOBUFS
+ Cygwin 1.7.x >= 163838 (depends on circumstances)
+ native Win32 >= 66294401
+ */
+#define SOCKET_DATA_BLOCK_SIZE 1000000
+
+/* On Linux, MacOS X, Cygwin 1.5.x, native Win32,
+ sockets have very large buffers in the kernel, so that write() calls
+ succeed before the reader has started reading, even if fd is blocking
+ and the amount of data is larger than 1 MB. */
+#if defined __linux__ || (defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__
+# define SOCKET_HAS_LARGE_BUFFER 1
+#else
+# define SOCKET_HAS_LARGE_BUFFER 0
+#endif
diff --git a/tests/test-nonblocking-socket.sh b/tests/test-nonblocking-socket.sh
new file mode 100755
index 0000000000..3818c93d3a
--- /dev/null
+++ b/tests/test-nonblocking-socket.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Test blocking write() with blocking read().
+./test-nonblocking-socket-main${EXEEXT} ./test-nonblocking-socket-child${EXEEXT} 0 || exit 1
+
+# Test non-blocking write() with blocking read().
+./test-nonblocking-socket-main${EXEEXT} ./test-nonblocking-socket-child${EXEEXT} 1 || exit 1
+
+# Test blocking write() with non-blocking read().
+./test-nonblocking-socket-main${EXEEXT} ./test-nonblocking-socket-child${EXEEXT} 2 || exit 1
+
+# Test non-blocking write() with non-blocking read().
+./test-nonblocking-socket-main${EXEEXT} ./test-nonblocking-socket-child${EXEEXT} 3 || exit 1
diff --git a/tests/test-nonblocking-writer.h b/tests/test-nonblocking-writer.h
new file mode 100644
index 0000000000..6db53f6dab
--- /dev/null
+++ b/tests/test-nonblocking-writer.h
@@ -0,0 +1,186 @@
+/* The writer part of a test program for non-blocking communication.
+
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* This program implements 4 tests:
+
+ test == 0:
+ Test blocking write() with blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ 1 s write(20000) Return from read(10000)
+ 2 s Next read(10000)
+ 2 s Return from write(20000) Return from read(10000)
+
+ test == 1:
+ Test non-blocking write() with blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ 1 s write(20000) Return from read(10000)
+ Return with at least 10000,
+ Repeatedly continue
+ write() of the rest
+ 2 s Next read(10000)
+ 2 s Return from write(10000) Return from read(10000)
+
+ test == 2:
+ Test blocking write() with non-blocking read().
+
+ Timeline Main process Child process
+ 0 s Start Start, read(10000)
+ repeatedly polling
+ 1 s write(20000) Return from read(10000)
+ 2 s Next read(10000)
+ 2 s Return from write(20000) Return from read(10000)
+
+ test == 3:
+ Test non-blocking write() with non-blocking read().
+ */
+
+#include "test-nonblocking-misc.h"
+
+/* Execute the writer loop.
+ Returns 0 if successful, 1 if data_block_size is too small. */
+static int
+main_writer_loop (int test, size_t data_block_size, int fd,
+ bool has_large_buffer)
+{
+ int too_small = 0;
+ unsigned char *data;
+
+ /* Set up the data to transfer. */
+ data = init_data (data_block_size);
+
+ switch (test)
+ {
+ TIMING_DECLS
+ ssize_t ret;
+
+ case 0: /* Test blocking write() with blocking read(). */
+ case 2: /* Test blocking write() with non-blocking read(). */
+ {
+ int saved_errno;
+
+ usleep (1000000);
+
+ dbgfprintf (stderr, "%s:1: >> write (%lu)\n", PROG_ROLE,
+ (unsigned long) 2 * data_block_size);
+ START_TIMING
+ ret = write (fd, data, 2 * data_block_size);
+ saved_errno = errno;
+ END_TIMING
+ dbgfprintf (stderr, "%s:1: << write -> %ld%s\n", PROG_ROLE,
+ (long) ret, dbgstrerror (ret < 0, saved_errno));
+ ASSERT (ret == 2 * data_block_size);
+ if (!has_large_buffer)
+ {
+ /* This assertion fails if data_block_size is too small. */
+ if (!(spent_time > 0.5))
+ {
+ fprintf (stderr,
+ "%s:1: spent_time = %g, data_block_size too small\n",
+ PROG_ROLE, spent_time);
+ too_small = 1;
+ }
+ }
+ ASSERT (spent_time < 1.5);
+ }
+ break;
+
+ case 1: /* Test non-blocking write() with blocking read(). */
+ case 3: /* Test non-blocking write() with non-blocking read(). */
+ {
+ size_t bytes_written;
+ int saved_errno;
+
+ usleep (1000000);
+
+ bytes_written = 0;
+ while (bytes_written < 2 * data_block_size)
+ {
+ dbgfprintf (stderr, "%s:2: >> write (%lu)\n", PROG_ROLE,
+ (unsigned long) (2 * data_block_size - bytes_written));
+ START_TIMING
+ ret = write (fd, data + bytes_written,
+ 2 * data_block_size - bytes_written);
+ saved_errno = errno;
+ END_TIMING
+ dbgfprintf (stderr, "%s:2: << write -> %ld%s\n", PROG_ROLE,
+ (long) ret, dbgstrerror (ret < 0, saved_errno));
+ if (ret < 0 && bytes_written >= data_block_size)
+ {
+ ASSERT (saved_errno == EAGAIN);
+ ASSERT (spent_time < 0.5);
+ break;
+ }
+ /* This assertion fails if the non-blocking flag is effectively not
+ set on fd. */
+ ASSERT (spent_time < 0.5);
+ if (ret < 0)
+ {
+ ASSERT (saved_errno == EAGAIN);
+ usleep (SMALL_DELAY);
+ }
+ else
+ {
+ /* This assertion fails if data_block_size is too small. */
+ if (!(ret > 0))
+ {
+ fprintf (stderr,
+ "%s:1: spent_time = %g, data_block_size too small\n",
+ PROG_ROLE, spent_time);
+ too_small = 1;
+ }
+ bytes_written += ret;
+ }
+ }
+ ASSERT (bytes_written >= data_block_size);
+
+ while (bytes_written < 2 * data_block_size)
+ {
+ dbgfprintf (stderr, "%s:3: >> write (%lu)\n", PROG_ROLE,
+ (unsigned long) (2 * data_block_size - bytes_written));
+ START_TIMING
+ ret = write (fd, data + bytes_written,
+ 2 * data_block_size - bytes_written);
+ saved_errno = errno;
+ END_TIMING
+ dbgfprintf (stderr, "%s:3: << write -> %ld%s\n", PROG_ROLE,
+ (long) ret, dbgstrerror (ret < 0, saved_errno));
+ ASSERT (spent_time < 0.5);
+ if (ret < 0)
+ {
+ ASSERT (saved_errno == EAGAIN);
+ usleep (SMALL_DELAY);
+ }
+ else
+ {
+ ASSERT (ret > 0);
+ bytes_written += ret;
+ }
+ }
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ free (data);
+ return too_small;
+}
diff --git a/tests/test-nonblocking.c b/tests/test-nonblocking.c
index f1b7610543..f3f1f1355b 100644
--- a/tests/test-nonblocking.c
+++ b/tests/test-nonblocking.c
@@ -33,13 +33,6 @@ main (void)
const char *file = "test-nonblock.tmp";
int fd_file;
int fd_pipe[2];
- int fd_sock;
- bool sock_works = true;
-
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
- /* For now, we can't get nonblocking status of windows sockets. */
- sock_works = false;
-#endif
fd_file = creat (file, 0600);
@@ -79,28 +72,39 @@ main (void)
ASSERT (close (fd_pipe[1]) == 0);
#if GNULIB_TEST_PIPE2
- /* mingw still lacks O_NONBLOCK replacement. */
ASSERT (pipe2 (fd_pipe, O_NONBLOCK) == 0);
- ASSERT (get_nonblocking_flag (fd_pipe[0]) == !!O_NONBLOCK);
- ASSERT (get_nonblocking_flag (fd_pipe[1]) == !!O_NONBLOCK);
+ ASSERT (get_nonblocking_flag (fd_pipe[0]) == 1);
+ ASSERT (get_nonblocking_flag (fd_pipe[1]) == 1);
ASSERT (close (fd_pipe[0]) == 0);
ASSERT (close (fd_pipe[1]) == 0);
#endif /* GNULIB_TEST_PIPE2 */
- /* Test sockets. */
- fd_sock = socket (AF_INET, SOCK_STREAM, 0);
- ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 0 : -1));
- ASSERT (set_nonblocking_flag (fd_sock, true) == 0);
- ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 1 : -1));
- ASSERT (set_nonblocking_flag (fd_sock, false) == 0);
- ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 0 : -1));
- ASSERT (close (fd_sock) == 0);
-
-#if SOCK_NONBLOCK
- fd_sock = socket (AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
- ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 1 : -1));
- ASSERT (close (fd_sock) == 0);
-#endif /* SOCK_NONBLOCK */
+#if GNULIB_TEST_SOCKET
+ {
+ /* Test sockets. */
+ bool sock_works = true;
+ int fd_sock;
+
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ /* For now, we can't get nonblocking status of windows sockets. */
+ sock_works = false;
+# endif
+
+ fd_sock = socket (AF_INET, SOCK_STREAM, 0);
+ ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 0 : -1));
+ ASSERT (set_nonblocking_flag (fd_sock, true) == 0);
+ ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 1 : -1));
+ ASSERT (set_nonblocking_flag (fd_sock, false) == 0);
+ ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 0 : -1));
+ ASSERT (close (fd_sock) == 0);
+
+# if SOCK_NONBLOCK
+ fd_sock = socket (AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ ASSERT (get_nonblocking_flag (fd_sock) == (sock_works ? 1 : -1));
+ ASSERT (close (fd_sock) == 0);
+# endif /* SOCK_NONBLOCK */
+ }
+#endif /* GNULIB_TEST_SOCKET */
/* Test error handling. */
{
diff --git a/tests/test-open.h b/tests/test-open.h
index 3e5c5e1726..2ba5d137bf 100644
--- a/tests/test-open.h
+++ b/tests/test-open.h
@@ -63,6 +63,12 @@ test_open (int (*func) (char const *, int, ...), bool print)
ASSERT (write (fd, "c", 1) == 1);
ASSERT (close (fd) == 0);
+ /* Although O_NONBLOCK on regular files can be ignored, it must not
+ cause a failure. */
+ fd = func (BASE "file", O_NONBLOCK | O_RDONLY);
+ ASSERT (0 <= fd);
+ ASSERT (close (fd) == 0);
+
/* Symlink handling, where supported. */
if (symlink (BASE "file", BASE "link") != 0)
{
diff --git a/tests/test-passfd.c b/tests/test-passfd.c
index d657ad9d66..315e6c21ba 100644
--- a/tests/test-passfd.c
+++ b/tests/test-passfd.c
@@ -18,6 +18,7 @@
#include "passfd.h"
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
@@ -33,6 +34,7 @@
int
main ()
{
+#if HAVE_SOCKETPAIR
int pair[2];
int ret;
pid_t pid;
@@ -41,11 +43,11 @@ main ()
int fd;
struct stat st;
-#if HAVE_DECL_ALARM
+# if HAVE_DECL_ALARM
/* Avoid hanging on failure. */
signal (SIGALRM, SIG_DFL);
alarm (5);
-#endif
+# endif
fdnull = open ("/dev/null", O_RDWR);
if (fdnull < 0)
@@ -115,4 +117,17 @@ main ()
}
return 0;
}
+#else
+ errno = 0;
+ ASSERT(sendfd (0, 0) == -1);
+ ASSERT(errno == ENOSYS);
+
+ errno = 0;
+ ASSERT(recvfd (0, 0) == -1);
+ ASSERT(errno == ENOSYS);
+
+ fputs ("skipping test: socketpair not supported on this system\n",
+ stderr);
+ return 77;
+#endif
}
diff --git a/tests/test-pipe2.c b/tests/test-pipe2.c
index ddfb819abb..8ca8e01363 100644
--- a/tests/test-pipe2.c
+++ b/tests/test-pipe2.c
@@ -33,6 +33,7 @@ SIGNATURE_CHECK (pipe2, int, (int[2], int));
#include "binary-io.h"
#include "macros.h"
+#include "nonblocking.h"
/* Return true if FD is open. */
static bool
@@ -67,49 +68,23 @@ is_cloexec (int fd)
#endif
}
-/* Return true if FD is in non-blocking mode. */
-static bool
-is_nonblocking (int fd)
-{
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
- /* We don't use the non-blocking mode for sockets here. */
- return 0;
-#else
- int flags;
- ASSERT ((flags = fcntl (fd, F_GETFL)) >= 0);
- return (flags & O_NONBLOCK) != 0;
-#endif
-}
-
int
main ()
{
int use_nonblocking;
int use_cloexec;
-#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
for (use_nonblocking = 0; use_nonblocking <= 1; use_nonblocking++)
-#else
- use_nonblocking = 0;
-#endif
-#if O_CLOEXEC
- for (use_cloexec = 0; use_cloexec <= 1; use_cloexec++)
-#else
- use_cloexec = 0;
-#endif
+ for (use_cloexec = 0; use_cloexec <= !!O_CLOEXEC; use_cloexec++)
{
int o_flags;
int fd[2];
o_flags = 0;
-#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
if (use_nonblocking)
o_flags |= O_NONBLOCK;
-#endif
-#if O_CLOEXEC
if (use_cloexec)
o_flags |= O_CLOEXEC;
-#endif
fd[0] = -1;
fd[1] = -1;
@@ -131,14 +106,17 @@ main ()
}
if (use_nonblocking)
{
- ASSERT (is_nonblocking (fd[0]));
- ASSERT (is_nonblocking (fd[1]));
+ ASSERT (get_nonblocking_flag (fd[0]) == 1);
+ ASSERT (get_nonblocking_flag (fd[1]) == 1);
}
else
{
- ASSERT (!is_nonblocking (fd[0]));
- ASSERT (!is_nonblocking (fd[1]));
+ ASSERT (get_nonblocking_flag (fd[0]) == 0);
+ ASSERT (get_nonblocking_flag (fd[1]) == 0);
}
+
+ ASSERT (close (fd[0]) == 0);
+ ASSERT (close (fd[1]) == 0);
}
return 0;
diff --git a/tests/test-renameat.c b/tests/test-renameat.c
index 1849a24413..96fe3a7555 100644
--- a/tests/test-renameat.c
+++ b/tests/test-renameat.c
@@ -33,7 +33,6 @@ SIGNATURE_CHECK (renameat, int, (int, char const *, int, char const *));
#include <sys/stat.h>
#include "filenamecat.h"
-#include "xgetcwd.h"
#include "ignore-value.h"
#include "macros.h"
@@ -79,7 +78,8 @@ main (void)
dfd = creat (BASE "00", 0600);
ASSERT (0 <= dfd);
ASSERT (close (dfd) == 0);
- cwd = xgetcwd ();
+ cwd = getcwd (NULL, 0);
+ ASSERT (cwd);
dfd = open (BASE "sub1", O_RDONLY);
ASSERT (0 <= dfd);
diff --git a/tests/test-stdio-c++.cc b/tests/test-stdio-c++.cc
index a9d00a39f8..07faf0fa02 100644
--- a/tests/test-stdio-c++.cc
+++ b/tests/test-stdio-c++.cc
@@ -36,6 +36,14 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::fclose, int, (FILE *));
SIGNATURE_CHECK (GNULIB_NAMESPACE::fflush, int, (FILE *));
#endif
+#if GNULIB_TEST_FGETC
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fgetc, int, (FILE *));
+#endif
+
+#if GNULIB_TEST_FGETS
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fgets, char *, (char *, int, FILE *));
+#endif
+
#if GNULIB_TEST_FOPEN
SIGNATURE_CHECK (GNULIB_NAMESPACE::fopen, FILE *,
(const char *, const char *));
@@ -57,11 +65,20 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::fputc, int, (int, FILE *));
SIGNATURE_CHECK (GNULIB_NAMESPACE::fputs, int, (const char *, FILE *));
#endif
+#if GNULIB_TEST_FREAD
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fread, size_t,
+ (void *, size_t, size_t, FILE *));
+#endif
+
#if GNULIB_TEST_FREOPEN
SIGNATURE_CHECK (GNULIB_NAMESPACE::freopen, FILE *,
(const char *, const char *, FILE *));
#endif
+#if GNULIB_TEST_FSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fscanf, int, (FILE *, const char *, ...));
+#endif
+
#if GNULIB_TEST_FSEEK
SIGNATURE_CHECK (GNULIB_NAMESPACE::fseek, int, (FILE *, long, int));
#endif
@@ -83,6 +100,14 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::fwrite, size_t,
(const void *, size_t, size_t, FILE *));
#endif
+#if GNULIB_TEST_GETC
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getc, int, (FILE *));
+#endif
+
+#if GNULIB_TEST_GETCHAR
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getchar, int, (void));
+#endif
+
#if GNULIB_TEST_GETDELIM
SIGNATURE_CHECK (GNULIB_NAMESPACE::getdelim, ssize_t,
(char **, size_t *, int, FILE *));
@@ -93,6 +118,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::getline, ssize_t,
(char **, size_t *, FILE *));
#endif
+#if GNULIB_TEST_GETS
+SIGNATURE_CHECK (GNULIB_NAMESPACE::gets, char *, (char *));
+#endif
+
#if GNULIB_TEST_OBSTACK_PRINTF || GNULIB_TEST_OBSTACK_PRINTF_POSIX
SIGNATURE_CHECK (GNULIB_NAMESPACE::obstack_printf, int,
(struct obstack *, const char *, ...));
@@ -140,6 +169,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::renameat, int,
(int, char const *, int, char const *));
#endif
+#if GNULIB_TEST_SCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::scanf, int, (const char *, ...));
+#endif
+
#if GNULIB_TEST_SNPRINTF
SIGNATURE_CHECK (GNULIB_NAMESPACE::snprintf, int,
(char *, size_t, const char *, ...));
@@ -170,10 +203,19 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::vfprintf, int,
(FILE *, const char *, va_list));
#endif
+#if GNULIB_TEST_VFSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::vfscanf, int,
+ (FILE *, const char *, va_list));
+#endif
+
#if GNULIB_TEST_VPRINTF_POSIX || GNULIB_TEST_VPRINTF
SIGNATURE_CHECK (GNULIB_NAMESPACE::vprintf, int, (const char *, va_list));
#endif
+#if GNULIB_TEST_VSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::vscanf, int, (const char *, va_list));
+#endif
+
#if GNULIB_TEST_VSNPRINTF
SIGNATURE_CHECK (GNULIB_NAMESPACE::vsnprintf, int,
(char *, size_t, const char *, va_list));
diff --git a/tests/test-sys_socket.c b/tests/test-sys_socket.c
index 8f323ca1d9..a6e99d6008 100644
--- a/tests/test-sys_socket.c
+++ b/tests/test-sys_socket.c
@@ -30,6 +30,12 @@ int a[] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
/* Check that the 'socklen_t' type is defined. */
socklen_t t1;
+/* Check that 'struct iovec' is defined. */
+struct iovec io;
+
+/* Check that a minimal set of 'struct msghdr' is defined. */
+struct msghdr msg;
+
int
main (void)
{
@@ -51,10 +57,8 @@ main (void)
x.ss_family = 42;
i = 42;
+ msg.msg_iov = &io;
- /* Tell the compiler that these variables are used. */
- (void) x;
- (void) i;
-
- return 0;
+ return (x.ss_family - i + msg.msg_namelen + msg.msg_iov->iov_len
+ + msg.msg_iovlen);
}
diff --git a/tests/test-sys_uio.c b/tests/test-sys_uio.c
new file mode 100644
index 0000000000..7855a6bc43
--- /dev/null
+++ b/tests/test-sys_uio.c
@@ -0,0 +1,32 @@
+/* Test of <sys/uio.h> substitute.
+ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Eric Blake <eblake@redhat.com>, 2011. */
+
+#include <config.h>
+
+#include <sys/uio.h>
+
+/* Check that necessary types are defined. */
+size_t a;
+ssize_t b;
+struct iovec c;
+
+int
+main (void)
+{
+ return a + b + !!c.iov_base + c.iov_len;
+}