diff options
Diffstat (limited to '')
-rw-r--r-- | src/common.c (renamed from src/daemon.c) | 213 |
1 files changed, 113 insertions, 100 deletions
diff --git a/src/daemon.c b/src/common.c index a39b0e3..a6f4c7c 100644 --- a/src/daemon.c +++ b/src/common.c @@ -19,12 +19,10 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "daemon.h" +#include "common.h" #include <ctype.h> -#include <signal.h> #include <stdarg.h> -#include <sys/stat.h> -#include <sys/file.h> +#include <pwd.h> #include <sys/wait.h> @@ -101,50 +99,6 @@ pwriten(int fildes, const void *buf, size_t nbyte, size_t offset) /** - * Wrapper for `read` that reads all available data. - * - * `errno` is set to `EBADMSG` on success. - * - * @param fd The file descriptor from which to to read. - * @param buf Output parameter for the data. - * @param n Output parameter for the number of read bytes. - * @return 0 on success, -1 on error. - * - * @throws Any exception specified for read(3). - * @throws Any exception specified for realloc(3). - */ -int -readall(int fd, char **buf, size_t *n) -{ - char *buffer = NULL; - size_t ptr = 0, size = 128; - ssize_t got; - char *new; - int saved_errno; - - do { - if ((buffer == NULL) || (ptr == size)) { - t (!(new = realloc(buffer, size <<= 1))); - buffer = new; - } - t (got = read(fd, buffer + ptr, size - ptr), got < 0); - } while (ptr += (size_t)got, got); - - new = realloc(buffer, *n = ptr); - *buf = ptr ? (new ? new : buffer) : NULL; - shutdown(SOCK_FILENO, SHUT_RD); - return errno = EBADMSG, 0; - -fail: - saved_errno = errno; - free(buffer); - shutdown(SOCK_FILENO, SHUT_RD); - errno = saved_errno; - return -1; -} - - -/** * Unmarshal a `NULL`-terminated string array. * * The elements are not actually copied, subpointers @@ -213,49 +167,12 @@ reopen(int fd, int oflag) if (r = open(path, oflag), r < 0) return -1; if (DUP2_AND_CLOSE(r, fd) == -1) - return saved_errno = errno, close(r), errno = saved_errno, -1; + return S(close(r)), -1; return 0; } /** - * Send a string to a client. - * - * @param sockfd The file descriptor of the socket. - * @param outfd The file descriptor to which the client shall output the message. - * @param ... `NULL`-terminated list of string to concatenate. - * @return 0 on success, -1 on error. - */ -int -send_string(int sockfd, int outfd, ...) -{ - va_list args; - size_t i, n = 0; - ssize_t r; - char out = (char)outfd; - const char *s; - - va_start(args, outfd); - while ((s = va_arg(args, const char *))) - n += strlen(s); - va_end(args); - - t (write(sockfd, &out, sizeof(out)) < (ssize_t)sizeof(out)); - t (write(sockfd, &n, sizeof(n)) < (ssize_t)sizeof(n)); - - va_start(args, outfd); - while ((s = va_arg(args, const char *))) - for (i = 0, n = strlen(s); i < n; i += (size_t)r) - t (r = write(sockfd, s + i, n - i), r <= 0); - va_end(args); - - return 0; -fail: - return -1; -} - - -/** * Run a job or a hook. * * @param job The job. @@ -287,8 +204,7 @@ run_job_or_hook(struct job *job, const char *hook) } if (!(pid = fork())) { - close(SOCK_FILENO), close(STATE_FILENO); - close(BOOT_FILENO), close(REAL_FILENO); + close(STATE_FILENO), close(BOOT_FILENO), close(REAL_FILENO); (void)(status = chdir(envp[0])); environ = envp + 1; execvp(*argv, argv); @@ -297,9 +213,7 @@ run_job_or_hook(struct job *job, const char *hook) t ((pid < 0) || (waitpid(pid, &status, 0) != pid)); fail: - saved_errno = errno; - free(args), free(argv), free(envp); - errno = saved_errno; + S(free(args), free(argv), free(envp)); return status ? 1 : -!!saved_errno; } @@ -369,10 +283,7 @@ found_it: return rc; fail: - saved_errno = errno; - flock(STATE_FILENO, LOCK_UN); - free(buf), free(job_full); - errno = saved_errno; + S(flock(STATE_FILENO, LOCK_UN), free(buf), free(job_full)); return -1; } @@ -436,8 +347,7 @@ dup2_and_null(int old, int new) if (fd == old) return new; t (DUP2_AND_CLOSE(fd, old)); return new; fail: - saved_errno = errno, close(fd), errno = saved_errno; - return -1; + return S(close(fd)), -1; } @@ -467,7 +377,7 @@ open_state(int open_flags, char **state_path) if (state_path) *state_path = path, path = NULL; else free(path), path = NULL; fail: - saved_errno = errno, free(path), errno = saved_errno; + S(free(path)); if (!(open_flags & O_CREAT) && ((errno == ENOENT) || (errno == ENOTDIR))) errno = 0; return fd; @@ -478,11 +388,114 @@ fail: * Let the daemon know that it may need to * update the timers, and perhaps exit. * + * @param start Start the daemon if it is not running? + * @param name The name of the process. + * @return 0 on success, -1 on error. + */ +int +poke_daemon(int start, const char *name) +{ + char *path = NULL; + const char *dir; + pid_t pid; + int fd = -1, status, saved_errno; + + /* Get the lock file's pathname. */ + dir = getenv("XDG_RUNTIME_DIR"), dir = (dir ? dir : "/run"); + t (!(path = malloc(strlen(dir) * sizeof(char) + sizeof("/" PACKAGE "/lock")))); + stpcpy(stpcpy(path, dir), "/" PACKAGE "/lock"); + + /* Any daemon listening? */ + fd = open(path, O_RDONLY); + if (fd == -1) { + t ((errno != ENOENT) && (errno != ENOTDIR)); + } else { + if (flock(fd, LOCK_SH | LOCK_NB /* and LOCK_DRY if that was ever added... */)) + t (start = 0, errno != EWOULDBLOCK); + else + flock(fd, LOCK_UN); + t (read(fd, &pid, sizeof(pid)) < (ssize_t)sizeof(pid)); + close(fd), fd = -1; + } + + /* Start daemon if not running, otherwise poke it. */ + if (start) { + switch ((pid = fork())) { + case -1: + goto fail; + case 0: + execl(BINDIR "/satd", BINDIR "/satd", NULL); + perror(name); + exit(1); + default: + t (waitpid(pid, &status, 0) != pid); + t (errno = 0, status); + break; + } + } else { + t (kill(pid, SIGCHLD)); + } + + return 0; +fail: + return S(close(fd), free(path)), -1; +} + + +/** + * Construct the pathname for the hook script. + * + * @param env The environment variable to use for the beginning + * of the pathname, `NULL` for the home directory. + * @param suffix The rest of the pathname. + * @return The pathname. + * + * @throws 0 The environment variable is not set, or, if `env` is + * `NULL` the user is root or homeless. + */ +static char * +hookpath(const char *env, const char *suffix) +{ + struct passwd *pwd; + const char *prefix = NULL; + char *path; + + if (env) { + prefix = getenv(env); + } else if (getuid()) { + pwd = getpwuid(getuid()); + prefix = pwd ? pwd->pw_dir : NULL; + } + if (!prefix || !*prefix) + return errno = 0, NULL; + + t (!(path = malloc((strlen(prefix) + strlen(suffix) + 1) * sizeof(char)))); + stpcpy(stpcpy(path, prefix), suffix); +fail: + return path; +} + + +/** + * Set SAT_HOOK_PATH. + * * @return 0 on success, -1 on error. */ int -poke_daemon(void) +set_hookpath(void) { - return 0; /* TODO poke_daemon */ +#define HOOKPATH(PRE, SUF) \ + t (path = path ? path : hookpath(PRE, SUF), !path && errno) + char *path = NULL; + int saved_errno; + if (!getenv("SAT_HOOK_PATH")) { + HOOKPATH("XDG_CONFIG_HOME", "/sat/hook"); + HOOKPATH("HOME", "/.config/sat/hook"); + HOOKPATH(NULL, "/.config/sat/hook"); + t (setenv("SAT_HOOK_PATH", path ? path : "/etc/sat/hook", 1)); + } + return free(path), 0; +fail: + return S(free(path)), -1; } |