From f556af9ad5c90db94ecf01af2b50a22f6c721791 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sat, 15 Aug 2020 13:05:31 -0400 Subject: Implement non-blocking line-buffered reading --- daemon.c | 18 ++++++++++++++++-- daemon.h | 43 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/daemon.c b/daemon.c index 9eb8bb4..42ea78f 100644 --- a/daemon.c +++ b/daemon.c @@ -209,8 +209,11 @@ int main(int argc, char *argv[]) { warn("%s", fifoPath); } - int fifo = open(fifoPath, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + // XXX: Make sure there is always at least one writer open, otherwise we + // get EOF continually. + int fifo = open(fifoPath, O_RDWR | O_NONBLOCK | O_CLOEXEC); if (fifo < 0) err(EX_CANTCREAT, "%s", fifoPath); + struct Line fifoLine = {0}; openlog(getprogname(), LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_DAEMON); @@ -277,8 +280,19 @@ int main(int argc, char *argv[]) { (timespecisset(&deadline) ? &timeout : NULL), &mask ); + if (nfds < 0 && errno != EINTR) { + syslog(LOG_ERR, "ppoll: %m"); + continue; + } + + if (nfds > 0 && fds[0].revents) { + for (char *line; NULL != (line = lineRead(&fifoLine, fifo));) { + syslog(LOG_INFO, "control: %s", line); + } + if (errno != EAGAIN) syslog(LOG_ERR, "read: %m"); + } - // TODO: Handle FIFO and pipes. + // TODO: Handle pipes. if (timespecisset(&deadline)) { clock_gettime(CLOCK_MONOTONIC, &now); diff --git a/daemon.h b/daemon.h index db82ee2..7290420 100644 --- a/daemon.h +++ b/daemon.h @@ -14,6 +14,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -49,6 +50,42 @@ static inline int prependAdd(const char *command) { return 0; } +struct Line { + size_t len; + char buf[512]; +}; + +static inline char *lineFlush(struct Line *line) { + if (!line->len) return NULL; + line->buf[line->len++] = '\0'; + return line->buf; +} + +static inline char *lineRead(struct Line *line, int fd) { + char *nul = memchr(line->buf, '\0', line->len); + if (nul) { + nul++; + line->len -= nul - line->buf; + memmove(line->buf, nul, line->len); + } + + size_t cap = sizeof(line->buf) - line->len - 1; + if (!cap) return lineFlush(line); + + ssize_t len = read(fd, &line->buf[line->len], cap); + if (len < 0 && errno != EAGAIN) return NULL; + if (len > 0) line->len += len; + + char *nl = memchr(line->buf, '\n', line->len); + if (nl) { + *nl = '\0'; + return line->buf; + } else { + errno = EAGAIN; + return NULL; + } +} + enum { SHELL, PATH, @@ -70,12 +107,6 @@ enum State { Restart, }; -enum { LineCap = 512 }; -struct Line { - size_t len; - char buf[LineCap]; -}; - struct Service { char *name; char *command; -- cgit 1.4.1