summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorRuss Allbery <rra@stanford.edu>2011-09-20 21:39:52 -0700
committerRuss Allbery <rra@stanford.edu>2011-09-20 21:39:52 -0700
commitc82ebaa070d5c4e9e1311b336139160ddf9e12cc (patch)
tree1b67c222b72f00eda61b79dbd03e56a7589f4536 /util
parentd4fb4c26b7e3a3911c7d02da7cad6135435a7977 (diff)
Update to rra-c-util 3.9
* Add notices in each file copied from rra-c-util. * Prefer gssapi/gssapi.h to gssapi.h. * Include strings.h if it exists for strncasecmp on some platforms. * getaddrinfo replacement now portable to systems with bad netdb.h. * Avoid krb5-config if --with-gssapi-{include,lib} are given. * Add Windows implementation of fdflag_nonblocking. * The network_connect utility functions now take an optional timeout. * Use typedef instead of #define for socklen_t and sig_atomic_t. * Stop providing or using INADDR_LOOPBACK for portability reasons.
Diffstat (limited to 'util')
-rw-r--r--util/concat.c3
-rw-r--r--util/concat.h3
-rw-r--r--util/fdflag.c67
-rw-r--r--util/fdflag.h16
-rw-r--r--util/macros.h12
-rw-r--r--util/messages.c7
-rw-r--r--util/messages.h5
-rw-r--r--util/network.c118
-rw-r--r--util/network.h13
-rw-r--r--util/vector.c11
-rw-r--r--util/vector.h7
-rw-r--r--util/xmalloc.c3
-rw-r--r--util/xmalloc.h3
-rw-r--r--util/xwrite.c3
-rw-r--r--util/xwrite.h3
15 files changed, 212 insertions, 62 deletions
diff --git a/util/concat.c b/util/concat.c
index 0525ddb..fb4afa8 100644
--- a/util/concat.c
+++ b/util/concat.c
@@ -18,6 +18,9 @@
* together and returned. This is useful for building file names where names
* that aren't fully qualified are qualified with some particular directory.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
*
* The authors hereby relinquish any claim to any copyright that they may have
diff --git a/util/concat.h b/util/concat.h
index 9712d70..960f242 100644
--- a/util/concat.h
+++ b/util/concat.h
@@ -1,6 +1,9 @@
/*
* Prototypes for string concatenation with dynamic memory allocation.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
*
* The authors hereby relinquish any claim to any copyright that they may have
diff --git a/util/fdflag.c b/util/fdflag.c
index bf3125e..1be200c 100644
--- a/util/fdflag.c
+++ b/util/fdflag.c
@@ -4,7 +4,10 @@
* Simple functions (wrappers around fcntl) to set or clear file descriptor
* flags like close-on-exec or nonblocking I/O.
*
- * Copyright 2008
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Copyright 2008, 2011
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006
* by Internet Systems Consortium, Inc. ("ISC")
@@ -30,16 +33,21 @@
#include <config.h>
#include <portable/system.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifndef O_NONBLOCK
-# include <sys/ioctl.h>
-# if HAVE_SYS_FILIO_H
-# include <sys/filio.h>
+#ifdef _WIN32
+# include <winsock2.h>
+#else
+# include <errno.h>
+# include <fcntl.h>
+# ifndef O_NONBLOCK
+# include <sys/ioctl.h>
+# if HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+# endif
# endif
#endif
#include <util/fdflag.h>
+#include <util/macros.h>
/*
@@ -49,7 +57,17 @@
* One is supposed to retrieve the flags, add FD_CLOEXEC, and then set them,
* although I've never seen a system with any flags other than close-on-exec.
* Do it right anyway; it's not that expensive.
-*/
+ *
+ * Stub this out on Windows, where it's not supported (at least currently by
+ * this utility library).
+ */
+#ifdef _WIN32
+bool
+fdflag_close_exec(int fd UNUSED, bool flag UNUSED)
+{
+ return false;
+}
+#else
bool
fdflag_close_exec(int fd, bool flag)
{
@@ -61,17 +79,23 @@ fdflag_close_exec(int fd, bool flag)
mode = flag ? (oflag | FD_CLOEXEC) : (oflag & ~FD_CLOEXEC);
return (fcntl(fd, F_SETFD, mode) == 0);
}
+#endif
/*
* Set a file descriptor to nonblocking (or clear the nonblocking flag if flag
* is false), returning true on success and false on failure.
*
- * Always use O_NONBLOCK; O_NDELAY is not the same thing historically. The
- * semantics of O_NDELAY are that if the read would block, it returns 0
- * instead. This is indistinguishable from an end of file condition. POSIX
- * added O_NONBLOCK, which requires read to return -1 and set errno to EAGAIN,
- * which is what we want.
+ * For Windows, be aware that this will only work for sockets. For UNIX, you
+ * can pass a non-socket in and it will do the right thing, since UNIX doesn't
+ * distinguish, but Windows will not allow that. Thankfully, there's rarely
+ * any need to set non-sockets non-blocking.
+ *
+ * For UNIX, always use O_NONBLOCK; O_NDELAY is not the same thing
+ * historically. The semantics of O_NDELAY are that if the read would block,
+ * it returns 0 instead. This is indistinguishable from an end of file
+ * condition. POSIX added O_NONBLOCK, which requires read to return -1 and
+ * set errno to EAGAIN, which is what we want.
*
* FNDELAY (4.3BSD) originally did the correct thing, although it has a
* different incompatibility (affecting all users of a socket rather than just
@@ -93,9 +117,18 @@ fdflag_close_exec(int fd, bool flag)
* O_NONBLOCK). Accordingly, we currently unconditionally use O_NONBLOCK. If
* this causes too many problems, an autoconf test may be required.
*/
-#ifdef O_NONBLOCK
+#if defined(_WIN32)
+bool
+fdflag_nonblocking(socket_type fd, bool flag)
+{
+ u_long mode;
+
+ mode = flag ? 1 : 0;
+ return (ioctlsocket(fd, FIONBIO, &mode) == 0);
+}
+#elif defined(O_NONBLOCK)
bool
-fdflag_nonblocking(int fd, bool flag)
+fdflag_nonblocking(socket_type fd, bool flag)
{
int mode;
@@ -106,8 +139,8 @@ fdflag_nonblocking(int fd, bool flag)
return (fcntl(fd, F_SETFL, mode) == 0);
}
#else /* !O_NONBLOCK */
-int
-nonblocking(int fd, bool flag)
+bool
+fdflag_nonblocking(socket_type fd, bool flag)
{
int state;
diff --git a/util/fdflag.h b/util/fdflag.h
index 6b8af60..bed45da 100644
--- a/util/fdflag.h
+++ b/util/fdflag.h
@@ -1,7 +1,10 @@
/*
* Prototypes for setting or clearing file descriptor flags.
*
- * Copyright 2008, 2010
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
+ * Copyright 2008, 2010, 2011
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006
* by Internet Systems Consortium, Inc. ("ISC")
@@ -30,15 +33,22 @@
#include <config.h>
#include <portable/macros.h>
#include <portable/stdbool.h>
+#include <portable/socket.h>
BEGIN_DECLS
/* Default to a hidden visibility for all util functions. */
#pragma GCC visibility push(hidden)
-/* Set a file descriptor close-on-exec or nonblocking. */
+/*
+ * Set a file descriptor close-on-exec or nonblocking. fdflag_close_exec is
+ * not supported on Windows and will always return false. fdflag_nonblocking
+ * is defined to take a socket_type so that it can be supported on Windows.
+ * On UNIX systems, you can safely pass in a non-socket file descriptor, but
+ * be aware that this will fail to compile on Windows.
+ */
bool fdflag_close_exec(int fd, bool flag);
-bool fdflag_nonblocking(int fd, bool flag);
+bool fdflag_nonblocking(socket_type fd, bool flag);
/* Undo default visibility change. */
#pragma GCC visibility pop
diff --git a/util/macros.h b/util/macros.h
index 084a5a2..54faee5 100644
--- a/util/macros.h
+++ b/util/macros.h
@@ -1,6 +1,9 @@
/*
* Some standard helpful macros.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
*
* The authors hereby relinquish any claim to any copyright that they may have
@@ -17,6 +20,15 @@
#include <portable/macros.h>
+/*
+ * Used for iterating through arrays. ARRAY_SIZE returns the number of
+ * elements in the array (useful for a < upper bound in a for loop) and
+ * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it
+ * legal to refer to such a pointer as long as it's never dereferenced).
+ */
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)])
+
/* Used for unused parameters to silence gcc warnings. */
#define UNUSED __attribute__((__unused__))
diff --git a/util/messages.c b/util/messages.c
index 01038d6..52fcfb7 100644
--- a/util/messages.c
+++ b/util/messages.c
@@ -50,6 +50,9 @@
* generates given the format and arguments), a format, an argument list as a
* va_list, and the applicable errno value (if any).
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
* Copyright 2008, 2009, 2010
* The Board of Trustees of the Leland Stanford Junior University
@@ -204,8 +207,8 @@ message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err)
buffer = malloc(len + 1);
if (buffer == NULL) {
- fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s",
- len + 1, __FILE__, __LINE__, strerror(errno));
+ fprintf(stderr, "failed to malloc %lu bytes at %s line %d: %s",
+ (unsigned long) len + 1, __FILE__, __LINE__, strerror(errno));
exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
}
vsnprintf(buffer, len + 1, fmt, args);
diff --git a/util/messages.h b/util/messages.h
index 05dacac..0f8b5b6 100644
--- a/util/messages.h
+++ b/util/messages.h
@@ -1,6 +1,9 @@
/*
* Prototypes for message and error reporting (possibly fatal).
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Copyright 2008, 2010
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006
@@ -91,7 +94,7 @@ void message_log_syslog_crit(size_t, const char *, va_list, int)
__attribute__((__nonnull__));
/* The type of a message handler. */
-typedef void (*message_handler_func)(size_t, const char *, va_list, int);
+typedef void (*message_handler_func)(unsigned int, const char *, va_list, int);
/* If non-NULL, called before exit and its return value passed to exit. */
extern int (*message_fatal_cleanup)(void);
diff --git a/util/network.c b/util/network.c
index 50d7f8d..b88f83b 100644
--- a/util/network.c
+++ b/util/network.c
@@ -10,6 +10,15 @@
* implementations for functions that aren't found on some pre-IPv6 systems.
* No other part of the source tree should have to care about IPv4 vs. IPv6.
*
+ * In this file, casts through void * or const void * of struct sockaddr *
+ * parameters are to silence gcc warnings with -Wcast-align. The specific
+ * address types often require stronger alignment than a struct sockaddr, and
+ * were originally allocated with that alignment. GCC doesn't have a good way
+ * of knowing that this code is correct.
+ *
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
* Copyright 2009, 2011
* The Board of Trustees of the Leland Stanford Junior University
@@ -39,7 +48,14 @@
#include <portable/socket.h>
#include <errno.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <util/fdflag.h>
#include <util/messages.h>
#include <util/network.h>
#include <util/xmalloc.h>
@@ -218,7 +234,7 @@ network_bind_ipv6(const char *address, unsigned short port)
*/
#if HAVE_INET6
void
-network_bind_all(unsigned short port, int **fds, unsigned int *count)
+network_bind_all(unsigned short port, socket_type **fds, unsigned int *count)
{
struct addrinfo hints, *addrs, *addr;
unsigned int size;
@@ -245,7 +261,7 @@ network_bind_all(unsigned short port, int **fds, unsigned int *count)
* assuming an IPv6 and IPv4 socket, and grow it by two when necessary.
*/
size = 2;
- *fds = xmalloc(size * sizeof(int));
+ *fds = xmalloc(size * sizeof(socket_type));
for (addr = addrs; addr != NULL; addr = addr->ai_next) {
network_sockaddr_sprint(name, sizeof(name), addr->ai_addr);
if (addr->ai_family == AF_INET)
@@ -285,6 +301,18 @@ network_bind_all(unsigned short port, socket_type **fds, unsigned int *count)
/*
+ * Free the array of file descriptors allocated by network_bind_all. This is
+ * a simple wrapper around free, needed on platforms where libraries allocate
+ * memory from a different memory domain than programs (such as Windows).
+ */
+void
+network_bind_all_free(socket_type *fds)
+{
+ free(fds);
+}
+
+
+/*
* Given an array of file descriptors and the length of that array (the same
* data that's returned by network_bind_all), wait for an incoming connection
* on any of those sockets, accept the connection with accept(), and return
@@ -327,7 +355,10 @@ network_accept_any(socket_type fds[], unsigned int count,
fd = fds[i];
break;
}
- return accept(fd, addr, addrlen);
+ if (fd == INVALID_SOCKET)
+ return INVALID_SOCKET;
+ else
+ return accept(fd, addr, addrlen);
}
@@ -336,18 +367,18 @@ network_accept_any(socket_type fds[], unsigned int count,
* using the provided source address. Returns true on success and false on
* failure.
*/
-static int
+static bool
network_source(socket_type fd, int family, const char *source)
{
if (source == NULL || strcmp(source, "all") == 0)
- return 1;
+ return true;
if (family == AF_INET) {
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
if (!inet_aton(source, &saddr.sin_addr))
- return 0;
+ return false;
return bind(fd, (struct sockaddr *) &saddr, sizeof(saddr)) == 0;
}
#ifdef HAVE_INET6
@@ -357,7 +388,7 @@ network_source(socket_type fd, int family, const char *source)
memset(&saddr, 0, sizeof(saddr));
saddr.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, source, &saddr.sin6_addr) < 1)
- return 0;
+ return false;
return bind(fd, (struct sockaddr *) &saddr, sizeof(saddr)) == 0;
}
#endif
@@ -367,7 +398,7 @@ network_source(socket_type fd, int family, const char *source)
#else
socket_set_errno(EINVAL);
#endif
- return 0;
+ return false;
}
}
@@ -381,13 +412,15 @@ network_source(socket_type fd, int family, const char *source)
* errno.
*/
socket_type
-network_connect(struct addrinfo *ai, const char *source)
+network_connect(struct addrinfo *ai, const char *source, time_t timeout)
{
socket_type fd = INVALID_SOCKET;
- int oerrno;
- int success;
+ int oerrno, status, err;
+ socklen_t len;
+ struct timeval tv;
+ fd_set set;
- for (success = 0; ai != NULL; ai = ai->ai_next) {
+ for (status = -1; status != 0 && ai != NULL; ai = ai->ai_next) {
if (fd != INVALID_SOCKET)
socket_close(fd);
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
@@ -395,15 +428,34 @@ network_connect(struct addrinfo *ai, const char *source)
continue;
if (!network_source(fd, ai->ai_family, source))
continue;
- if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) {
- success = 1;
- break;
+ if (timeout == 0)
+ status = connect(fd, ai->ai_addr, ai->ai_addrlen);
+ else {
+ fdflag_nonblocking(fd, true);
+ status = connect(fd, ai->ai_addr, ai->ai_addrlen);
+ if (status < 0 && socket_errno == EINPROGRESS) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ status = select(fd + 1, NULL, &set, NULL, &tv);
+ if (status == 0 && !FD_ISSET(fd, &set)) {
+ status = -1;
+ socket_set_errno(ETIMEDOUT);
+ } else if (status > 0 && FD_ISSET(fd, &set)) {
+ len = sizeof(err);
+ status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+ if (status == 0)
+ status = err;
+ }
+ }
+ fdflag_nonblocking(fd, false);
}
}
- if (success)
+ if (status == 0)
return fd;
else {
- if (fd >= 0) {
+ if (fd != INVALID_SOCKET) {
oerrno = socket_errno;
socket_close(fd);
socket_set_errno(oerrno);
@@ -421,7 +473,7 @@ network_connect(struct addrinfo *ai, const char *source)
*/
socket_type
network_connect_host(const char *host, unsigned short port,
- const char *source)
+ const char *source, time_t timeout)
{
struct addrinfo hints, *ai;
char portbuf[16];
@@ -434,7 +486,7 @@ network_connect_host(const char *host, unsigned short port,
snprintf(portbuf, sizeof(portbuf), "%d", port);
if (getaddrinfo(host, portbuf, &hints, &ai) != 0)
return INVALID_SOCKET;
- fd = network_connect(ai, source);
+ fd = network_connect(ai, source, timeout);
oerrno = socket_errno;
freeaddrinfo(ai);
socket_set_errno(oerrno);
@@ -483,7 +535,7 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr)
if (addr->sa_family == AF_INET6) {
const struct sockaddr_in6 *sin6;
- sin6 = (const struct sockaddr_in6 *) addr;
+ sin6 = (const struct sockaddr_in6 *) (const void *) addr;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct in_addr in;
@@ -497,7 +549,7 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr)
if (addr->sa_family == AF_INET) {
const struct sockaddr_in *sin;
- sin = (const struct sockaddr_in *) addr;
+ sin = (const struct sockaddr_in *) (const void *) addr;
result = inet_ntop(AF_INET, &sin->sin_addr, dst, size);
return (result != NULL);
} else {
@@ -515,20 +567,26 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr)
bool
network_sockaddr_equal(const struct sockaddr *a, const struct sockaddr *b)
{
- const struct sockaddr_in *a4 = (const struct sockaddr_in *) a;
- const struct sockaddr_in *b4 = (const struct sockaddr_in *) b;
-
+ const struct sockaddr_in *a4;
+ const struct sockaddr_in *b4;
#ifdef HAVE_INET6
- const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) a;
- const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *) b;
+ const struct sockaddr_in6 *a6;
+ const struct sockaddr_in6 *b6;
const struct sockaddr *tmp;
+#endif
+
+ a4 = (const struct sockaddr_in *) (const void *) a;
+ b4 = (const struct sockaddr_in *) (const void *) b;
+#ifdef HAVE_INET6
+ a6 = (const struct sockaddr_in6 *) (const void *) a;
+ b6 = (const struct sockaddr_in6 *) (const void *) b;
if (a->sa_family == AF_INET && b->sa_family == AF_INET6) {
tmp = a;
a = b;
b = tmp;
- a6 = (const struct sockaddr_in6 *) a;
- b4 = (const struct sockaddr_in *) b;
+ a6 = (const struct sockaddr_in6 *) (const void *) a;
+ b4 = (const struct sockaddr_in *) (const void *) b;
}
if (a->sa_family == AF_INET6) {
if (b->sa_family == AF_INET6)
@@ -564,14 +622,14 @@ network_sockaddr_port(const struct sockaddr *sa)
const struct sockaddr_in6 *sin6;
if (sa->sa_family == AF_INET6) {
- sin6 = (const struct sockaddr_in6 *) sa;
+ sin6 = (const struct sockaddr_in6 *) (const void *) sa;
return htons(sin6->sin6_port);
}
#endif
if (sa->sa_family != AF_INET)
return 0;
else {
- sin = (const struct sockaddr_in *) sa;
+ sin = (const struct sockaddr_in *) (const void *) sa;
return htons(sin->sin_port);
}
}
diff --git a/util/network.h b/util/network.h
index d528a1a..5c4d981 100644
--- a/util/network.h
+++ b/util/network.h
@@ -1,6 +1,9 @@
/*
* Prototypes for network connection utility functions.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
* Copyright 2009, 2010, 2011
* The Board of Trustees of the Leland Stanford Junior University
@@ -56,11 +59,13 @@ socket_type network_bind_ipv6(const char *address, unsigned short port)
* and one for IPv6, if IPv6 support is enabled). If IPv6 is not enabled,
* just one socket will be created and bound to the IPv4 wildcard address.
* fds will be set to an array containing the resulting file descriptors, with
- * count holding the count returned.
+ * count holding the count returned. Use network_bind_all_free to free the
+ * array of file descriptors when no longer needed.
*/
void network_bind_all(unsigned short port, socket_type **fds,
unsigned int *count)
__attribute__((__nonnull__));
+void network_bind_all_free(socket_type *fds);
/*
* Accept an incoming connection from any file descriptor in an array. This
@@ -78,9 +83,9 @@ socket_type network_accept_any(socket_type fds[], unsigned int count,
* Create a socket and connect it to the remote service given by the linked
* list of addrinfo structs. Returns the new file descriptor on success and
* -1 on failure, with the error left in errno. Takes an optional source
- * address.
+ * address and a timeout in seconds, which may be 0 for no timeout.
*/
-socket_type network_connect(struct addrinfo *, const char *source)
+socket_type network_connect(struct addrinfo *, const char *source, time_t)
__attribute__((__nonnull__(1)));
/*
@@ -88,7 +93,7 @@ socket_type network_connect(struct addrinfo *, const char *source)
* fails, errno may not be set to anything useful.
*/
socket_type network_connect_host(const char *host, unsigned short port,
- const char *source)
+ const char *source, time_t)
__attribute__((__nonnull__(1)));
/*
diff --git a/util/vector.c b/util/vector.c
index 5138438..285969c 100644
--- a/util/vector.c
+++ b/util/vector.c
@@ -20,6 +20,9 @@
* and perform the same operations, but I'm leery of doing that as I'm not
* sure if it's a violation of the C type aliasing rules.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
*
* The authors hereby relinquish any claim to any copyright that they may have
@@ -345,7 +348,7 @@ vector_split_multi(const char *string, const char *seps,
if (vector->allocated < count)
vector_resize(vector, count);
- for (start = string, p = string, i = 0; *p; p++)
+ for (start = string, p = string, i = 0; *p != '\0'; p++)
if (strchr(seps, *p) != NULL) {
if (start != p)
vector->strings[i++] = xstrndup(start, p - start);
@@ -378,7 +381,7 @@ cvector_split_multi(char *string, const char *seps, struct cvector *vector)
if (vector->allocated < count)
cvector_resize(vector, count);
- for (start = string, p = string, i = 0; *p; p++)
+ for (start = string, p = string, i = 0; *p != '\0'; p++)
if (strchr(seps, *p) != NULL) {
if (start != p) {
*p = '\0';
@@ -438,7 +441,7 @@ vector_split_space(const char *string, struct vector *vector)
if (vector->allocated < count)
vector_resize(vector, count);
- for (start = string, p = string, i = 0; *p; p++)
+ for (start = string, p = string, i = 0; *p != '\0'; p++)
if (*p == ' ' || *p == '\t') {
if (start != p)
vector->strings[i++] = xstrndup(start, p - start);
@@ -470,7 +473,7 @@ cvector_split_space(char *string, struct cvector *vector)
if (vector->allocated < count)
cvector_resize(vector, count);
- for (start = string, p = string, i = 0; *p; p++)
+ for (start = string, p = string, i = 0; *p != '\0'; p++)
if (*p == ' ' || *p == '\t') {
if (start != p) {
*p = '\0';
diff --git a/util/vector.h b/util/vector.h
index ac3bf18..6a872d3 100644
--- a/util/vector.h
+++ b/util/vector.h
@@ -8,6 +8,9 @@
* Vectors require list of strings, not arbitrary binary data, and cannot
* handle data elements containing nul characters.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Written by Russ Allbery <rra@stanford.edu>
*
* The authors hereby relinquish any claim to any copyright that they may have
@@ -97,7 +100,9 @@ void cvector_free(struct cvector *)
* Empty strings will yield zero-length vectors. Adjacent delimiters are
* treated as a single delimiter by *_split_space and *_split_multi, but *not*
* by *_split, so callers of *_split should be prepared for zero-length
- * strings in the vector.
+ * strings in the vector. *_split_space and *_split_multi ignore any leading
+ * or trailing delimiters, so those functions will never create zero-length
+ * strings (similar to the behavior of strtok).
*/
struct vector *vector_split(const char *string, char sep, struct vector *)
__attribute__((__nonnull__(1)));
diff --git a/util/xmalloc.c b/util/xmalloc.c
index 0803999..839f5a0 100644
--- a/util/xmalloc.c
+++ b/util/xmalloc.c
@@ -55,6 +55,9 @@
* header file defines macros named xmalloc, etc. that pass the file name and
* line number to these functions.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Copyright (c) 2004, 2005, 2006
* by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
diff --git a/util/xmalloc.h b/util/xmalloc.h
index 5447335..14d8831 100644
--- a/util/xmalloc.h
+++ b/util/xmalloc.h
@@ -1,6 +1,9 @@
/*
* Prototypes for malloc routines with failure handling.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Copyright 2010
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006
diff --git a/util/xwrite.c b/util/xwrite.c
index 7e27654..8d472a7 100644
--- a/util/xwrite.c
+++ b/util/xwrite.c
@@ -21,6 +21,9 @@
* written, on the subsequent additional write; in that case, these functions
* will return -1 and the number of bytes actually written will be lost.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Copyright 2008
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006
diff --git a/util/xwrite.h b/util/xwrite.h
index d79e801..2822727 100644
--- a/util/xwrite.h
+++ b/util/xwrite.h
@@ -1,6 +1,9 @@
/*
* Prototypes for write and writev replacements to handle partial writes.
*
+ * The canonical version of this file is maintained in the rra-c-util package,
+ * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.
+ *
* Copyright 2008, 2010
* The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2004, 2005, 2006