diff options
Diffstat (limited to '')
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | daemon.c | 122 | ||||
-rw-r--r-- | daemon.h | 35 |
4 files changed, 176 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..821db5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +config.mk +spawn +spawnd diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..46ab385 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CFLAGS += -std=c99 -Wall -Wextra -Wpedantic + +-include config.mk + +OBJS += daemon.o + +all: spawn spawnd + +spawnd: ${OBJS} + ${CC} ${LDFLAGS} ${OBJS} ${LDLIBS} -o $@ + +${OBJS}: daemon.h + +clean: + rm -f spawn spawnd ${OBJS} diff --git a/daemon.c b/daemon.c new file mode 100644 index 0000000..36d5986 --- /dev/null +++ b/daemon.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2020 C. 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sysexits.h> +#include <unistd.h> + +#include "daemon.h" + +#ifndef RUNDIR +#define RUNDIR "/var/run" +#endif + +#ifndef ETCDIR +#define ETCDIR "/usr/local/etc" +#endif + +int restartInterval = 1000; +struct Set256 stopExits; + +static void parseExits(char *list) { + setClear(&stopExits); + while (*list) { + byte exit = strtoul(list, &list, 10); + if (*list) { + if (*list != ',') errx(EX_USAGE, "invalid exit status %s", list); + list++; + } + setAdd(&stopExits, exit); + } +} + +int main(int argc, char *argv[]) { + bool daemonize = true; + + const char *pidPath = NULL; + const char *configPath = ETCDIR "/spawntab"; + const char *fifoPath = RUNDIR "/spawnd.pipe"; + + const char *chdirPath = "/"; + const char *user = NULL; + const char *group = NULL; + + setAdd(&stopExits, 127); + setAdd(&stopExits, EX_USAGE); + setAdd(&stopExits, EX_DATAERR); + setAdd(&stopExits, EX_NOINPUT); + setAdd(&stopExits, EX_OSFILE); + setAdd(&stopExits, EX_CANTCREAT); + setAdd(&stopExits, EX_CONFIG); + + for (int opt; 0 < (opt = getopt(argc, argv, "C:c:df:g:p:s:t:u:"));) { + switch (opt) { + break; case 'C': chdirPath = optarg; + break; case 'c': fifoPath = optarg; + break; case 'd': daemonize = false; + break; case 'f': configPath = optarg; + break; case 'g': group = optarg; + break; case 'p': pidPath = optarg; + break; case 's': parseExits(optarg); + break; case 't': restartInterval = strtoul(optarg, NULL, 10); + break; case 'u': user = optarg; + break; default: return EX_USAGE; + } + } + + int pidFile = -1; + if (pidPath) { + pidFile = open( + pidPath, O_WRONLY | O_CREAT | O_EXLOCK | O_CLOEXEC, 0600 + ); + if (pidFile < 0) err(EX_CANTCREAT, "%s", pidPath); + } + + // TODO: Read config file. + + int error = access(chdirPath, X_OK); + if (error) err(EX_NOINPUT, "%s", chdirPath); + + // TODO: Do user, group lookup. + + // We can't lock a named pipe, so just warn if it already exists. + error = mkfifo(fifoPath, 0600); + if (error) { + if (errno != EEXIST) err(EX_CANTCREAT, "%s", fifoPath); + warn("%s", fifoPath); + } + + int fifo = open(fifoPath, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fifo < 0) err(EX_CANTCREAT, "%s", fifoPath); + + // TODO: Daemonize, write pid file. + + // TODO: Main loop. + + close(fifo); + unlink(fifoPath); + if (pidPath) { + close(pidFile); + unlink(pidPath); + } +} diff --git a/daemon.h b/daemon.h new file mode 100644 index 0000000..0d9e4de --- /dev/null +++ b/daemon.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2020 C. 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> + +typedef unsigned char byte; + +struct Set256 { + uint32_t bits[8]; +}; +static inline void setClear(struct Set256 *set) { + for (int i = 0; i < 8; ++i) set->bits[i] = 0; +} +static inline void setAdd(struct Set256 *set, byte x) { + set->bits[x / 32] |= 1 << (uint32_t)(x & 31); +} +static inline uint32_t setTest(const struct Set256 *set, byte x) { + return set->bits[x / 32] & (1 << (uint32_t)(x & 31)); +} + +extern int restartInterval; +extern struct Set256 stopExits; |