diff options
Diffstat (limited to '')
-rw-r--r-- | src/gammad.c | 53 | ||||
-rw-r--r-- | src/util.c | 39 | ||||
-rw-r--r-- | src/util.h | 16 |
3 files changed, 106 insertions, 2 deletions
diff --git a/src/gammad.c b/src/gammad.c index 254dd52..fa24d82 100644 --- a/src/gammad.c +++ b/src/gammad.c @@ -1210,7 +1210,8 @@ static void usage(void) int main(int argc, char** argv) { int rc = 1, preserve = 0, foreground = 0, keep_stderr = 0, r; - const char* statefile = NULL; + char* statefile = NULL; + char* statebuffer = NULL; ARGBEGIN { @@ -1245,6 +1246,8 @@ int main(int argc, char** argv) if (argc > 0) usage(); + restart: /* If C had comefrom: comefrom reexec_failure; */ + switch ((r = initialise(statefile == NULL, preserve, foreground, keep_stderr))) { case 1: @@ -1265,12 +1268,60 @@ int main(int argc, char** argv) if (unmarshal_and_merge_state(statefile) < 0) goto fail; unlink(statefile), statefile = NULL; + reexec = 0; /* See `if (reexec && !terminate)` */ + } + + if (reexec && !terminate) + { + size_t buffer_size; + int fd; + + /* `reexec = 0;` is done later in case of re-execute failure, + * since it determines whether `statefile` shall be freed. */ + + statefile = get_state_pathname(); + if (statefile == NULL) + goto fail; + + buffer_size = marshal(NULL); + statebuffer = malloc(buffer_size); + if (statebuffer == NULL) + goto fail; + if (marshal(statebuffer) != buffer_size) + abort(); + + fd = open(statefile, O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + goto fail; + + if (nwrite(fd, statebuffer, buffer_size) != buffer_size) + { + perror(argv0); + close(fd); + errno = 0; + goto fail; + } + free(statebuffer), statebuffer = NULL; + + if ((close(fd) < 0) && (errno != EINTR)) + goto fail; + + destroy(0); + + execlp(argv0_real ? argv0_real : argv0, argv0, "-#", statefile, preserve ? "-p" : NULL, NULL); + perror(argv0); + fprintf(stderr, "%s: restoring state without re-executing\n", argv0); + free(argv0_real), argv0_real = NULL; + goto restart; } rc = 0; done: + free(statebuffer); if (statefile) unlink(statefile); + if (reexec) + free(statefile); destroy(1); return rc; fail: @@ -82,7 +82,11 @@ void* nread(int fd, size_t* n) got = read(fd, buf + *n, size - *n); if (got < 0) - goto fail; + { + if (errno == EINTR) + continue; + goto fail; + } if (got == 0) break; *n += (size_t)got; @@ -99,6 +103,39 @@ void* nread(int fd, size_t* n) /** + * Write an entire buffer to a file + * + * Not cancelled by `EINTR` + * + * @param fd The file descriptor + * @param buf The buffer which shall be written to the fail + * @param n The size of the buffer + * @return The number of written bytes, less than `n` + * on error, cannot exceed `n` + */ +size_t nwrite(int fd, const void* buf, size_t n) +{ + const char* bs = buf; + ssize_t wrote; + size_t ptr = 0; + + while (ptr < n) + { + wrote = write(fd, bs + ptr, n - ptr); + if (wrote <= 0) + { + if ((wrote < 0) && (errno == EINTR)) + continue; + return ptr; + } + ptr += (size_t)wrote; + } + + return ptr; +} + + +/** * Duplicate a file descriptor an make sure * the new file descriptor's index as a * specified minimum value @@ -33,6 +33,8 @@ void* memdup(const void* src, size_t n); /** * Read an entire file * + * Not cancelled by `EINTR` + * * @param fd The file descriptor * @param n Output for the size of the file * @return The read content, plus a NUL byte at @@ -42,6 +44,20 @@ void* nread(int fd, size_t* n); /** + * Write an entire buffer to a file + * + * Not cancelled by `EINTR` + * + * @param fd The file descriptor + * @param buf The buffer which shall be written to the fail + * @param n The size of the buffer + * @return The number of written bytes, less than `n` + * on error, cannot exceed `n` + */ +size_t nwrite(int fd, const void* buf, size_t n); + + +/** * Duplicate a file descriptor an make sure * the new file descriptor's index as a * specified minimum value |