diff options
-rw-r--r-- | src/coopgammad.c | 268 | ||||
-rw-r--r-- | src/state.c | 9 |
2 files changed, 144 insertions, 133 deletions
diff --git a/src/coopgammad.c b/src/coopgammad.c index 67dc0e4..a2eddab 100644 --- a/src/coopgammad.c +++ b/src/coopgammad.c @@ -145,6 +145,7 @@ static void sig_terminate(int signo) static void sig_connection(int signo) { connection = signo - SIGRTMIN + 1; + signal(signo, sig_connection); } @@ -184,6 +185,22 @@ static int get_method(const char* restrict arg) /** + * Set up signal handlers + * + * @return Zero on success, -1 on error + */ +static int set_up_signals(void) +{ + if ((signal(SIGUSR1, sig_reexec) == SIG_ERR) || + (signal(SIGTERM, sig_terminate) == SIG_ERR) || + (signal(SIGRTMIN + 0, sig_connection) == SIG_ERR) || + (signal(SIGRTMIN + 1, sig_connection) == SIG_ERR)) + return -1; + return 0; +} + + +/** * Fork the process to the background * * @param keep_stderr Keep stderr open? @@ -275,14 +292,12 @@ static enum init_status daemonise(int keep_stderr) /** * Initialise the process * - * @param full Perform a full initialisation, shall be done - * iff the state is not going to be unmarshalled * @param foreground Keep process in the foreground * @param keep_stderr Keep stderr open * @param query Was -q used, see `main` for description * @return An `enum init_status` value or an exit value */ -static enum init_status initialise(int full, int foreground, int keep_stderr, int query) +static enum init_status initialise(int foreground, int keep_stderr, int query) { struct rlimit rlimit; size_t i, n; @@ -293,7 +308,7 @@ static enum init_status initialise(int full, int foreground, int keep_stderr, in /* Zero out some memory so it can be destoried safely. */ memset(&site, 0, sizeof(site)); - if (full && !query) + if (!query) { /* Close all file descriptors above stderr */ if (getrlimit(RLIMIT_NOFILE, &rlimit) || (rlimit.rlim_cur == RLIM_INFINITY)) @@ -325,21 +340,18 @@ static enum init_status initialise(int full, int foreground, int keep_stderr, in if (initialise_site() < 0) goto fail; - if (full) + /* Get PID file and socket pathname */ + if (!(pidpath = get_pidfile_pathname()) || + !(socketpath = get_socket_pathname())) + goto fail; + + /* Create PID file */ + if ((r = create_pidfile(pidpath)) < 0) { - /* Get PID file and socket pathname */ - if (!(pidpath = get_pidfile_pathname()) || - !(socketpath = get_socket_pathname())) - goto fail; - - /* Create PID file */ - if ((r = create_pidfile(pidpath)) < 0) - { - free(pidpath), pidpath = NULL; - if (r == -2) - return INIT_RUNNING; - goto fail; - } + free(pidpath), pidpath = NULL; + if (r == -2) + return INIT_RUNNING; + goto fail; } /* Get partitions and CRTC:s */ @@ -362,33 +374,27 @@ static enum init_status initialise(int full, int foreground, int keep_stderr, in if (preserve && (preserve_gamma() < 0)) goto fail; - if (full) - { - /* Create socket and start listening */ - if (create_socket(socketpath) < 0) - goto fail; - - /* Get the real pathname of the process's binary, in case - * it is relative, so we can re-execute without problem. */ - if ((*argv0 != '/') && strchr(argv0, '/') && !(argv0_real = realpath(argv0, NULL))) - goto fail; - - /* Change directory to / to avoid blocking umounting */ - if (chdir("/") < 0) - perror(argv0); - } + /* Create socket and start listening */ + if (create_socket(socketpath) < 0) + goto fail; + + /* Get the real pathname of the process's binary, in case + * it is relative, so we can re-execute without problem. */ + if ((*argv0 != '/') && strchr(argv0, '/') && !(argv0_real = realpath(argv0, NULL))) + goto fail; + + /* Change directory to / to avoid blocking umounting */ + if (chdir("/") < 0) + perror(argv0); /* Set up signal handlers */ - if ((signal(SIGUSR1, sig_reexec) == SIG_ERR) || - (signal(SIGTERM, sig_terminate) == SIG_ERR) || - (signal(SIGRTMIN + 0, sig_connection) == SIG_ERR) || - (signal(SIGRTMIN + 1, sig_connection) == SIG_ERR)) + if (set_up_signals() < 0) goto fail; /* Place in the background unless -f */ - if (full && (foreground == 0)) + if (foreground == 0) return daemonise(keep_stderr); - else if (full) + else { /* Signal the spawner that the service is ready */ close(STDOUT_FILENO); @@ -514,26 +520,26 @@ static size_t unmarshal(const void* restrict buf) /** - * Unmarshal the state of the process and merge with new state + * Do minimal initialisation, unmarshal the state of + * the process and merge with new state * * @param statefile The state file * @return Zero on success, -1 on error */ GCC_ONLY(__attribute__((nonnull))) -static int unmarshal_and_merge_state(const char* restrict statefile) +static int restore_state(const char* restrict statefile) { - struct output* restrict old_outputs = NULL; - size_t i, n, r, old_outputs_n = 0; void* marshalled = NULL; int fd = -1, saved_errno; + size_t r, n; + + if (set_up_signals() < 0) + goto fail; fd = open(statefile, O_RDONLY); if (fd < 0) goto fail; - old_outputs = outputs, outputs = NULL; - old_outputs_n = outputs_n, outputs_n = 0; - if (!(marshalled = nread(fd, &n))) goto fail; close(fd), fd = -1; @@ -549,14 +555,13 @@ static int unmarshal_and_merge_state(const char* restrict statefile) errno = 0; goto fail; } - free(marshalled), marshalled = NULL; - if (merge_state(old_outputs, old_outputs_n) < 0) - goto fail; - - for (i = 0; i < old_outputs_n; i++) - output_destroy(old_outputs + i); - free(old_outputs); + if (connected) + { + connected = 0; + if (reconnect() < 0) + goto fail; + } return 0; fail: @@ -564,15 +569,75 @@ static int unmarshal_and_merge_state(const char* restrict statefile) if (fd >= 0) close(fd); free(marshalled); - for (i = 0; i < old_outputs_n; i++) - output_destroy(old_outputs + i); - free(old_outputs); errno = saved_errno; return -1; } /** + * Reexecute the server + * + * Returns only on failure + * + * @return Pathname of file where the state is stored, + * `NULL` if the state is in tact + */ +static char* reexecute(void) +{ + char* statefile = NULL; + char* statebuffer = NULL; + size_t buffer_size; + int fd = -1, saved_errno; + + 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) + { + fprintf(stderr, "%s: internal error", argv0); + errno = 0; + goto fail; + } + + fd = open(statefile, O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + goto fail; + + if (nwrite(fd, statebuffer, buffer_size) != buffer_size) + goto fail; + free(statebuffer), statebuffer = NULL; + + if ((close(fd) < 0) && (fd = -1, errno != EINTR)) + goto fail; + fd = -1; + + destroy(0); + + execlp(argv0_real ? argv0_real : argv0, argv0, "- ", statefile, NULL); + saved_errno = errno; + free(argv0_real), argv0_real = NULL; + errno = saved_errno; + return statefile; + + fail: + saved_errno = errno; + free(statebuffer); + if (fd >= 0) + close(fd); + if (statefile != NULL) + unlink(statefile), free(statefile); + errno = saved_errno; + return NULL; +} + + + +/** * Print the response for the -q option * * @param query See -q for `main`, must be atleast 1 @@ -641,67 +706,6 @@ static int print_method_and_site(int query) } -/** - * Reexecute the server - * - * Returns only on failure - * - * @return Pathname of file where the state is stored, - * `NULL` if the state is in tact - */ -static char* reexecute(void) -{ - char* statefile = NULL; - char* statebuffer = NULL; - size_t buffer_size; - int fd = -1, saved_errno; - - 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) - { - fprintf(stderr, "%s: internal error", argv0); - errno = 0; - goto fail; - } - - fd = open(statefile, O_CREAT, S_IRUSR | S_IWUSR); - if (fd < 0) - goto fail; - - if (nwrite(fd, statebuffer, buffer_size) != buffer_size) - goto fail; - free(statebuffer), statebuffer = NULL; - - if ((close(fd) < 0) && (fd = -1, errno != EINTR)) - goto fail; - fd = -1; - - destroy(0); - - execlp(argv0_real ? argv0_real : argv0, argv0, "- ", statefile, preserve ? "-p" : NULL, NULL); - saved_errno = errno; - free(argv0_real), argv0_real = NULL; - errno = saved_errno; - return statefile; - - fail: - saved_errno = errno; - free(statebuffer); - if (fd >= 0) - close(fd); - if (statefile != NULL) - unlink(statefile), free(statefile); - errno = saved_errno; - return NULL; -} - /** * Print usage information and exit @@ -798,12 +802,22 @@ int main(int argc, char** argv) restart: - switch ((r = initialise(statefile == NULL, foreground, keep_stderr, query))) + if (statefile == NULL) + switch ((r = initialise(foreground, keep_stderr, query))) + { + case INIT_SUCCESS: break; + case INIT_RUNNING: rc = 2; /* fall through */ + case INIT_FAILURE: goto fail; + default: return r; + } + else if (restore_state(statefile) < 0) + goto fail; + else { - case INIT_SUCCESS: break; - case INIT_RUNNING: rc = 2; /* fall through */ - case INIT_FAILURE: goto fail; - default: return r; + if (reexec) + free(statefile); + unlink(statefile), statefile = NULL; + reexec = 0; /* See `if (reexec && !terminate)` below */ } if (query) @@ -813,16 +827,6 @@ int main(int argc, char** argv) goto done; } - if (statefile != NULL) - { - if (unmarshal_and_merge_state(statefile) < 0) - goto fail; - if (reexec) - free(statefile); - unlink(statefile), statefile = NULL; - reexec = 0; /* See `if (reexec && !terminate)` below */ - } - reenter_loop: if (main_loop() < 0) goto fail; diff --git a/src/state.c b/src/state.c index d140789..c8cb1d9 100644 --- a/src/state.c +++ b/src/state.c @@ -137,7 +137,7 @@ libgamma_crtc_state_t* restrict crtcs = NULL; /* do not marshal */ /** * Preserve gamma ramps at priority 0? */ -int preserve = 0; /* do not marshal, pass on via command line arguments */ +int preserve = 0; @@ -263,6 +263,10 @@ size_t state_marshal(void* restrict buf) off += n; } + if (bs != NULL) + *(int*)(bs + off) = preserve; + off += sizeof(int); + return off; } @@ -354,6 +358,9 @@ size_t state_unmarshal(const void* restrict buf) else off += sizeof(int); + preserve = *(const int*)(bs + off); + off += sizeof(int); + return off; } |