diff options
-rw-r--r-- | src/daemon.c | 7 | ||||
-rw-r--r-- | src/daemon.h | 64 | ||||
-rw-r--r-- | src/satd-diminished.c | 22 | ||||
-rw-r--r-- | src/satd-list.c | 230 | ||||
-rw-r--r-- | src/satd-rm.c | 18 | ||||
-rw-r--r-- | src/satd-run.c | 24 |
6 files changed, 335 insertions, 30 deletions
diff --git a/src/daemon.c b/src/daemon.c index 8d9b1b3..b47e4d2 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -41,7 +41,7 @@ * @throws Any exception specified for realloc(3). */ int -readall(int fd, char **buf, size_t *n); +readall(int fd, char **buf, size_t *n) { char *buffer = NULL; size_t ptr = 0; @@ -54,7 +54,7 @@ readall(int fd, char **buf, size_t *n); if (ptr == size) { new = realloc(buffer, size <<= 1); t (!new); - buffer = wnew; + buffer = new; } got = read(fd, buffer + ptr, size - ptr); t (got < 0); @@ -90,10 +90,9 @@ fail: * @throws Any exception specified for realloc(3). */ char ** -restore_array(char* buf, size_t len, size_t* n) +restore_array(char *buf, size_t len, size_t *n) { char **rc = malloc((len + 1) * sizeof(char*)); - char *elem = NULL; char **new; size_t i, e = 0; t (!rc); diff --git a/src/daemon.h b/src/daemon.h index 6b968ba..2c0d0ff 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -20,6 +20,10 @@ * DEALINGS IN THE SOFTWARE. */ #include <stddef.h> +#include <errno.h> +#include <string.h> +#include <time.h> +#include <stdlib.h> #include <sys/socket.h> @@ -35,6 +39,27 @@ #define STATE_FILENO 4 +/** + * Command: queue a job. + */ +#define SAT_QUEUE 0 + +/** + * Command: remove jobs. + */ +#define SAT_REMOVE 1 + +/** + * Command: print job queue. + */ +#define SAT_PRINT 2 + +/** + * Command: run jobs. + */ +#define SAT_RUN 3 + + #ifndef t /** @@ -48,6 +73,43 @@ /** + * A queued job. + */ +struct job { + /** + * The job number. + */ + size_t no; + + /** + * The number of “argv” elements in `payload`. + */ + int argc; + + /** + * The clock in which `ts` is measured. + */ + clockid_t clk; + + /** + * The time when the job shall be executed. + */ + struct timespec ts; + + /** + * The number of bytes in `payload`. + */ + size_t n; + + /** + * “argv” followed by “envp”. + */ + char payload[0]; +}; + + + +/** * Wrapper for `read` that reads all available data. * * Sets `errno` to `EBADMSG` on success. @@ -75,7 +137,7 @@ int readall(int fd, char **buf, size_t *n); * * @throws Any exception specified for realloc(3). */ -char **restore_array(char* buf, size_t len, size_t* n); +char **restore_array(char *buf, size_t len, size_t *n); /** * Create `NULL`-terminate subcopy of an list, diff --git a/src/satd-diminished.c b/src/satd-diminished.c index 3a42fba..a3a2807 100644 --- a/src/satd-diminished.c +++ b/src/satd-diminished.c @@ -32,28 +32,6 @@ /** - * Command: queue a job. - */ -#define SAT_QUEUE 0 - -/** - * Command: remove jobs. - */ -#define SAT_REMOVE 1 - -/** - * Command: print job queue. - */ -#define SAT_PRINT 2 - -/** - * Command: run jobs. - */ -#define SAT_RUN 3 - - - -/** * The common beginning of for all daemon pathnames. */ #define DAEMON_PREFIX LIBEXEC "/" PACKAGE "/satd-" diff --git a/src/satd-list.c b/src/satd-list.c index a7d13e3..3a6747a 100644 --- a/src/satd-list.c +++ b/src/satd-list.c @@ -20,6 +20,215 @@ * DEALINGS IN THE SOFTWARE. */ #include "daemon.h" +#include <stdio.h> + + + +/** + * Quote a string, in shell (Bash-only if necessary) compatible + * format, if necessary. + * + * @param str The string. + * @return Return a safe representation of the string, + * `NULL` on error. + */ +static char * +quote(const unsigned char *str) +{ + size_t in = 0; /* < ' ' */ + size_t sn = 0; /* = ' ', '"' or '$' */ + size_t bn = 0; /* = '\\' */ + size_t qn = 0; /* = '\'' */ + size_t rn = 0; /* other */ + size_t n, i = 0; + char *s; + char *rc; + + for (s = str; *s; s++) { + if (*s < ' ') in++; + else if (*s == ' ') sn++; + else if (*s == '"') sn++; + else if (*s == '$') sn++; + else if (*s == '\\') bn++; + else if (*s == '\'') qn++; + else rn++; + } + + switch (in ? 2 : (sn + bn + qn) ? 1 : 0) { + case 0: + return strdup(str); + case 1: + n = rn + sn + bn + 4 * qn + 4 * in + 2; + t (!(rc = malloc((n + 1) * sizeof(char)))); + rc[i++] = '\''; + for (s = str; *s; s++) { + rc[i++] = (char)*s; + if (*s == '\'') + rc[i++] = '\\', rc[i++] = '\'', rc[i++] = '\''; + + } + rc[i++] = '\''; + rc[i] = '\0'; + return rc; + case 2: + n = 4 * in + rn + sn + 2 * bn + 2 * qn + 3; + t (!(rc = malloc((n + 1) * sizeof(char)))); + rc[i++] = '$'; + rc[i++] = '\''; + for (s = str; *s; s++) { + if (*s < ' ') { + rc[i++] = '\\'; + rc[i++] = 'x'; + rc[i++] = "0123456789ABCDEF"[(*s >> 4) & 15]; + rc[i++] = "0123456789ABCDEF"[(*s >> 0) & 15]; + } + else if (*s == ' ') rc[i++] = (char)*s; + else if (*s == '"') rc[i++] = (char)*s; + else if (*s == '$') rc[i++] = (char)*s; + else if (*s == '\\') rc[i++] = '\\', rc[i++] = (char)*s; + else if (*s == '\'') rc[i++] = '\\', rc[i++] = (char)*s; + else rc[i++] = (char)*s; + } + rc[i++] = '\''; + rc[i] = '\0'; + break; + } +fail: + return NULL; +} + + +/** + * Create a textual representation of the a duration. + * + * @param buffer Output buffer, with a size of at least + * 10 `char`:s plus enough to encode a `time_t`. + * @param s The duration in seconds. + */ +static void +strduration(char *buffer, time_t s) +{ + char *buf = buffer; + int seconds, minutes, hours, days; + seconds = s % 60, s /= 60; + minutes = s % 60, s /= 60; + hours = s % 24, s /= 24; + if (s) { + buf += sprintf(buf, "%llid", (long long int)s)); + buf += sprintf(buf, "%02i:", hours); + buf += sprintf(buf, "%02i", minutes); + } else if (hours) { + buf += sprintf(buf, "%i:", hours); + buf += sprintf(buf, "%02i", minutes); + } else if (minutes) { + buf += sprintf(buf, "%i", minutes); + } + sprintf(buf, "%02i", seconds); +} + + +/** + * Dump a job to the socket. + * + * @param job The job. + * @return 0 on success, -1 on error. + */ +static int +send_job_str(struct job* job) +{ + struct tm *tm; + struct timespec rem; + const char *clk; + char rem_s[3 * sizeof(time_t) + sizeof("d00:00:00")]; + char *qstr = NULL; + char line[sizeof("job: %zu clock: unrecognised argc: %i remaining: , argv[0]: ") + + 3 * sizeof(size_t) + 3 * sizeof(int) + sizeof(rem_s) + 9]; + char timestr_a[sizeof("0000-00-00 00:00:00") + 3 * sizeof(time_t)]; + char timestr_b[10]; + char **args = NULL; + const char **arg; + const char **argv = NULL; + const char **envp = NULL; + size_t argsn; + int rc = 0; + + /* Get remaining time. */ + if (clock_gettime(job->clk, &rem)) + return errno == EINVAL ? 0 : -1; + rem.tv_sec -= job->ts.tv_sec; + rem.tv_nsec -= job->ts.tv_nsec; + if (rem.tv_nsec < 0) { + rem.tv_sec -= 1; + rem.tv_nsec += 1000000000L; + } + if (rem.tv_sec < 0) + /* This job will be removed momentarily, do not list it. (To simply things.) */ + return 0; + + /* Get clock name. */ + switch (job->clk) { + case CLOCK_REALTIME: clk = "walltime"; break; + case CLOCK_BOOTTIME: clk = "boottime"; break; + default: clk = "unrecognised"; break; + } + + /* Get textual representation of the remaining time. (Seconds only.) */ + strduration(rem_s, rem.tv_sec); + + /* Get textual representation of the expiration time. */ + switch (job->clk) { + case CLOCK_REALTIME: + t (!(tm = localtime(job->ts.tv_sec))); + strftime(timestr_a, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm); + break; + default: + strduration(timestr_a, job->ts.tv_sec); + break; + } + sprintf(timestr_b, "%09li", job->ts.tv_nsec); + + /* Get arguments. */ + t (!(args = restore_array(job->payload, job->n, &argsn))); + t (!(argv = sublist(args, (size_t)argc))); + t (!(envp = sublist(args + argc, argsn - (size_t)argc))); + + /* Send message. */ + t (!(qstr = quote(args[0]))); + sprintf(line, "job: %zu clock: %s argc: %i remaining: %s.%09li, argv[0]: ", + job->no, clk, job->argc, rem_s, rem.tv_nsec); + t (send_string(SOCK_FILENO, STDOUT_FILENO, + line, qstr, "\n", + " time: ", timestr_a, ".", timestr_b, "\n", + " argv:", + NULL)); + for (arg = argv, *arg, arg++) { + free(qstr); + t (!(qstr = quote(arg))); + t (send_string(SOCK_FILENO, STDOUT_FILENO, " ", qstr, NULL)); + } + free(qstr), qstr = NULL; + t (send_string(SOCK_FILENO, STDOUT_FILENO, "\n envp:", NULL)); + for (arg = envp, *arg, arg++) { + t (!(qstr = quote(arg))); + t (send_string(SOCK_FILENO, STDOUT_FILENO, " ", qstr, NULL)); + free(qstr); + } + qstr = NULL; + t (send_string(SOCK_FILENO, STDOUT_FILENO, "\n\n", NULL)); + +done: + saved_errno = errno; + free(qstr); + free(args); + free(argv); + free(envp); + errno = saved_errno; + return rc; + +fail: + rc = -1; + goto done; +} @@ -38,12 +247,31 @@ main(int argc, char *argv[]) { size_t n = 0; char *message = NULL; + struct job** jobs; + struct job** job; /* Receive and validate message. */ t (readall(SOCK_FILENO, &message, &n) || n); shutdown(SOCK_FILENO, SHUT_RD); - return 0; + /* Perform action. */ + t (!(jobs = get_jobs())); + for (job = jobs; *job; job++) + t (send_job_str(*job)); + +done: + /* Cleanup. */ + shutdown(SOCK_FILENO, SHUT_WR); + close(SOCK_FILENO); + for (job = jobs; *job; job++) + free(*job); + free(jobs); + free(message); + return rc; fail: + if (send_string(SOCK_FILENO, STDERR_FILENO, argv[0], ": ", strerror(errno) "\n", NULL)) + perror(argv[0]); + rc = 1; + goto done; } diff --git a/src/satd-rm.c b/src/satd-rm.c index 6a9f6cd..58b9eed 100644 --- a/src/satd-rm.c +++ b/src/satd-rm.c @@ -39,6 +39,8 @@ main(int argc, char *argv[]) size_t n = 0; char *message = NULL; char **msg_argv = NULL; + char **arg; + int rc = 0; /* Receive and validate message. */ t (readall(SOCK_FILENO, &message, &n) || !n || message[n - 1]); @@ -46,7 +48,21 @@ main(int argc, char *argv[]) msg_argv = restore_array(message, n, NULL); t (!msg_argv); - return 0; + /* Perform action. */ + for (arg = msg_argv; *arg; arg++) + t (remove_job(*arg, 0) && errno); + +done: + /* Cleanup. */ + shutdown(SOCK_FILENO, SHUT_WR); + close(SOCK_FILENO); + free(msg_argv); + free(message); + return rc; fail: + if (send_string(SOCK_FILENO, STDERR_FILENO, argv[0], ": ", strerror(errno), "\n", NULL)) + perror(argv[0]); + rc = 1; + goto done; } diff --git a/src/satd-run.c b/src/satd-run.c index 7cccb57..36b66e2 100644 --- a/src/satd-run.c +++ b/src/satd-run.c @@ -39,6 +39,8 @@ main(int argc, char *argv[]) size_t n = 0; char *message = NULL; char **msg_argv = NULL; + char **arg; + int rc = 0; /* Receive and validate message. */ t (readall(SOCK_FILENO, &message, &n) || (n && message[n - 1])); @@ -48,7 +50,27 @@ main(int argc, char *argv[]) t (!msg_argv); } - return 0; + /* Perform action. */ + if (msg_argv) { + for (arg = msg_argv; *arg; arg++) + t (remove_job(*arg, 1) && errno); + } else { + for (;;) + if (remove_job(NULL, 1)) + t (errno); + } + +done: + /* Cleanup. */ + shutdown(SOCK_FILENO, SHUT_WR); + close(SOCK_FILENO); + free(msg_argv); + free(message); + return rc; fail: + if (send_string(SOCK_FILENO, STDERR_FILENO, argv[0], ": ", strerror(errno), "\n", NULL)) + perror(argv[0]); + rc = 1; + goto done; } |