aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/daemon.c7
-rw-r--r--src/daemon.h64
-rw-r--r--src/satd-diminished.c22
-rw-r--r--src/satd-list.c230
-rw-r--r--src/satd-rm.c18
-rw-r--r--src/satd-run.c24
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;
}