diff options
-rw-r--r-- | bar.c | 12 | ||||
-rw-r--r-- | spawn.c | 11 | ||||
-rw-r--r-- | util.c | 55 | ||||
-rw-r--r-- | util.h | 20 |
4 files changed, 80 insertions, 18 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 = 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. */ @@ -189,12 +189,9 @@ static void bfs_spawn_exec(const char *exe, const struct bfs_spawn *ctx, char ** fail: error = errno; - while (write(pipefd[1], &error, sizeof(error)) < 0) { - if (errno != EINTR) { - // Parent will still see that we exited unsuccessfully, but won't know why - break; - } - } + // In case of write error parent will still see that we exited + // unsuccessfully, but won't know why. + (void) safe_write_all(pipefd[1], &error, sizeof(error)); close(pipefd[1]); _Exit(127); @@ -224,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 = 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; @@ -368,3 +368,58 @@ int bfs_minor(dev_t dev) { return dev & 0xFF; #endif } + +ssize_t safe_read(int fd, void *buf, size_t nbytes) { + for (;;) { + ssize_t ret = read(fd, buf, nbytes); + if (ret < 0 && errno == EINTR) { + continue; + } + return ret; + } +} + +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); + if (ret < 0 && errno == EINTR) { + continue; + } + 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; + } + } +} @@ -225,4 +225,24 @@ int bfs_major(dev_t dev); */ int bfs_minor(dev_t dev); +/** + * A safe version of read() that handles interrupted system calls. + */ +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 |