diff --git a/src/command.c b/src/command.c index 10e9e7e..28df8e2 100644 --- a/src/command.c +++ b/src/command.c @@ -320,10 +320,18 @@ struct Value *handle_lcd_command(String *args, int offset) } #if HAVE_GETCWD - oprintf("%% Current directory is %s", getcwd(buffer, PATH_MAX)); + if (!getcwd(buffer, sizeof(buffer))) { + operror("getcwd"); + return shareval(val_zero); + } + oprintf("%% Current directory is %s", buffer); #else # if HAVE_GETWD - oprintf("%% Current directory is %s", getwd(buffer)); + if (!getwd(buffer)) { + operror("getwd"); + return shareval(val_zero); + } + oprintf("%% Current directory is %s", buffer); # endif #endif return shareval(val_one); @@ -359,8 +367,11 @@ int handle_echo_func( return 0; } if (raw) { - write(STDOUT_FILENO, src->data, src->len); - return 1; + if (write_full(STDOUT_FILENO, src->data, src->len) < 0) { + operror("write"); + return 0; + } + return 1; } newstr = inline_flag ? CS(decode_attr(src, 0, 0)) : CS(Stringdup(src)); @@ -823,4 +834,3 @@ struct Value *handle_bind_command(String *args, int offset) return newint(add_new_macro(NULL, print_to_ascii(NULL, pattern)->data, NULL, NULL, body, 1, 100, 0, FALSE, 0)); } - diff --git a/src/output.c b/src/output.c index dc077c5..2351ba6 100644 --- a/src/output.c +++ b/src/output.c @@ -349,8 +349,12 @@ void bufflush(void) n = outbuf->len - written; if (n > 2048) n = 2048; - result = write(STDOUT_FILENO, outbuf->data + written, n); - if (result < 0) break; + RETRY_ON_EINTR(result, write(STDOUT_FILENO, + outbuf->data + written, n)); + if (result < 0) + break; + if (result == 0) + break; written += result; } Stringtrunc(outbuf, 0); diff --git a/src/port.h b/src/port.h index 190e30b..3cc2372 100644 --- a/src/port.h +++ b/src/port.h @@ -79,6 +79,11 @@ extern int errno; /* Some systems don't declare errno in errno.h. Duh. */ #include +#define RETRY_ON_EINTR(result, expr) \ + do { \ + (result) = (expr); \ + } while ((result) == -1 && errno == EINTR) + #ifndef SEEK_SET # define SEEK_SET 0 #endif diff --git a/src/signals.c b/src/signals.c index b33a60a..e3dfe04 100644 --- a/src/signals.c +++ b/src/signals.c @@ -434,9 +434,11 @@ void init_exename(char *name) { argv0 = name; #if HAVE_GETCWD - getcwd(initial_dir, PATH_MAX); + if (!getcwd(initial_dir, sizeof(initial_dir))) + initial_dir[0] = '\0'; #elif HAVE_GETWD - getwd(initial_dir); + if (!getwd(initial_dir)) + initial_dir[0] = '\0'; #endif initial_path = getenv("PATH"); } diff --git a/src/socket.c b/src/socket.c index 39bba0a..67a73a9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -342,6 +342,9 @@ static Sock *find_sock(const char *name); static void wload(World *w); static int fg_sock(Sock *sock, int quiet); static int get_host_address(Sock *sock, const char **what, int *errp); +#ifdef NONBLOCKING_GETHOST +static void close_resolver(Sock *sock); +#endif #if !HAVE_GETADDRINFO static int tfgetaddrinfo(const char *nodename, const char *port, const struct addrinfo *hints, struct addrinfo **res); @@ -1491,6 +1494,29 @@ static int ICONFAIL(Sock *sock, const char *what, const char *why) return 0; } +#ifdef NONBLOCKING_GETHOST +static void close_resolver(Sock *sock) +{ +#ifdef PLATFORM_UNIX + pid_t pid; +#endif /* PLATFORM_UNIX */ + + if (sock->fd >= 0) { + close(sock->fd); + sock->fd = -1; + } +#ifdef PLATFORM_UNIX + if (sock->pid >= 0) { + RETRY_ON_EINTR(pid, waitpid(sock->pid, NULL, 0)); + if (pid < 0) + tfprintf(tferr, "waitpid %ld: %s", (long)sock->pid, + strerror(errno)); + sock->pid = -1; + } +#endif /* PLATFORM_UNIX */ +} +#endif + static int openconn(Sock *sock) { int flags; @@ -1500,41 +1526,34 @@ static int openconn(Sock *sock) if (xsock->constate == SS_RESOLVING) { nbgai_hdr_t info = { 0, 0 }; struct addrinfo *ai; - FD_CLR(xsock->fd, &readers); - if (read(xsock->fd, &info, sizeof(info)) < 0 || info.err != 0) { - if (!info.err) - CONFAIL(xsock, "read", strerror(errno)); - else - CONFAILHP(xsock, gai_strerror(info.err)); - if (xsock->fd >= 0) { - close(xsock->fd); - xsock->fd = -1; - } -# ifdef PLATFORM_UNIX - if (xsock->pid >= 0) - if (waitpid(xsock->pid, NULL, 0) < 0) - tfprintf(tferr, "waitpid %ld: %s", xsock->pid, strerror(errno)); - xsock->pid = -1; -# endif /* PLATFORM_UNIX */ - killsock(xsock); - return 0; - } + FD_CLR(xsock->fd, &readers); + if (read_full(xsock->fd, (char *)&info, sizeof(info)) < 0) { + CONFAIL(xsock, "read", strerror(errno)); + close_resolver(xsock); + killsock(xsock); + return 0; + } + if (info.err != 0) { + CONFAILHP(xsock, gai_strerror(info.err)); + close_resolver(xsock); + killsock(xsock); + return 0; + } if (info.size <= 0) { /* shouldn't happen */ xsock->addrs = NULL; } else { xsock->addrs = XMALLOC(info.size); - read(xsock->fd, (char*)xsock->addrs, info.size); + if (read_full(xsock->fd, (char *)xsock->addrs, info.size) < 0) { + CONFAIL(xsock, "read", strerror(errno)); + FREE(xsock->addrs); + xsock->addrs = NULL; + close_resolver(xsock); + killsock(xsock); + return 0; + } } - if (xsock->fd >= 0) { - close(xsock->fd); - } -# ifdef PLATFORM_UNIX - if (xsock->pid >= 0) - if (waitpid(xsock->pid, NULL, 0) < 0) - tfprintf(tferr, "waitpid: %ld: %s", xsock->pid, strerror(errno)); - xsock->pid = -1; -# endif /* PLATFORM_UNIX */ - xsock->constate = SS_RESOLVED; + close_resolver(xsock); + xsock->constate = SS_RESOLVED; for (ai = xsock->addrs; ai; ai = ai->ai_next) { ai->ai_addr = (struct sockaddr*)((char*)ai + sizeof(*ai)); if (ai->ai_next != 0) { @@ -1851,11 +1870,13 @@ static void waitforhostname(int fd, const char *name, const char *port) iov[niov].iov_len = ai->ai_addrlen; niov++; } - writev(fd, iov, niov); + (void)writev_full(fd, iov, niov); if (res) freeaddrinfo(res); } else { hdr.size = 0; - write(fd, &hdr, sizeof(hdr)); + iov[0].iov_base = (char *)&hdr; + iov[0].iov_len = sizeof(hdr); + (void)writev_full(fd, iov, 1); } close(fd); } @@ -1954,9 +1975,13 @@ static int establish(Sock *sock) } else if ((ai_connect(xsock->fd, xsock->addr) < 0) && errno != EISCONN) { - read(xsock->fd, &ch, 1); /* must fail */ - return ICONFAIL(xsock, "nonblocking connect 2/read", strerror(errno)); - } + int connect_err = errno; + if (read(xsock->fd, &ch, 1) < 0) /* must fail */ + return ICONFAIL(xsock, "nonblocking connect 2/read", + strerror(errno)); + return ICONFAIL(xsock, "nonblocking connect 2", + strerror(connect_err)); + } } #endif if (err != 0) { @@ -2115,9 +2140,13 @@ static void killsock(Sock *sock) #ifdef NONBLOCKING_GETHOST # ifdef PLATFORM_UNIX if (sock->pid >= 0) { + pid_t pid; + kill(sock->pid, SIGTERM); - if (waitpid(sock->pid, NULL, 0) < 0) - tfprintf(tferr, "waitpid: %ld: %s", sock->pid, strerror(errno)); + RETRY_ON_EINTR(pid, waitpid(sock->pid, NULL, 0)); + if (pid < 0) + tfprintf(tferr, "waitpid: %ld: %s", (long)sock->pid, + strerror(errno)); sock->pid = -1; } # endif /* PLATFORM_UNIX */ diff --git a/src/tfio.c b/src/tfio.c index fbcd899..2d27241 100644 --- a/src/tfio.c +++ b/src/tfio.c @@ -788,11 +788,27 @@ char igetchar(void) { char c; fd_set readers; + int result; - FD_ZERO(&readers); - FD_SET(STDIN_FILENO, &readers); - while(select(1, &readers, NULL, NULL, NULL) <= 0); - read(STDIN_FILENO, &c, 1); + for (;;) { + FD_ZERO(&readers); + FD_SET(STDIN_FILENO, &readers); + result = select(STDIN_FILENO + 1, &readers, NULL, NULL, NULL); + if (result > 0) + break; + if (result < 0) { + if (errno == EINTR) + continue; + operror("select"); + return '\0'; + } + } + RETRY_ON_EINTR(result, read(STDIN_FILENO, &c, 1)); + if (result != 1) { + if (result < 0) + operror("read"); + return '\0'; + } return c; } @@ -900,8 +916,11 @@ String *tfgetS(String *str, TFILE *file) file->off = next; } file->off = 0; - file->len = read(fileno(file->u.fp), file->buf, sizeof(file->buf)); - } while (file->len > 0); + RETRY_ON_EINTR(file->len, read(fileno(file->u.fp), file->buf, + sizeof(file->buf))); + if (file->len < 0) + operror("read"); + } while (file->len > 0); file->len = -1; /* note eof */ return str->len ? str : NULL; @@ -1004,4 +1023,3 @@ struct Value *handle_liststreams_command(String *args, int offset) return newint(count); } - diff --git a/src/util.c b/src/util.c index a3c432b..1fe2ea0 100644 --- a/src/util.c +++ b/src/util.c @@ -22,6 +22,7 @@ #endif #include #include +#include #include #include "port.h" #include "tf.h" @@ -81,6 +82,72 @@ struct feature features[] = { static void free_maillist(void); +int read_full(int fd, char *buf, size_t len) +{ + size_t off = 0; + + while (off < len) { + ssize_t result; + + RETRY_ON_EINTR(result, read(fd, buf + off, len - off)); + if (result < 0) + return -1; + if (result == 0) { + errno = EIO; + return -1; + } + off += result; + } + return 0; +} + +int write_full(int fd, const char *buf, size_t len) +{ + size_t off = 0; + + while (off < len) { + ssize_t result; + + RETRY_ON_EINTR(result, write(fd, buf + off, len - off)); + if (result < 0) + return -1; + if (result == 0) { + errno = EIO; + return -1; + } + off += result; + } + return 0; +} + +int writev_full(int fd, struct iovec *iov, int niov) +{ + while (niov > 0) { + ssize_t result; + size_t written; + + RETRY_ON_EINTR(result, writev(fd, iov, niov)); + if (result < 0) + return -1; + if (result == 0) { + errno = EIO; + return -1; + } + + written = result; + while (niov > 0 && written >= iov[0].iov_len) { + written -= iov[0].iov_len; + iov++; + niov--; + } + if (niov > 0 && written > 0) { + iov[0].iov_base = (char *)iov[0].iov_base + written; + iov[0].iov_len -= written; + } + } + return 0; +} + #if !STDC_HEADERS int lcase(x) char x; { return is_upper(x) ? tolower(x) : x; } int ucase(x) char x; { return is_lower(x) ? toupper(x) : x; } diff --git a/src/util.h b/src/util.h index 87def47..5d08d90 100644 --- a/src/util.h +++ b/src/util.h @@ -14,6 +14,8 @@ struct feature { const int *flag; }; +struct iovec; + #undef CTRL /* convert to or from ctrl character */ #define CTRL(c) (ucase(c) ^ '@') @@ -101,6 +103,10 @@ extern const conString* print_to_ascii(String *buf, const char *str); extern const conString* ascii_to_print(const char *str); extern char *cstrchr(const char *s, int c); extern char *estrchr(const char *s, int c, int e); +extern int read_full(int fd, char *buf, size_t len); +extern int write_full(int fd, const char *buf, size_t len); +/* writev_full() mutates iov while advancing through partial writes. */ +extern int writev_full(int fd, struct iovec *iov, int niov); extern int numarg(const char **str); extern int nullstrcmp(const char *s, const char *t); extern int nullcstrcmp(const char *s, const char *t);