diff options
-rw-r--r-- | Makefile | 47 | ||||
-rw-r--r-- | catsit-timer.1 | 2 | ||||
-rw-r--r-- | catsit-timer.c | 2 | ||||
-rw-r--r-- | catsit-watch.1 | 2 | ||||
-rw-r--r-- | catsit-watch.c | 2 | ||||
-rw-r--r-- | catsit.8 | 27 | ||||
-rw-r--r-- | catsit.conf.5 | 13 | ||||
-rw-r--r-- | catsit.in | 14 | ||||
-rw-r--r-- | catsitd.8 | 2 | ||||
-rw-r--r-- | daemon.c | 107 | ||||
-rw-r--r-- | daemon.h | 6 | ||||
-rw-r--r-- | service.c | 6 |
12 files changed, 137 insertions, 93 deletions
diff --git a/Makefile b/Makefile index 2f52b2f..a3b40b7 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,10 @@ UNAME != uname PREFIX ?= /usr/local MANDIR ?= ${PREFIX}/man RUNDIR ?= /var/run -.if ${UNAME} == OpenBSD -ETCDIR ?= /etc -.else +.if ${UNAME} == FreeBSD ETCDIR ?= ${PREFIX}/etc +.else +ETCDIR ?= /etc .endif CFLAGS += -std=c99 -Wall -Wextra -Wpedantic @@ -18,12 +18,9 @@ RC_SCRIPT = ${UNAME}/catsitd BINS = catsit-timer catsit-watch SBINS = catsit catsitd -MAN1 = ${BINS:=.1} -MAN5 = catsit.conf.5 -MAN8 = ${SBINS:=.8} +MANS = ${BINS:=.1} catsit.conf.5 ${SBINS:=.8} -OBJS += daemon.o -OBJS += service.o +OBJS = daemon.o service.o dev: tags all @@ -46,34 +43,28 @@ tags: *.[ch] clean: rm -f ${BINS} ${SBINS} ${OBJS} ${RC_SCRIPT} tags -install: ${BINS} ${SBINS} ${RC_SCRIPT} ${MAN1} ${MAN5} ${MAN8} +install: ${BINS} ${SBINS} ${MANS} ${RC_SCRIPT} install -d ${DESTDIR}${PREFIX}/bin install -d ${DESTDIR}${PREFIX}/sbin - install -d ${DESTDIR}${MANDIR}/man1 - install -d ${DESTDIR}${MANDIR}/man5 - install -d ${DESTDIR}${MANDIR}/man8 +.for sect in 1 5 8 + install -d ${DESTDIR}${MANDIR}/man${sect} +.endfor install -d ${DESTDIR}${ETCDIR}/rc.d install ${BINS} ${DESTDIR}${PREFIX}/bin install ${SBINS} ${DESTDIR}${PREFIX}/sbin +.for man in ${MANS} + install -m 444 ${man} ${DESTDIR}${MANDIR}/man${man:E} +.endfor install ${RC_SCRIPT} ${DESTDIR}${ETCDIR}/rc.d - install -m 644 ${MAN1} ${DESTDIR}${MANDIR}/man1 - install -m 644 ${MAN5} ${DESTDIR}${MANDIR}/man5 - install -m 644 ${MAN8} ${DESTDIR}${MANDIR}/man8 uninstall: -.for BIN in ${BINS} - rm -f ${DESTDIR}${PREFIX}/bin/${BIN} -.endfor -.for SBIN in ${SBINS} - rm -f ${DESTDIR}${PREFIX}/sbin/${SBIN} +.for bin in ${BINS} + rm -f ${DESTDIR}${PREFIX}/bin/${bin} .endfor - rm -f ${DESTDIR}${ETCDIR}/rc.d/${RC_SCRIPT:T} -.for MAN in ${MAN1} - rm -f ${DESTDIR}${MANDIR}/man1/${MAN} +.for sbin in ${SBINS} + rm -f ${DESTDIR}${PREFIX}/sbin/${sbin} .endfor -.for MAN in ${MAN5} - rm -f ${DESTDIR}${MANDIR}/man5/${MAN} -.endfor -.for MAN in ${MAN8} - rm -f ${DESTDIR}${MANDIR}/man8/${MAN} +.for man in ${MANS} + rm -f ${DESTDIR}${MANDIR}/man${man:E}/${man} .endfor + rm -f ${DESTDIR}${ETCDIR}/rc.d/${RC_SCRIPT:T} diff --git a/catsit-timer.1 b/catsit-timer.1 index 9ad8956..53f6024 100644 --- a/catsit-timer.1 +++ b/catsit-timer.1 @@ -59,4 +59,4 @@ exits with the same status. .Xr catsitd 8 . .Sh AUTHORS -.An June Bug Aq Mt june@causal.agency +.An June McEnroe Aq Mt june@causal.agency diff --git a/catsit-timer.c b/catsit-timer.c index 2869311..1f754c3 100644 --- a/catsit-timer.c +++ b/catsit-timer.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/catsit-watch.1 b/catsit-watch.1 index 5e97bdd..b5ccccd 100644 --- a/catsit-watch.1 +++ b/catsit-watch.1 @@ -61,4 +61,4 @@ exits with the same status. .Xr catsitd 8 . .Sh AUTHORS -.An June Bug Aq Mt june@causal.agency +.An June McEnroe Aq Mt june@causal.agency diff --git a/catsit-watch.c b/catsit-watch.c index 096449b..1bee8cf 100644 --- a/catsit-watch.c +++ b/catsit-watch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/catsit.8 b/catsit.8 index 7448012..e52b188 100644 --- a/catsit.8 +++ b/catsit.8 @@ -1,4 +1,4 @@ -.Dd August 16, 2020 +.Dd September 28, 2021 .Dt CATSIT 8 .Os . @@ -8,6 +8,7 @@ . .Sh SYNOPSIS .Nm +.Op Fl q .Op Fl c Ar control .Cm start|stop|restart|status|drop Ns | Ns Ar signal .Ar service ... @@ -29,6 +30,15 @@ Communication with is unidirectional. The daemon logs any feedback with syslog. +The +.Nm +utility waits +a tenth of a second +after sending the command +then shows recent messages from +.Xr catsitd 8 +in +.Pa /var/log/messages . . .Pp The arguments are as follows: @@ -36,6 +46,10 @@ The arguments are as follows: .It Fl c Ar control Set the path of the named pipe. . +.It Fl q +Do not show +.Pa /var/log/messages . +. .It Cm start Start any matching services which are not already started. @@ -72,10 +86,9 @@ to the processes of any matching started services. Signal names are case-insensitive. . .It Ar service ... -The list of services to operate on. -Service names can include -.Sy *?[] -shell-style pattern operators. +The list of services to operate on, +using shell-style pattern matching as in +.Xr glob 7 . Patterns must be quoted to be interpreted by .Xr catsitd 8 @@ -103,7 +116,7 @@ The default path of the named pipe. . .Sh EXAMPLES .Bd -literal -catsit restart pounce/freenode +catsit restart pounce/tilde catsit INFO 'pounce/*' .Ed . @@ -111,4 +124,4 @@ catsit INFO 'pounce/*' .Xr catsitd 8 . .Sh AUTHORS -.An June Bug Aq Mt june@causal.agency +.An June McEnroe Aq Mt june@causal.agency diff --git a/catsit.conf.5 b/catsit.conf.5 index b7a45d4..e9de2ce 100644 --- a/catsit.conf.5 +++ b/catsit.conf.5 @@ -1,4 +1,4 @@ -.Dd March 1, 2021 +.Dd September 28, 2021 .Dt CATSIT.CONF 5 .Os . @@ -13,6 +13,10 @@ file lists the services managed by the .Xr catsitd 8 daemon. Leading whitespace is ignored. +The current line +can be extended over multiple lines +using a backslash +.Pq Ql \e . Each line of the file is one of the following: . @@ -78,11 +82,12 @@ calico calico -H irc.example.org $socks pounce pounce -U $socks pounce.conf # Templating command lines using service names: -pounce/freenode pounce ${0#*/}.conf pounce/tilde pounce ${0#*/}.conf +pounce/libera pounce ${0#*/}.conf # Privileged services: -@scooper kfcgi -d -U $USER -p ~/.local -- /bin/scooper +@scooper kfcgi -d -U $USER -p ~/.local -- \e + /bin/scooper /share/litterbox/litterbox.sqlite .Ed . .Sh SEE ALSO @@ -91,4 +96,4 @@ pounce/tilde pounce ${0#*/}.conf .Xr catsitd 8 . .Sh AUTHORS -.An June Bug Aq Mt june@causal.agency +.An June McEnroe Aq Mt june@causal.agency diff --git a/catsit.in b/catsit.in index 6e934f1..0d28a1d 100644 --- a/catsit.in +++ b/catsit.in @@ -8,18 +8,20 @@ die() { : ${CATSITD_PIPE:='%%RUNDIR%%/catsitd.pipe'} -while getopts 'c:' opt; do - case "${opt}" in +quiet= +while getopts 'c:q' opt; do + case $opt in (c) CATSITD_PIPE=$OPTARG;; + (q) quiet=q;; (?) exit 1;; esac done shift $((OPTIND - 1)) -if ! [ -p "${CATSITD_PIPE}" ]; then +if ! test -p "${CATSITD_PIPE}"; then die "${CATSITD_PIPE} is not a named pipe" fi -if ! [ -w "${CATSITD_PIPE}" ]; then +if ! test -w "${CATSITD_PIPE}"; then die "${CATSITD_PIPE} is not writable" fi @@ -35,3 +37,7 @@ if [ "${action}" != "${valid}" ]; then fi echo "$@" > "${CATSITD_PIPE}" +test $quiet && exit + +sleep 0.1 +tail /var/log/messages | grep catsitd diff --git a/catsitd.8 b/catsitd.8 index fa1e67a..aaedbf0 100644 --- a/catsitd.8 +++ b/catsitd.8 @@ -223,4 +223,4 @@ used for service control. .Xr catsit 8 . .Sh AUTHORS -.An June Bug Aq Mt june@causal.agency +.An June McEnroe Aq Mt june@causal.agency diff --git a/daemon.c b/daemon.c index f36e277..736fd08 100644 --- a/daemon.c +++ b/daemon.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -49,6 +49,34 @@ static void signalHandler(int signal) { signals[signal] = 1; } +static ssize_t getlinecont(char **line, size_t *lcap, FILE *file) { + size_t cap = 0; + char *buf = NULL; + ssize_t llen = getline(line, lcap, file); + while (llen > 1 && (*line)[llen - 1] == '\n' && (*line)[llen - 2] == '\\') { + llen -= 2; + ssize_t len = getline(&buf, &cap, file); + if (len < 0) { + llen = -1; + break; + } + size_t req = llen + len + 1; + if (req > *lcap) { + char *ptr = realloc(*line, req); + if (!ptr) { + llen = -1; + break; + } + *line = ptr; + *lcap = req; + } + strlcpy(*line + llen, buf, *lcap - llen); + llen += len; + } + free(buf); + return llen; +} + static int parseConfig(const char *path) { int ret = -1; size_t cap = 0; @@ -63,14 +91,15 @@ static int parseConfig(const char *path) { prependClear(); int line = 1; - for (ssize_t len; 0 <= (len = getline(&buf, &cap, file)); ++line) { + for (ssize_t len; 0 <= (len = getlinecont(&buf, &cap, file)); ++line) { if (buf[len - 1] == '\n') buf[len - 1] = '\0'; char *ptr = &buf[strspn(buf, WS)]; if (!ptr[0] || ptr[0] == '#') { continue; } else if (ptr[0] == '%') { - int error = prependAdd(&ptr[1]); + ptr++; + int error = prependAdd(&ptr[strspn(ptr, WS)]); if (error) { syslog(LOG_WARNING, "cannot add prepend command: %m"); goto err; @@ -84,7 +113,7 @@ static int parseConfig(const char *path) { ); goto err; } - int error = serviceAdd(name, ptr); + int error = serviceAdd(name, &ptr[strspn(ptr, WS)]); if (error) { syslog(LOG_WARNING, "cannot add service: %m"); goto err; @@ -215,30 +244,9 @@ int main(int argc, char *argv[]) { } } -#ifdef __OpenBSD__ - struct { - const char *path; - const char *mode; - } paths[] = { - { fifoPath, "crw" }, - { configPath, "r" }, - { "/", "r" }, - { "/dev/null", "rw" }, - { serviceDir, "r" }, - { _PATH_BSHELL, "x" }, - { pidPath, "cw" }, - { NULL, NULL }, - }; - for (size_t i = 0; paths[i].path; ++i) { - error = unveil(paths[i].path, paths[i].mode); - if (error) err(EX_CANTCREAT, "%s", paths[i].path); - } - error = pledge( - "stdio cpath dpath rpath wpath flock getpw proc exec id", NULL - ); - if (error) err(EX_OSERR, "pledge"); -#endif - + error = access(configPath, R_OK); + if (error) err(EX_NOINPUT, "%s", configPath); + error = access(serviceDir, X_OK); if (error) err(EX_NOINPUT, "%s", serviceDir); @@ -292,9 +300,6 @@ int main(int argc, char *argv[]) { int writer = open(fifoPath, O_WRONLY | O_NONBLOCK | O_CLOEXEC); if (writer < 0) err(EX_CANTCREAT, "%s", fifoPath); - error = parseConfig(configPath); - if (error) return EX_DATAERR; - if (daemonize) { error = daemon(0, 0); if (error) { @@ -302,27 +307,47 @@ int main(int argc, char *argv[]) { return EX_OSERR; } } - if (pidPath) { - int len = dprintf(pidFile, "%ju", (uintmax_t)getpid()); - if (len < 0) syslog(LOG_WARNING, "%s: %m", pidPath); - } #ifdef __OpenBSD__ - error = pledge("stdio cpath rpath proc exec id", NULL); + error = 0 + || unveil(fifoPath, "c") + || unveil(configPath, "r") + || unveil(serviceDir, "r") + || unveil(_PATH_BSHELL, "x"); + if (error) err(EX_OSERR, "unveil"); + if (pidPath) { + error = unveil(pidPath, "c"); + if (error) err(EX_OSERR, "unveil"); + } + error = pledge("stdio rpath cpath proc exec id", NULL); if (error) err(EX_OSERR, "pledge"); #endif + if (pidPath) { + int len = dprintf(pidFile, "%ju", (uintmax_t)getpid()); + if (len < 0) syslog(LOG_WARNING, "%s: %m", pidPath); + } + signal(SIGHUP, signalHandler); signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGCHLD, signalHandler); signal(SIGINFO, signalHandler); + parseConfig(configPath); for (size_t i = 0; i < services.len; ++i) { serviceStart(&services.ptr[i]); } setTitle(); + struct pollfd *fds = calloc(1 + 2 * services.len, sizeof(*fds)); + if (!fds) { + syslog(LOG_ERR, "calloc: %m"); + goto shutdown; + } + fds[0].fd = fifo; + fds[0].events = POLLIN; + sigset_t mask; sigemptyset(&mask); for (;;) { @@ -342,6 +367,11 @@ int main(int argc, char *argv[]) { } if (signals[SIGHUP]) { parseConfig(configPath); + fds = reallocarray(fds, 1 + 2 * services.len, sizeof(*fds)); + if (!fds) { + syslog(LOG_ERR, "reallocarray: %m"); + goto shutdown; + } setTitle(); signals[SIGHUP] = 0; } @@ -351,10 +381,6 @@ int main(int argc, char *argv[]) { signals[SIGINFO] = 0; } - struct pollfd fds[1 + 2 * services.len]; - fds[0].fd = fifo; - fds[0].events = POLLIN; - struct timespec deadline = {0}; for (size_t i = 0; i < services.len; ++i) { struct Service *service = &services.ptr[i]; @@ -425,6 +451,7 @@ int main(int argc, char *argv[]) { } } +shutdown: close(fifo); unlink(fifoPath); diff --git a/daemon.h b/daemon.h index e86e43a..b68c51c 100644 --- a/daemon.h +++ b/daemon.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -38,7 +38,9 @@ static inline void prependClear(void) { static inline int prependAdd(const char *command) { if (prepend.len == prepend.cap) { size_t cap = (prepend.cap ? prepend.cap * 2 : 8); - void *ptr = realloc(prepend.commands, sizeof(*prepend.commands) * cap); + void *ptr = reallocarray( + prepend.commands, cap, sizeof(*prepend.commands) + ); if (!ptr) return -1; prepend.cap = cap; prepend.commands = ptr; diff --git a/service.c b/service.c index 38049ff..2406175 100644 --- a/service.c +++ b/service.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -82,7 +82,7 @@ int serviceAdd(const char *name, const char *command) { if (services.len == services.cap) { size_t cap = (services.cap ? services.cap * 2 : 8); - void *ptr = realloc(services.ptr, sizeof(*services.ptr) * cap); + void *ptr = reallocarray(services.ptr, cap, sizeof(*services.ptr)); if (!ptr) return -1; services.cap = cap; services.ptr = ptr; @@ -247,7 +247,7 @@ void serviceStart(struct Service *service) { } int n = snprintf( &command[len], sizeof(command) - len, "%s%s", - (service->command[strcspn(service->command, ";&|()")] ? "exec " : ""), + (service->command[strcspn(service->command, ";&|()")] ? "" : "exec "), service->command ); assert(n > 0); |