diff options
author | Mattias Andrée <maandree@member.fsf.org> | 2016-01-01 22:34:34 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@member.fsf.org> | 2016-01-01 22:34:34 +0100 |
commit | 4cba520a67e615b43dc22994670a904daf8643ae (patch) | |
tree | 6649c99fa94d8b7842a8ca7df7478ccf722d4c67 /src/daemon.c | |
parent | remove satd-rm and satd-r and let satrm and satr do everything (not done yet) (diff) | |
download | sat-4cba520a67e615b43dc22994670a904daf8643ae.tar.gz sat-4cba520a67e615b43dc22994670a904daf8643ae.tar.bz2 sat-4cba520a67e615b43dc22994670a904daf8643ae.tar.xz |
massive simpliciation and small bug fixes (not tested yet)
Signed-off-by: Mattias Andrée <maandree@member.fsf.org>
Diffstat (limited to 'src/daemon.c')
-rw-r--r-- | src/daemon.c | 488 |
1 files changed, 0 insertions, 488 deletions
diff --git a/src/daemon.c b/src/daemon.c deleted file mode 100644 index a39b0e3..0000000 --- a/src/daemon.c +++ /dev/null @@ -1,488 +0,0 @@ -/** - * Copyright © 2015, 2016 Mattias Andrée <maandree@member.fsf.org> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include "daemon.h" -#include <ctype.h> -#include <signal.h> -#include <stdarg.h> -#include <sys/stat.h> -#include <sys/file.h> -#include <sys/wait.h> - - - -/** - * The environment. - */ -extern char **environ; - - - -/** - * Common code for `preadn` and `pwriten`. - * - * @param FUN `pread` or `pwrite`. - */ -#define PIO(FUN) \ - ssize_t r, n = 0; \ - int saved_errno = 0; \ - sigset_t mask, oldmask; \ - sigfillset(&mask); \ - sigprocmask(SIG_BLOCK, &mask, &oldmask); \ - while (nbyte) { \ - t (r = FUN(fildes, buffer, nbyte, (off_t)offset), r < 0); \ - if (r == 0) \ - break; \ - n += r; \ - buffer += r; \ - offset += (size_t)r; \ - nbyte -= (size_t)r; \ - } \ -done: \ - sigprocmask(SIG_SETMASK, &oldmask, NULL); \ - errno = saved_errno; \ - return n; \ -fail: \ - saved_errno = errno; \ - n = -1; \ - goto done - - -/** - * Wrapper for `pread` that reads the required amount of data. - * - * @param fildes See pread(3). - * @param buf See pread(3). - * @param nbyte See pread(3). - * @param offset See pread(3). - * @return See pread(3), only short if the file is shorter. - */ -ssize_t -preadn(int fildes, void *buf, size_t nbyte, size_t offset) -{ - char *buffer = buf; - PIO(pread); -} - - -/** - * Wrapper for `pwrite` that writes all specified data. - * - * @param fildes See pwrite(3). - * @param buf See pwrite(3). - * @param nbyte See pwrite(3). - * @param offset See pwrite(3). - * @return See pwrite(3). - */ -ssize_t -pwriten(int fildes, const void *buf, size_t nbyte, size_t offset) -{ - const char *buffer = buf; - PIO(pwrite); -} - - -/** - * 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 - * to `buf` are stored in the returned list. - * - * @param buf The marshalled array. Must end with a NUL byte. - * @param len The length of `buf`. - * @param n Output parameter for the number of elements. May be `NULL` - * @return The list, `NULL` on error. - * - * @throws Any exception specified for realloc(3). - */ -char ** -restore_array(char *buf, size_t len, size_t *n) -{ - char **rc = malloc((len + 1) * sizeof(char*)); - char **new = NULL; - size_t i = 0, e = 0; - - t (!rc); - while (i < len) i += strlen(rc[e++] = buf + i) + 1; - if (n) *n = e; - rc[e++] = NULL; - new = realloc(rc, e * sizeof(char*)); -fail: - return new ? new : rc; -} - - -/** - * Create `NULL`-terminate subcopy of an list, - * - * @param list The list. - * @param n The number of elements in the new sublist. - * @return The sublist, `NULL` on error. - * - * @throws Any exception specified for malloc(3). - */ -char ** -sublist(char *const *list, size_t n) -{ - char **rc = malloc((n + 1) * sizeof(char*)); - t (!rc); - for (rc[n] = NULL; n--; rc[n] = list[n]); -fail: - return rc; -} - - -/** - * Create a new open file descriptor for an already - * existing file descriptor. - * - * @param fd The file descriptor that shall be promoted - * to a new open file descriptor. - * @param oflag See open(3), `O_CREAT` is not allowed. - * @return 0 on success, -1 on error. - */ -int -reopen(int fd, int oflag) -{ - char path[sizeof("/dev/fd/") + 3 * sizeof(int)]; - int r, saved_errno; - - sprintf(path, "/dev/fd/%i", fd); - 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 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. - * @param hook The hook, `NULL` to run the job. - * @return 0 on success, -1 on error, 1 if the child failed. - */ -int -run_job_or_hook(struct job *job, const char *hook) -{ - pid_t pid; - char **args = NULL; - char **argv = NULL; - char **envp = NULL; - size_t argsn; - void *new; - int status = 0, saved_errno; - - t (!(args = restore_array(job->payload, job->n, &argsn))); - t (!(argv = sublist(args, (size_t)(job->argc)))); - t (!(envp = sublist(args + job->argc, argsn - (size_t)(job->argc)))); /* Includes wdir. */ - free(args), args = NULL; - - if (hook) { - t (!(new = realloc(argv, ((size_t)(job->argc) + 3) * sizeof(*argv)))); - argv = new; - memmove(argv + 2, argv, ((size_t)(job->argc) + 1) * sizeof(*argv)); - argv[0] = getenv("SAT_HOOK_PATH"); - argv[1] = (strstr)(hook, hook); /* strstr: just to remove a warning */ - } - - if (!(pid = fork())) { - close(SOCK_FILENO), close(STATE_FILENO); - close(BOOT_FILENO), close(REAL_FILENO); - (void)(status = chdir(envp[0])); - environ = envp + 1; - execvp(*argv, argv); - exit(1); - } - - t ((pid < 0) || (waitpid(pid, &status, 0) != pid)); -fail: - saved_errno = errno; - free(args), free(argv), free(envp); - errno = saved_errno; - return status ? 1 : -!!saved_errno; -} - - -/** - * Removes (and optionally runs) a job. - * - * @param jobno The job number, `NULL` for any job. - * @param runjob Shall we run the job too? 2 if its time has expired (not forced). - * @return 0 on success, -1 on error. - * - * @throws 0 The job is not in the queue. - */ -int -remove_job(const char *jobno, int runjob) -{ - char *end; - char *buf = NULL; - size_t no = 0, off = sizeof(size_t), n; - ssize_t r; - struct stat attr; - struct job job; - struct job *job_full = NULL; - int rc = 0, saved_errno = 0; - - if (jobno) { - no = (errno = 0, strtoul)(jobno, &end, 10); - if (errno || *end || !isdigit(*jobno)) - return 0; - } - - t (flock(STATE_FILENO, LOCK_EX)); - t (fstat(STATE_FILENO, &attr)); - for (n = (size_t)(attr.st_size); off < n; off += sizeof(job) + job.n) { - t (preadn(STATE_FILENO, &job, sizeof(job), off) < (ssize_t)sizeof(job)); - if (!jobno || (job.no == no)) - goto found_it; - } - flock(STATE_FILENO, LOCK_UN); /* Failure isn't fatal. */ - return errno = 0, -1; - -found_it: - t (!(job_full = malloc(sizeof(job) + job.n))); - *job_full = job; - t (preadn(STATE_FILENO, job_full->payload, job.n, off + sizeof(job)) < (ssize_t)(job.n)); - n -= off + sizeof(job) + job.n; - t (!(buf = malloc(n))); - t (r = preadn(STATE_FILENO, buf, n, off + sizeof(job) + job.n), r < 0); - t (pwriten(STATE_FILENO, buf, (size_t)r, off) < 0); - t (ftruncate(STATE_FILENO, (off_t)r + (off_t)off)); - free(buf), buf = NULL; - fsync(STATE_FILENO); - - if (runjob) { - run_job_or_hook(job_full, runjob == 2 ? "expired" : "forced"); - rc = run_job_or_hook(job_full, NULL); - saved_errno = errno; - run_job_or_hook(job_full, rc ? "failure" : "success"); - rc = rc == 1 ? 0 : rc; - } else { - run_job_or_hook(job_full, "removed"); - } - - free(job_full); - flock(STATE_FILENO, LOCK_UN); /* Unlock late so that hooks are synchronised. Failure isn't fatal. */ - errno = saved_errno; - return rc; - -fail: - saved_errno = errno; - flock(STATE_FILENO, LOCK_UN); - free(buf), free(job_full); - errno = saved_errno; - return -1; -} - - -/** - * Get a `NULL`-terminated list of all queued jobs. - * - * @return A `NULL`-terminated list of all queued jobs. `NULL` on error. - */ -struct job ** -get_jobs(void) -{ - size_t off = sizeof(size_t), n, j = 0; - struct stat attr; - struct job **js = NULL; - struct job job; - int saved_errno; - - t (flock(STATE_FILENO, LOCK_SH)); - t (fstat(STATE_FILENO, &attr)); - n = (size_t)(attr.st_size); - t (!(js = malloc((n / sizeof(**js) + 1) * sizeof(*js)))); - while (off < n) { - t (preadn(STATE_FILENO, &job, sizeof(job), off) < (ssize_t)sizeof(job)); - off += sizeof(job); - t (!(js[j] = malloc(sizeof(job) + job.n))); - *(js[j]) = job; - t (preadn(STATE_FILENO, js[j++]->payload, job.n, off) < (ssize_t)(job.n)); - off += job.n; - } - t (flock(STATE_FILENO, LOCK_UN)); - return js[j] = NULL, js; - -fail: - saved_errno = errno; - flock(STATE_FILENO, LOCK_UN); - while (j--) free(js[j]); - free(js); - errno = saved_errno; - return NULL; -} - - -/** - * Duplicate a file descriptor, and - * open /dev/null to the old file descriptor. - * However, if `old` is 3 or greater, it will - * be closed rather than /dev/null. - * - * @param old The old file descriptor. - * @param new The new file descriptor. - * @return `new`, -1 on error. - */ -int -dup2_and_null(int old, int new) -{ - int fd = -1, saved_errno; - - if (old == new) return new; t (DUP2_AND_CLOSE(old, new)); - if (old >= 3) return new; t (fd = open("/dev/null", O_RDWR), fd == -1); - if (fd == old) return new; t (DUP2_AND_CLOSE(fd, old)); - return new; -fail: - saved_errno = errno, close(fd), errno = saved_errno; - return -1; -} - - -/** - * Create or open the state file. - * - * @param open_flags Flags (the second parameter) for `open`. - * @param state_path Output parameter for the state file's pathname. - * May be `NULL`; - * @return A file descriptor to the state file, -1 on error. - * - * @throws 0 `!(open_flags & O_CREAT)` and the file does not exist. - */ -int -open_state(int open_flags, char **state_path) -{ - const char *dir; - char *path; - int fd = -1, saved_errno; - - /* Create directory. */ - dir = getenv("XDG_RUNTIME_DIR"), dir = (dir ? dir : "/run"); - t (!(path = malloc(strlen(dir) * sizeof(char) + sizeof("/" PACKAGE "/state")))); - stpcpy(stpcpy(path, dir), "/" PACKAGE "/state"); - t (fd = open(path, open_flags, S_IRUSR | S_IWUSR), fd == -1); - - if (state_path) *state_path = path, path = NULL; - else free(path), path = NULL; -fail: - saved_errno = errno, free(path), errno = saved_errno; - if (!(open_flags & O_CREAT) && ((errno == ENOENT) || (errno == ENOTDIR))) - errno = 0; - return fd; -} - - -/** - * Let the daemon know that it may need to - * update the timers, and perhaps exit. - * - * @return 0 on success, -1 on error. - */ -int -poke_daemon(void) -{ - return 0; /* TODO poke_daemon */ -} - |