diff options
-rw-r--r-- | bar.c | 12 | ||||
-rw-r--r-- | spawn.c | 4 | ||||
-rw-r--r-- | util.c | 35 | ||||
-rw-r--r-- | util.h | 10 |
4 files changed, 48 insertions, 13 deletions
@@ -58,17 +58,7 @@ static int bfs_bar_getsize(struct bfs_bar *bar) { /** Async Signal Safe puts(). */ static int ass_puts(int fd, const char *str) { size_t len = strlen(str); - - while (len > 0) { - ssize_t ret = safe_write(fd, str, len); - if (ret <= 0) { - return -1; - } - str += ret; - len -= ret; - } - - return 0; + return safe_write_all(fd, str, len) == (ssize_t)len ? 0 : -1; } /** Number of decimal digits needed for terminal sizes. */ @@ -191,7 +191,7 @@ fail: // In case of write error parent will still see that we exited // unsuccessfully, but won't know why. - safe_write(pipefd[1], &error, sizeof(error)); + (void) safe_write_all(pipefd[1], &error, sizeof(error)); close(pipefd[1]); _Exit(127); @@ -221,7 +221,7 @@ pid_t bfs_spawn(const char *exe, const struct bfs_spawn *ctx, char **argv, char // Parent close(pipefd[1]); - ssize_t nbytes = safe_read(pipefd[0], &error, sizeof(error)); + ssize_t nbytes = safe_read_all(pipefd[0], &error, sizeof(error)); close(pipefd[0]); if (nbytes == sizeof(error)) { int wstatus; @@ -379,6 +379,23 @@ ssize_t safe_read(int fd, void *buf, size_t nbytes) { } } +ssize_t safe_read_all(int fd, void *buf, size_t nbytes) { + size_t count = 0; + for (;;) { + ssize_t ret = read(fd, (char *)buf + count, nbytes - count); + if (ret < 0 && errno == EINTR) { + continue; + } + if (ret < 0) { + return ret; // always return error < 0 + } + count += ret; + if (ret == 0 || count == nbytes) { // EOF or success + return count; + } + } +} + ssize_t safe_write(int fd, const void *buf, size_t nbytes) { for (;;) { ssize_t ret = write(fd, buf, nbytes); @@ -388,3 +405,21 @@ ssize_t safe_write(int fd, const void *buf, size_t nbytes) { return ret; } } + +ssize_t safe_write_all(int fd, const void *buf, size_t nbytes) +{ + size_t count = 0; + for (;;) { + ssize_t ret = write(fd, (const char *)buf + count, nbytes - count); + if (ret < 0 && errno == EINTR) { + continue; + } + if (ret < 0) { + return ret; // always return error < 0 + } + count += ret; + if (ret == 0 || count == nbytes) { // EOF (should never happen with write) or success + return count; + } + } +} @@ -231,8 +231,18 @@ int bfs_minor(dev_t dev); ssize_t safe_read(int fd, void *buf, size_t nbytes); /** + * A safe version of read() that handles interrupted system calls and partial reads. + */ +ssize_t safe_read_all(int fd, void *buf, size_t nbytes); + +/** * A safe version of write() that handles interrupted system calls. */ ssize_t safe_write(int fd, const void *buf, size_t nbytes); +/** + * A safe version of write() that handles interrupted system calls and partial writes. + */ +ssize_t safe_write_all(int fd, const void *buf, size_t nbytes); + #endif // BFS_UTIL_H |