Implement non-blocking line-buffered reading

This commit is contained in:
C. McEnroe 2020-08-15 13:05:31 -04:00
parent 3e2568aeb0
commit f556af9ad5
2 changed files with 53 additions and 8 deletions

View File

@ -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;
}
// TODO: Handle FIFO and pipes.
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 pipes.
if (timespecisset(&deadline)) {
clock_gettime(CLOCK_MONOTONIC, &now);

View File

@ -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;