diff options
-rw-r--r-- | src/daemon.c | 164 | ||||
-rw-r--r-- | src/daemon.h | 4 | ||||
-rw-r--r-- | src/satd-run.c | 2 |
3 files changed, 160 insertions, 10 deletions
diff --git a/src/daemon.c b/src/daemon.c index 5e030c3..05036b3 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -20,10 +20,66 @@ * DEALINGS IN THE SOFTWARE. */ #include "daemon.h" +#include <ctype.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/file.h> /** + * Common code for `preadn` and `pwriten`. + * + * @param FUN `pread` or `pwrite`. + */ +#define PIO(FUN) \ + char *buffer = buf; \ + ssize_t r, n = 0; \ + while (nbyte) { \ + r = FUN(fildes, buffer, nbyte, offset); \ + if (r < 0) return -1; \ + if (r == 0) break; \ + n += r; \ + nbyte -= (size_t)r; \ + offset += (size_t)r; \ + buffer += (size_t)r; \ + } \ + return n + + +/** + * 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. + */ +static ssize_t +preadn(int fildes, void *buf, size_t nbyte, size_t offset) +{ + 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). + */ +static ssize_t +pwriten(int fildes, void *buf, size_t nbyte, size_t offset) +{ + PIO(pwrite); +} + + +/** * Wrapper for `read` that reads all available data. * * Sets `errno` to `EBADMSG` on success. @@ -166,8 +222,29 @@ reopen(int fd, int oflag) int send_string(int sockfd, int outfd, ...) { - return 0; /* TODO send_string */ - (void) sockfd, (void) 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; } @@ -183,19 +260,92 @@ send_string(int sockfd, int outfd, ...) int remove_job(const char *jobno, int runjob) { - return 0; /* TODO remove_job */ - (void) jobno, (void) runjob; + char *end; + char *buf = NULL; + size_t no = 0, off = 0, n; + ssize_t r; + struct stat attr; + struct job job; + int saved_errno; + + 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)); + n = (size_t)(attr.st_size); + while (off < n) { + t (preadn(STATE_FILENO, &job, sizeof(job), off) < (ssize_t)sizeof(job)); + if (!jobno || (job.no == no)) + goto found_it; + off += sizeof(job) + job.n; + } + t (flock(STATE_FILENO, LOCK_UN)); + return 0; + +found_it: + 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, (size_t)r + off)); + free(buf), buf = NULL; + fsync(STATE_FILENO); + flock(STATE_FILENO, LOCK_UN); + if (runjob == 0) + return 0; + + /* TODO run job (when running, remember to use PATH from the job's envp) */ + +fail: + saved_errno = errno; + flock(STATE_FILENO, LOCK_UN); + free(buf); + errno = saved_errno; + return -1; } /** - * Get a `NULL` terminated list of all queued jobs. + * Get a `NULL`-terminated list of all queued jobs. * - * @return A `NULL` terminated list of all queued jobs. `NULL` on error. + * @return A `NULL`-terminated list of all queued jobs. `NULL` on error. */ struct job ** get_jobs(void) { - return NULL; /* TODO get_jobs */ + size_t off = 0, 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) + sizeof(job.n)))); + *(js[j]) = job; + t (preadn(STATE_FILENO, js[j++] + sizeof(job), job.n, off) < (ssize_t)(job.n)); + off += job.n; + } + js[j] = NULL; + t (flock(STATE_FILENO, LOCK_UN)); + return js; + +fail: + saved_errno = errno; + while (j--) + free(js[j]); + free(js); + flock(STATE_FILENO, LOCK_UN); + errno = saved_errno; + return NULL; } diff --git a/src/daemon.h b/src/daemon.h index 773be85..d279dbc 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -190,9 +190,9 @@ int send_string(int sockfd, int outfd, ...); int remove_job(const char *jobno, int runjob); /** - * Get a `NULL` terminated list of all queued jobs. + * Get a `NULL`-terminated list of all queued jobs. * - * @return A `NULL` terminated list of all queued jobs. `NULL` on error. + * @return A `NULL`-terminated list of all queued jobs. `NULL` on error. */ struct job **get_jobs(void); diff --git a/src/satd-run.c b/src/satd-run.c index 95551b0..763b8f7 100644 --- a/src/satd-run.c +++ b/src/satd-run.c @@ -61,7 +61,7 @@ main(int argc, char *argv[]) for (;;) if (remove_job(NULL, 1)) t (errno); - } /* XXX when running, remember to use PATH from the job's envp */ + } done: /* Cleanup. */ |