summary refs log tree commit diff
diff options
context:
space:
mode:
authorC. McEnroe <june@causal.agency>2020-08-15 13:05:31 -0400
committerC. McEnroe <june@causal.agency>2020-08-15 13:05:31 -0400
commitf556af9ad5c90db94ecf01af2b50a22f6c721791 (patch)
treea609c64b296fbce484df0306abd12579a67706fc
parentGenerate tags file (diff)
downloadcatsit-f556af9ad5c90db94ecf01af2b50a22f6c721791.tar.gz
catsit-f556af9ad5c90db94ecf01af2b50a22f6c721791.zip
Implement non-blocking line-buffered reading
-rw-r--r--daemon.c18
-rw-r--r--daemon.h43
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 <http://www.gnu.org/licenses/>.
  */
 
+#include <errno.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdint.h>
@@ -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;