diff options
Diffstat (limited to 'daemon.c')
-rw-r--r-- | daemon.c | 122 |
1 files changed, 122 insertions, 0 deletions
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); + } +} |