aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/README4
-rw-r--r--src/daemon.c58
-rw-r--r--src/daemon.h38
-rw-r--r--src/satd-diminished.c1
-rw-r--r--src/satd-list.c241
-rw-r--r--src/satd.c57
-rw-r--r--src/satq.c229
7 files changed, 324 insertions, 304 deletions
diff --git a/src/README b/src/README
index 5062afa..c4a0b15 100644
--- a/src/README
+++ b/src/README
@@ -18,10 +18,10 @@ parse_time.[ch] Use by sat.c to parse the time argument.
daemonise.[ch] From <http://github.com/maandree/slibc>;
daemonisation of the process. Used by satd.c
-client.[ch] Used by sat{,q,r,rm}.c, code for communicating
+client.[ch] Used by sat{,r,rm}.c, code for communicating
with satd, starts satd transparently if necessary.
-daemon.[ch] Used by satd*.c, some shared code for daemons objects.
+daemon.[ch] Used by sat{q,d*}.c, some shared code for daemons objects.
common.h Used by sat{,q,r,rm,d*}.c, some shared code.
Included via client.h and daemon.h.
diff --git a/src/daemon.c b/src/daemon.c
index ee05cf7..ab97dff 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -415,3 +415,61 @@ fail:
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;
+}
+
diff --git a/src/daemon.h b/src/daemon.h
index cb6736a..dc8a355 100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -125,6 +125,20 @@ fail: \
goto done; \
(void) argc
+/**
+ * Call `CALL` which returns a file descriptor.
+ * Than make sure that the file descriptor's
+ * number is `WANT`. Go to `fail' on error.
+ *
+ * @param FD:int variable The variable where the file descriptor shall be stored.
+ * @param WANT:int The file descriptor the file should have.
+ * @parma CALL:int call Call to function that creates and returns the file descriptor.
+ */
+#define GET_FD(FD, WANT, CALL) \
+ t (FD = CALL, FD == -1); \
+ t (dup2_and_null(FD, WANT) == -1); \
+ FD = WANT
+
/**
@@ -238,3 +252,27 @@ int remove_job(const char *jobno, int runjob);
*/
struct job **get_jobs(void);
+/**
+ * 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);
+
+/**
+ * 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);
+
diff --git a/src/satd-diminished.c b/src/satd-diminished.c
index c8c0b53..845fa13 100644
--- a/src/satd-diminished.c
+++ b/src/satd-diminished.c
@@ -135,7 +135,6 @@ spawn(int command, int fd, char *argv[], char *envp[])
switch (command) {
IMAGE(SAT_QUEUE, "add");
IMAGE(SAT_REMOVE, "rm");
- IMAGE(SAT_PRINT, "list");
IMAGE(SAT_RUN, "run");
IMAGE(-1, "timer");
default:
diff --git a/src/satd-list.c b/src/satd-list.c
deleted file mode 100644
index 12c06a7..0000000
--- a/src/satd-list.c
+++ /dev/null
@@ -1,241 +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"
-
-
-
-/**
- * Quote a string, in shell (Bash-only if necessary) compatible
- * format, if necessary. Here, just adding quotes around all not
- * do. The string must be single line, and there must not be
- * any invisible characters; it should be possible to copy
- * a string from the terminal by marking it, hence all of this
- * ugliness.
- *
- * @param str The string.
- * @return Return a safe representation of the string,
- * `NULL` on error.
- */
-static char *
-quote(const char *str)
-{
-#define UNSAFE(c) strchr(" \"$()[]{};|&^#!?*~`<>", c)
-#define N(I, S, B, Q) (I*in + S*sn + B*bn + Q*qn + rn)
-
- size_t in = 0; /* < ' ' or 127 */
- size_t sn = 0; /* in UNSAFE */
- size_t bn = 0; /* = '\\' */
- size_t qn = 0; /* = '\'' */
- size_t rn = 0; /* other */
- size_t n, i = 0;
- const unsigned char *s;
- char *rc = NULL;
-
- for (s = (const unsigned char *)str; *s; s++) {
- if (*s < ' ') in++;
- else if (*s == 127) in++;
- else if (UNSAFE(*s)) sn++;
- else if (*s == '\\') bn++;
- else if (*s == '\'') qn++;
- else rn++;
- }
- if (N(1, 1, 1, 1) == rn)
- return strdup(rn ? str : "''");
-
- n = in ? (N(4, 1, 2, 2) + 3) : (N(0, 1, 1, 4) + 2);
- t (!(rc = malloc((n + 1) * sizeof(char))));
- rc[i += !!in] = '$';
- rc[i += 1] = '\'';
- if (in == 0) {
- for (s = (const unsigned char *)str; *s; s++) {
- rc[i++] = (char)*s;
- if (*s == '\'')
- rc[i++] = '\\', rc[i++] = '\'', rc[i++] = '\'';
- }
- } else {
- for (s = (const unsigned char *)str; *s; s++) {
- if ((*s < ' ') || (*s == 127)) {
- rc[i++] = '\\';
- rc[i++] = 'x';
- rc[i++] = "0123456789ABCDEF"[(*s >> 4) & 15];
- rc[i++] = "0123456789ABCDEF"[(*s >> 0) & 15];
- }
- else if (strchr("\\'", *s)) rc[i++] = '\\', rc[i++] = (char)*s;
- else rc[i++] = (char)*s;
- }
- }
- rc[i++] = '\'';
- rc[i] = '\0';
-fail:
- return rc;
-}
-
-
-/**
- * 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 secs, mins, hours, sd = 0, md = 0, hd = 0;
- secs = (int)(s % 60), s /= 60;
- mins = (int)(s % 60), s /= 60;
- hours = (int)(s % 24), s /= 24;
- if (s) hd++, buf += sprintf(buf, "%llid", (long long int)s);
- if (hd | hours) md++, buf += sprintf(buf, "%0*i:", ++hd, hours);
- if (md | mins) sd++, buf += sprintf(buf, "%0*i:", ++md, mins);
- /*just for alignment*/ buf += sprintf(buf, "%0*i:", ++sd, secs);
-}
-
-
-/**
- * Dump a job to the socket.
- *
- * @param job The job.
- * @return 0 on success, -1 on error.
- */
-static int
-send_job_human(struct job *job)
-{
-#define FIX_NSEC(T) (((T)->tv_nsec < 0L) ? ((T)->tv_sec -= 1, (T)->tv_nsec += 1000000000L) : 0L)
-#define ARRAY(LIST) \
- for (arg = LIST; *arg; arg++) { \
- free(qstr); \
- t (!(qstr = quote(*arg))); \
- t (send_string(SOCK_FILENO, STDOUT_FILENO, " ", qstr, NULL)); \
- }
-
- struct tm *tm;
- struct timespec rem;
- const char *clk;
- char rem_s[3 * sizeof(time_t) + sizeof("d00:00:00")];
- char *qstr = NULL;
- char *wdir = 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("-00-00 00:00:00") + 3 * sizeof(time_t)];
- char timestr_b[10];
- char **args = NULL;
- char **arg;
- char **argv = NULL;
- char **envp = NULL;
- size_t argsn;
- int rc = 0, saved_errno;
-
- /* Get remaining time. */
- if (clock_gettime(job->clk, &rem))
- return errno == EINVAL ? 0 : -1;
- rem.tv_sec = job->ts.tv_sec - rem.tv_sec;
- rem.tv_nsec = job->ts.tv_nsec - rem.tv_nsec;
- FIX_NSEC(&rem);
- 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. */
- if (job->clk == CLOCK_REALTIME) {
- t (!(tm = localtime(&(job->ts.tv_sec))));
- strftime(timestr_a, sizeof(timestr_a), "%Y-%m-%d %H:%M:%S", tm);
- } else {
- strduration(timestr_a, job->ts.tv_sec);
- }
- 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)(job->argc))));
- t (!(envp = sublist(args + job->argc, argsn - (size_t)(job->argc)))); /* Includes wdir. */
-
- /* Send message. */
- t (!(qstr = quote(args[0])));
- t (!(wdir = quote(envp[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 wdir: ", wdir,
- "\n argv:", NULL));
- free(qstr);
- ARRAY(argv); t (send_string(SOCK_FILENO, STDOUT_FILENO, "\n envp:", NULL));
- ARRAY(envp + 1); t (send_string(SOCK_FILENO, STDOUT_FILENO, "\n\n", NULL));
-
-done:
- saved_errno = errno;
- free(qstr), free(args), free(argv), free(wdir), free(envp);
- errno = saved_errno;
- return rc;
-fail:
- rc = -1;
- goto done;
-}
-
-
-
-/**
- * Subroutine to the sat daemon: list jobs.
- *
- * @param argc Should be 3.
- * @param argv The name of the process, the pathname of the socket,
- * and the pathname to the state file.
- * @return 0 The process was successful.
- * @return 1 The process failed queuing the job.
- */
-int
-main(int argc, char *argv[])
-{
- size_t n = 0;
- char *message = NULL;
- struct job **jobs = NULL;
- struct job **job;
- DAEMON_PROLOGUE;
-
- /* Receive and validate message. */
- t (readall(SOCK_FILENO, &message, &n) || n);
-
- /* Perform action. */
- t (!(jobs = get_jobs()));
- for (job = jobs; *job; job++)
- t (send_job_human(*job));
-
- DAEMON_CLEANUP_START;
- for (job = jobs; *job; job++)
- free(*job);
- free(jobs);
- free(message);
- DAEMON_CLEANUP_END;
-}
-
diff --git a/src/satd.c b/src/satd.c
index d9745ef..dd5046b 100644
--- a/src/satd.c
+++ b/src/satd.c
@@ -87,32 +87,6 @@ fail:
/**
- * Create the state file.
- *
- * @param state_path Output parameter for the state file's pathname.
- * @return A file descriptor to the state file, -1 on error.
- */
-static int
-create_state(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, O_RDWR | O_CREAT /* but not O_EXCL or O_TRUNC */, S_IRUSR | S_IWUSR), fd == -1);
- *state_path = path, path = NULL;
-
-fail:
- saved_errno = errno, free(path), errno = saved_errno;
- return fd;
-}
-
-
-/**
* Create and lock the lock file, and its directory.
*
* @return A file descriptor to the lock file, -1 on error.
@@ -187,31 +161,6 @@ fail:
/**
- * 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.
- */
-static 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;
-}
-
-
-/**
* The sat daemon initialisation.
*
* @param argc Any value in [0, 2] is accepted.
@@ -224,10 +173,6 @@ fail:
int
main(int argc, char *argv[])
{
-#define GET_FD(FD, WANT, CALL) \
- t (FD = CALL, FD == -1); \
- t (dup2_and_null(FD, WANT) == -1); \
- FD = WANT
#define HOOKPATH(PRE, SUF) \
t (path = path ? path : hookpath(PRE, SUF), !path && errno)
@@ -253,7 +198,7 @@ main(int argc, char *argv[])
/* Open/create lock file and state file, and create socket. */
GET_FD(lock, LOCK_FILENO, create_lock());
- GET_FD(state, STATE_FILENO, create_state(&path));
+ GET_FD(state, STATE_FILENO, open_state(O_RDWR | O_CREAT, &path));
GET_FD(sock, SOCK_FILENO, create_socket(&address));
/* Create timers. */
diff --git a/src/satq.c b/src/satq.c
index 7f92878..f2fef92 100644
--- a/src/satq.c
+++ b/src/satq.c
@@ -19,7 +19,8 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
-#include "client.h"
+#include "daemon.h"
+#include <stdarg.h>
@@ -29,6 +30,210 @@ USAGE(NULL)
/**
+ * Quote a string, in shell (Bash-only if necessary) compatible
+ * format, if necessary. Here, just adding quotes around all not
+ * do. The string must be single line, and there must not be
+ * any invisible characters; it should be possible to copy
+ * a string from the terminal by marking it, hence all of this
+ * ugliness.
+ *
+ * @param str The string.
+ * @return Return a safe representation of the string,
+ * `NULL` on error.
+ */
+static char *
+quote(const char *str)
+{
+#define UNSAFE(c) strchr(" \"$()[]{};|&^#!?*~`<>", c)
+#define N(I, S, B, Q) (I*in + S*sn + B*bn + Q*qn + rn)
+
+ size_t in = 0; /* < ' ' or 127 */
+ size_t sn = 0; /* in UNSAFE */
+ size_t bn = 0; /* = '\\' */
+ size_t qn = 0; /* = '\'' */
+ size_t rn = 0; /* other */
+ size_t n, i = 0;
+ const unsigned char *s;
+ char *rc = NULL;
+
+ for (s = (const unsigned char *)str; *s; s++) {
+ if (*s < ' ') in++;
+ else if (*s == 127) in++;
+ else if (UNSAFE(*s)) sn++;
+ else if (*s == '\\') bn++;
+ else if (*s == '\'') qn++;
+ else rn++;
+ }
+ if (N(1, 1, 1, 1) == rn)
+ return strdup(rn ? str : "''");
+
+ n = in ? (N(4, 1, 2, 2) + 3) : (N(0, 1, 1, 4) + 2);
+ t (!(rc = malloc((n + 1) * sizeof(char))));
+ rc[i += !!in] = '$';
+ rc[i += 1] = '\'';
+ if (in == 0) {
+ for (s = (const unsigned char *)str; *s; s++) {
+ rc[i++] = (char)*s;
+ if (*s == '\'')
+ rc[i++] = '\\', rc[i++] = '\'', rc[i++] = '\'';
+ }
+ } else {
+ for (s = (const unsigned char *)str; *s; s++) {
+ if ((*s < ' ') || (*s == 127)) {
+ rc[i++] = '\\';
+ rc[i++] = 'x';
+ rc[i++] = "0123456789ABCDEF"[(*s >> 4) & 15];
+ rc[i++] = "0123456789ABCDEF"[(*s >> 0) & 15];
+ }
+ else if (strchr("\\'", *s)) rc[i++] = '\\', rc[i++] = (char)*s;
+ else rc[i++] = (char)*s;
+ }
+ }
+ rc[i++] = '\'';
+ rc[i] = '\0';
+fail:
+ return rc;
+}
+
+
+/**
+ * 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 secs, mins, hours, sd = 0, md = 0, hd = 0;
+ secs = (int)(s % 60), s /= 60;
+ mins = (int)(s % 60), s /= 60;
+ hours = (int)(s % 24), s /= 24;
+ if (s) hd++, buf += sprintf(buf, "%llid", (long long int)s);
+ if (hd | hours) md++, buf += sprintf(buf, "%0*i:", ++hd, hours);
+ if (md | mins) sd++, buf += sprintf(buf, "%0*i:", ++md, mins);
+ /*just for alignment*/ buf += sprintf(buf, "%0*i", ++sd, secs);
+}
+
+
+/**
+ * Prints a series of strings without any restrict
+ * (in constrast to the `printf` function) of the
+ * length of the strings.
+ *
+ * @param s... The strings to print. `NULL`-terminated.
+ * @return 0 on success, -1 on error.
+ */
+static int
+print(const char *s, ...)
+{
+ va_list args;
+ size_t i, n = 0;
+ ssize_t r = 1;
+ va_start(args, s);
+ do
+ for (i = 0, n = strlen(s); (r > 0) && (i < n); i += (size_t)r)
+ r = write(STDOUT_FILENO, s + i, n - i);
+ while ((r > 0) && ((s = va_arg(args, const char *))));
+ va_end(args);
+ return r > 0 ? 0 : -1;
+}
+
+
+/**
+ * Dump a job to the socket.
+ *
+ * @param job The job.
+ * @return 0 on success, -1 on error.
+ */
+static int
+print_job(struct job *job)
+{
+#define FIX_NSEC(T) (((T)->tv_nsec < 0L) ? ((T)->tv_sec -= 1, (T)->tv_nsec += 1000000000L) : 0L)
+#define ARRAY(LIST) \
+ for (arg = LIST; *arg; arg++) { \
+ free(qstr); \
+ t (!(qstr = quote(*arg))); \
+ t (print(" ", qstr, NULL)); \
+ }
+
+ struct tm *tm;
+ struct timespec rem;
+ const char *clk;
+ char rem_s[3 * sizeof(time_t) + sizeof("d00:00:00")];
+ char *qstr = NULL;
+ char *wdir = 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("-00-00 00:00:00") + 3 * sizeof(time_t)];
+ char timestr_b[10];
+ char **args = NULL;
+ char **arg;
+ char **argv = NULL;
+ char **envp = NULL;
+ size_t argsn;
+ int rc = 0, saved_errno;
+
+ /* Get remaining time. */
+ if (clock_gettime(job->clk, &rem))
+ return errno == EINVAL ? 0 : -1;
+ rem.tv_sec = job->ts.tv_sec - rem.tv_sec;
+ rem.tv_nsec = job->ts.tv_nsec - rem.tv_nsec;
+ FIX_NSEC(&rem);
+ 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. */
+ if (job->clk == CLOCK_REALTIME) {
+ t (!(tm = localtime(&(job->ts.tv_sec))));
+ strftime(timestr_a, sizeof(timestr_a), "%Y-%m-%d %H:%M:%S", tm);
+ } else {
+ strduration(timestr_a, job->ts.tv_sec);
+ }
+ 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)(job->argc))));
+ t (!(envp = sublist(args + job->argc, argsn - (size_t)(job->argc)))); /* Includes wdir. */
+
+ /* Send message. */
+ t (!(qstr = quote(args[0])));
+ t (!(wdir = quote(envp[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 (print(line, qstr,
+ "\n time: ", timestr_a, ".", timestr_b,
+ "\n wdir: ", wdir,
+ "\n argv:", NULL));
+ ARRAY(argv); t (print("\n envp:", NULL));
+ ARRAY(envp + 1); t (print("\n\n", NULL));
+
+done:
+ saved_errno = errno;
+ free(qstr), free(args), free(argv), free(wdir), free(envp);
+ errno = saved_errno;
+ return rc;
+fail:
+ rc = -1;
+ goto done;
+}
+
+
+/**
* Print all queued jobs.
*
* @param argc Should be 1 or 0.
@@ -36,15 +241,31 @@ USAGE(NULL)
* @return 0 The process was successful.
* @return 1 The process failed queuing the job.
* @return 2 User error, you do not know what you are doing.
- * @return 3 satd(1) failed.
*/
int
main(int argc, char *argv[])
{
+ struct job **jobs = NULL;
+ struct job **job;
+ int state = -1;
+
if (argc > 0) argv0 = argv[0];
if (argc > 1) usage();
- SEND(SAT_PRINT, (size_t)0, NULL);
- END(NULL);
+ GET_FD(state, STATE_FILENO, open_state(O_RDONLY, NULL));
+ t (!(jobs = get_jobs()));
+ for (job = jobs; *job; job++)
+ t (print_job(*job));
+
+ errno = 0;
+fail:
+ if (errno)
+ perror(argv[0]);
+ for (job = jobs; jobs && *job; job++)
+ free(*job);
+ free(jobs);
+ if (state >= 0)
+ close(state);
+ return !!errno;
}