/* Copyright (C) 2020 C. McEnroe * * 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 . */ #include #include #include #include #include #include #include #include #include #include #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); } }