diff options
-rw-r--r-- | src/client.c | 2 | ||||
-rw-r--r-- | src/client.h | 2 | ||||
-rw-r--r-- | src/common.h | 121 | ||||
-rw-r--r-- | src/daemonise.c | 36 | ||||
-rw-r--r-- | src/parse_time.c | 28 | ||||
-rw-r--r-- | src/sat.c | 57 | ||||
-rw-r--r-- | src/satd.c | 60 | ||||
-rw-r--r-- | src/satq.c | 28 | ||||
-rw-r--r-- | src/satr.c | 57 | ||||
-rw-r--r-- | src/satrm.c | 50 |
10 files changed, 206 insertions, 235 deletions
diff --git a/src/client.c b/src/client.c index c4f2987..b7a43eb 100644 --- a/src/client.c +++ b/src/client.c @@ -45,7 +45,7 @@ extern char *argv0; int send_command(enum command cmd, size_t n, const char *restrict msg) { - return 0 /* TODO */ + return 0; /* TODO */ } diff --git a/src/client.h b/src/client.h index 6a2b91b..d341df6 100644 --- a/src/client.h +++ b/src/client.h @@ -71,7 +71,7 @@ int send_command(enum command cmd, size_t n, const char *restrict msg); * @param array The string array. * @return The number of bytes required to store the array. */ -size_t measure_array(char *array[]) +size_t measure_array(char *array[]); /** * Store a string array. diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..2f8ac86 --- /dev/null +++ b/src/common.h @@ -0,0 +1,121 @@ +/** + * Copyright © 2015 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 <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + + + +/** + * Go to `fail` if a statement evaluates to non-zero. + * + * @param ... The statement. + */ +#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) + + + +/** + * Defines the function `void usage(void)` + * that prints usage information. + * + * @param synopsis:const char* The command's synopsis sans command name. + * `NULL` if there are not arguments. + */ +#define USAGE(synopsis) \ +static void \ +usage(void) \ +{ \ + fprintf(stderr, "usage: %s%s%s\n", \ + strrchr(argv0, '/') ? (strrchr(argv0, '/') + 1) : argv0, \ + (synopsis) ? " " : "", synopsis ? synopsis : ""); \ + exit(2); \ +} + + +/** + * Declares `argv0` and its value to + * a specified string. + * + * @param name:sitrng literal The name of the command. + */ +#define COMMAND(name) \ +char *argv0 = name; + + +/** + * Print usage and exit if there is any argument + * that is an option. + */ +#define NO_OPTIONS \ + int i; + if (!strcmp(argv[1], "--")) \ + argv++, argc--; \ + for (i = 1; i < argc; i++) \ + if (strchr("-", argv[i][0])) \ + usage() + + +/** + * Construct a message from `argv` + * to send to the daemon. + */ +#define CONSTRUCT_MESSAGE \ + n = measure_array(argv + 1); \ + t (n ? !(msg = malloc(n)) : 0); \ + store_array(msg, argv + 1) + + +/** + * Send message to daemon. + * + * @param cmd:enum command Command type. + * @param n:size_t The length of the message, 0 if + * `msg` is `NULL` or NUL-terminated. + * @param msg:char * The message to send. + */ +#define SEND(type, n, msg) \ +do { \ + if (send_command(type, n, msg)) { \ + t (errno); \ + free(msg); \ + return 3; \ + } +} while (0) + + +/** + * Exit the process with status indicating success. + * + * Defined the label `fail`. + * + * @param msg The message send to the daemon. + */ +#define END(msg) \ + free(msg); \ + return 0; \ +fail: \ + perror(argv0); \ + free(msg); \ + return 1; + diff --git a/src/daemonise.c b/src/daemonise.c index 929eca0..fb1546d 100644 --- a/src/daemonise.c +++ b/src/daemonise.c @@ -21,12 +21,15 @@ * * This file is copied from <http://github.com/maandree/slibc>. */ +#include "daemonise.h" #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <string.h> +#include <stdio.h> #include <stdlib.h> #include <errno.h> +#include <sys/stat.h> #include <sys/resource.h> @@ -149,10 +152,11 @@ int daemonise(const char* name, int flags) struct rlimit rlimit; int pipe_rw[2] = { -1, -1 }; sigset_t set; - char* r; - char* w; + char** r; + char** w; char* run; int i, closeerr, fd = -1; + pid_t pid; int saved_errno; @@ -217,7 +221,7 @@ int daemonise(const char* name, int flags) t (pid = fork(), pid == -1); close(pipe_rw[!!pid]), pipe_rw[!!pid] = 1; if (pid) - exit(read(pipe_rw[0], &b, (size_t)1) <= 0); + exit(read(pipe_rw[0], &fd, (size_t)1) <= 0); /* Temporarily become session leader. */ t (setsid() == -1); @@ -233,26 +237,26 @@ int daemonise(const char* name, int flags) run = getenv("XDG_RUNTIME_DIR"); if (run && *run) { - pidpath = malloc(sizeof("/.pid") + (strlen(run) + strlen(name)) * sizeof(char)); - t (pidfile == NULL); - stpcpy(stpcpy(stpcpy(stpcpy(pidpath, run), "/"), name), ".pid"); + __pidfile = malloc(sizeof("/.pid") + (strlen(run) + strlen(name)) * sizeof(char)); + t (__pidfile == NULL); + stpcpy(stpcpy(stpcpy(stpcpy(__pidfile, run), "/"), name), ".pid"); } else { - pidpath = malloc(sizeof("/run/.pid") + strlen(name) * sizeof(char)); - t (pidfile == NULL); - stpcpy(stpcpy(stpcpy(pidpath, "/run/"), name), ".pid"); + __pidfile = malloc(sizeof("/run/.pid") + strlen(name) * sizeof(char)); + t (__pidfile == NULL); + stpcpy(stpcpy(stpcpy(__pidfile, "/run/"), name), ".pid"); } - fd = open(pidpath, O_WRONLY | O_CREAT | O_EXCL, 0644); + fd = open(__pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd == -1) { saved_errno = errno; - free(pidpath), pidpath = NULL; + free(__pidfile), __pidfile = NULL; errno = saved_errno; goto fail; } pid = getpid(); - t (dprintf(fd, "%lli\n", (long long int)pid)) < 0; + t (dprintf(fd, "%lli\n", (long long int)pid) < 0); t (close(fd) && (errno != EINTR)); no_pid_file: @@ -275,7 +279,7 @@ int daemonise(const char* name, int flags) fd = -1; /* We are done! Let the original process exit. */ - if ((write(pipe_rw[1], &b, (size_t)1) <= 0) || + if ((write(pipe_rw[1], &fd, (size_t)1) <= 0) || (close(pipe_rw[1]) && (errno != EINTR))) { if (flags & DAEMONISE_KEEP_STDERR) @@ -313,11 +317,11 @@ int daemonise(const char* name, int flags) int undaemonise(void) { int r, saved_errno; - if (pidfile == NULL) + if (__pidfile == NULL) return 0; - r = unlink(pidfile); + r = unlink(__pidfile); saved_errno = errno; - free(pidfile), pidfile = NULL; + free(__pidfile), __pidfile = NULL; errno = saved_errno; return r; } diff --git a/src/parse_time.c b/src/parse_time.c index d86ef43..51e9011 100644 --- a/src/parse_time.c +++ b/src/parse_time.c @@ -58,6 +58,11 @@ */ extern char *argv0; +/** + * The highest value that can be stored in `time_t`. + */ +const time_t timemax = (sizeof(time_t) == sizeof(long long int)) ? LLONG_MAX : LONG_MAX; + /** @@ -81,6 +86,7 @@ strtotime(const char *str, const char **end) time_t rc; long long int rcll; long int rcl; + char **end_ = (char **)end; if (!isdigit(*str)) FAIL(EINVAL); @@ -91,10 +97,10 @@ strtotime(const char *str, const char **end) errno = 0; if (sizeof(time_t) == sizeof(long long int)) { - rcll = strtoll(str, end, 10); + rcll = strtoll(str, end_, 10); rc = (time_t)rcll; } else { - rcl = strtol(str, end, 10); + rcl = strtol(str, end_, 10); rc = (time_t)rcl; } @@ -117,9 +123,7 @@ strtotime(const char *str, const char **end) static int parse_time_time(const char *str, struct timespec *ts, const char **end) { - char *end; time_t t; - const time_t timemax = (sizeof(time_t) == sizeof(long long int)) ? LLONG_MAX : LONG_MAX; memset(ts, 0, sizeof(*ts)); @@ -208,9 +212,9 @@ int parse_time(const char *str, struct timespec *ts, clockid_t *clk) { struct timespec now; - int plus = *str == '+'; - char *start = str; - char *end; + int points, plus = *str == '+'; + const char *start = str; + const char *end; time_t adj; /* Get current time and clock. */ @@ -218,7 +222,7 @@ parse_time(const char *str, struct timespec *ts, clockid_t *clk) *clk = plus ? CLOCK_MONOTONIC : CLOCK_REALTIME; /* Mañana? */ - if (!strcmp("mañana")) { /* Do not documented. */ + if (!strcmp(str, "mañana")) { /* Do not documented. */ ts->tv_sec = now.tv_sec + ONE_DAY; ts->tv_nsec = now.tv_nsec; return 0; @@ -228,7 +232,7 @@ parse_time(const char *str, struct timespec *ts, clockid_t *clk) if (strchr(str, ':')) { if (parse_time_time(str, ts, &end)) return -1; - adj = now.sec - (now.sec % ONE_DAY); + adj = now.tv_sec - (now.tv_sec % ONE_DAY); ADD(ts->tv_sec, adj); /* In case the HH is really large. */ } else { if (parse_time_seconds(str + plus, ts, &end)) @@ -244,7 +248,7 @@ parse_time(const char *str, struct timespec *ts, clockid_t *clk) } /* Parse up to nanosecond resolution. */ - for (; isdigit(*str); points++) { + for (points = 0; isdigit(*str); points++) { if (points < 9) { ts->tv_nsec *= 10; ts->tv_nsec += *str++ & 15; @@ -260,10 +264,10 @@ parse_time(const char *str, struct timespec *ts, clockid_t *clk) /* Check for error at end, and missing explicit UTC. */ if (*str) { if (*clk == CLOCK_MONOTONIC) - FAIL(einval); + FAIL(EINVAL); while (*str == ' ') str++; if (!strcasecmp(str, "Z") && !strcasecmp(str, "UTC")) - FAIL(einval); + FAIL(EINVAL); } else if (*clk == CLOCK_REALTIME) { fprintf(stderr, "%s: warning: parsing as UTC, you can avoid " @@ -19,36 +19,20 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <errno.h> #include "parse_time.h" #include "client.h" +#include "common.h" -/** - * The name of the process. - */ -char *argv0 = "sat"; +COMMAND("sat") +USAGE("TIME COMMAND...") /** - * Print usage information. - */ -static void -usage(void) -{ - fprintf(stderr, "usage: %s TIME COMMAND...\n", - strrchr(argv0) ? (strrchr(argv0) + 1) : argv0); - exit(2); -} - - -/** * Queue a job for later execution. * * @param argc You guess! @@ -70,14 +54,13 @@ main(int argc, char *argv[], char *envp[]) struct timespec ts; clockid_t clk; char *msg = NULL; - char *w; - char *r; + char **w; + char **r; int removed_empty = 0; size_t n; - if ((argc < 3) || (argv[1][0] == '-')) { + if ((argc < 3) || (argv[1][0] == '-')) usage(); - } argv0 = argv[0]; @@ -87,17 +70,17 @@ main(int argc, char *argv[], char *envp[]) case EINVAL: fprintf(stderr, "%s: time parameter cound not be parsed, perhaps you " - "you need an external parser: %s\n", argv0, str); + "you need an external parser: %s\n", argv0, argv[1]); return 2; case ERANGE: fprintf(stderr, "%s: the specified time is beyond the limit of what " - "can be represented by `struct timespec`: %s\n", argv0, str); + "can be represented by `struct timespec`: %s\n", argv0, argv[1]); return 2; case EDOM: fprintf(stderr, "%s: the specified time is in past, and more than " - "a day ago: %s\n", argv0, str); + "a day ago: %s\n", argv0, argv[1]); return 2; default: goto fail; @@ -108,7 +91,7 @@ main(int argc, char *argv[], char *envp[]) argv += 2; /* Remove empty environment entries */ - for (w = r = envp; *r; *r++) { + for (w = r = envp; *r; r++) { if (**r) { *w++ = *r; } else if (removed_empty == 0) { @@ -121,24 +104,14 @@ main(int argc, char *argv[], char *envp[]) /* Construct message to send to the daemon. */ n = measure_array(argv) + measure_array(envp); - if (!(msg = malloc(n + sizeof(clk) + sizeof(ts)))) - goto fail; + t (!(msg = malloc(n + sizeof(clk) + sizeof(ts)))); store_array(store_array(msg, argv), envp); - memcpy(msg + n, clk, sizeof(clk)), n += sizeof(clk); - memcpy(msg + n, ts, sizeof(ts)), n += sizeof(ts); + memcpy(msg + n, &clk, sizeof(clk)), n += sizeof(clk); + memcpy(msg + n, &ts, sizeof(ts)), n += sizeof(ts); /* Send job to daemon, start daemon if necessary. */ - if (send_command(SAT_QUEUE, n, msg)) { - if (errno) - goto fail; - free(msg); - return 3; - } - return 0; + SEND(SAT_QUEUE, n, msg); -fail: - perror(argv0); - free(msg); - return 1; + END(msg); } @@ -19,56 +19,21 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <unistd.h> #include <errno.h> -#include <grp.h> #include <sys/stat.h> #include <sys/socket.h> +#include <sys/un.h> #include "daemonise.h" +#include "common.h" -#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) +COMMAND("satd") +USAGE("[-f]") -/** - * The name of the process. - */ -char *argv0 = "satd"; - - - -/** - * Print usage information. - */ -static void -usage(void) -{ - fprintf(stderr, "usage: [-f] %s\n", - strrchr(argv0) ? (strrchr(argv0) + 1) : argv0); - exit(2); -} - - -/** - * Get the group ID of a group. - * - * @param name The name of the group. - * @param fallback The group ID to return if the group is not found. - * @return The ID of the group, -1 on error. - */ -static gid_t -getgroup(const char* name, gid_t fallback) -{ - struct group *g; - if (!(g = getgrnam(name))) - return errno ? (gid_t)-1 : fallback; - return g->gr_gid; -} - /** * Create the socket. @@ -82,22 +47,19 @@ create_socket(struct sockaddr_un *address) int fd = -1; ssize_t len; char *dir; - gid_t group; + int saved_errno; - dir = getenv("XDG_RUNTIME_DIR"), dir = (dir ? dir : "/run") + dir = getenv("XDG_RUNTIME_DIR"), dir = (dir ? dir : "/run"); t (snprintf(NULL, 0, "%s/satd.socket%zn", dir, &len) == -1); - if ((len < 0) || (len >= sizeof(address->sun_path))) { - errno = ENAMETOOLING; - goto fail; - } - sprintf(address->sun_path, "%s/satd.socket", dir) + if ((len < 0) || ((size_t)len >= sizeof(address->sun_path))) + t ((errno = ENAMETOOLONG)); + sprintf(address->sun_path, "%s/satd.socket", dir); address->sun_family = AF_UNIX; /* TODO test flock */ unlink(address->sun_path); t ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1); t (fchmod(fd, S_IRWXU) == -1); - t ((group = getgroup("nobody", 0)) == -1); - t (fchown(fd, getuid(), group) == -1); + t (fchown(fd, getuid(), getgid()) == -1); t (bind(fd, (struct sockaddr *)address, sizeof(*address)) == -1); /* TODO flock */ @@ -19,31 +19,14 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - #include "client.h" +#include "common.h" -/** - * The name of the process. - */ -char *argv0 = "satq"; - - +COMMAND("satq") +USAGE(NULL) -/** - * Print usage information. - */ -static void -usage(void) -{ - fprintf(stderr, "usage: %s\n", - strrchr(argv0) ? (strrchr(argv0) + 1) : argv0); - exit(2); -} /** @@ -62,8 +45,7 @@ main(int argc, char *argv[]) if (argc > 0) argv0 = argv[0]; if (argc > 1) usage(); - if (send_command(SAT_PRINT, 0, NULL)) - return errno ? (perror(argv0), 1) : 3; - return 0; + SEND(SAT_PRINT, 0, NULL)); + END(NULL); } @@ -19,35 +19,17 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - #include "client.h" +#include "common.h" -/** - * The name of the process. - */ -char *argv0 = "satr"; +COMMAND("satr") +USAGE("[JOB-ID]...") /** - * Print usage information. - */ -static void -usage(void) -{ - fprintf(stderr, "usage: %s [JOB-ID]...\n", - strrchr(argv0) ? (strrchr(argv0) + 1) : argv0); - exit(2); -} - - -/** * Run all queued jobs even if it is not time yet. * * @param argc Should be 1 or 0. @@ -62,35 +44,14 @@ main(int argc, char *argv[]) { size_t n = 0; char *msg = NULL; - int i; - if (argc > 0) - argv0 = argv[0]; - if (argc < 2) - goto run; - if (!strcmp(argv[1], "--")) - argv++, argc--; - for (i = 1; i < argc; i++) - if (strchr("-", argv[i][0])) - usage(); - - n = measure_array(argv + 1); - if (n ? !(msg = malloc(n)) : 0) - goto fail; - store_array(msg, argv + 1); + if (argc > 0) argv0 = argv[0]; + if (argc < 2) goto run; + NO_OPTIONS; + CONSTRUCT_MESSAGE; run: - if (send_command(SAT_RUN, n, msg)) { - if (errno) - goto fail; - free(msg); - return 3; - } - return 0; - -fail: - perror(*argv); - free(msg); - return 1; + SEND(SAT_RUN, n, msg); + END(msg); } diff --git a/src/satrm.c b/src/satrm.c index 28bea0b..0a9eccf 100644 --- a/src/satrm.c +++ b/src/satrm.c @@ -19,35 +19,17 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - #include "client.h" +#include "common.h" -/** - * The name of the process. - */ -char *argv0 = "satrm"; +COMMAND("satrm") +USAGE("JOB-ID...") /** - * Print usage information. - */ -static void -usage(void) -{ - fprintf(stderr, "usage: %s JOB-ID...\n", - strrchr(argv0) ? (strrchr(argv0) + 1) : argv0); - exit(2); -} - - -/** * Remove a job from the queue of jobs. * * @param argc Should be 2. @@ -63,31 +45,13 @@ main(int argc, char *argv[]) { size_t n; char *msg; - int i; if (argc > 0) argv0 = argv[0]; if (argc < 2) usage(); - if (!strcmp(argv[1], "--") - argv++, argc--; - for (i = 1; i < argc; i++) - if (strchr("-", argv[i][0])) - usage(); - - if (!(msg = malloc(n = measure_array(argv + 1)))) - goto fail; - store_array(msg, argv + 1); - - if (send_command(SAT_REMOVE, n, msg)) { - if (errno) - goto fail; - free(msg); - return 3; - } - return 0; -fail: - perror(*argv); - free(msg); - return 1; + NO_OPTIONS; + CONSTRUCT_MESSAGE; + SEND(SAT_REMOVE, n, msg)); + END(msg); } |