infobar

Unixy status monitor
git clone git://wolog.xyz/infobar
Log | Files | Refs | README | LICENSE

fifolog.c (2515B)


      1 /*
      2  * Copyright (C) Raymond Cole <rc@wolog.xyz>
      3  * License: GPL-3.0-or-later
      4  */
      5 #include <errno.h>
      6 #include <fcntl.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <poll.h>
     11 #include <unistd.h>
     12 
     13 #include "util.h"
     14 
     15 static size_t
     16 getlines(char **linesptr, size_t *siz, int fd)
     17 {
     18 	char *lines = *linesptr;
     19 	size_t len = 0;
     20 	char buf[256];
     21 	ssize_t n;
     22 	struct pollfd fds[1];
     23 
     24 	while ((n = read(fd, buf, sizeof(buf))) != 0) {
     25 		if (n < 0) {
     26 			if (errno != EAGAIN)
     27 				die("read:");
     28 		} else {
     29 			if (len + n >= *siz && !(lines = realloc(lines, len + n + 1)))
     30 				die("realloc:");
     31 			memcpy(lines + len, buf, n);
     32 			lines[len += n] = '\0';
     33 			if (lines[len - 1] == '\n')
     34 				break;
     35 		}
     36 		fds->fd = fd;
     37 		fds->events = POLLIN;
     38 		while (poll(fds, 1, 1000) < 0)
     39 			;
     40 	}
     41 	*linesptr = lines;
     42 	return len;
     43 }
     44 
     45 int
     46 main(int argc, char **argv)
     47 {
     48 	char **fns, **bns;
     49 	struct pollfd *fds;
     50 	int nfds;
     51 	char *p, *q;
     52 	int i, ready;
     53 	char *lines = NULL;
     54 	size_t siz = 0;
     55 
     56 	progname = argv[0];
     57 	nfds = argc > 1 ? argc - 1 : 1;
     58 	if (!(fns = malloc(nfds * sizeof(*fns)))
     59 	 || !(bns = malloc(nfds * sizeof(*bns)))
     60 	 || !(fds = malloc(nfds * sizeof(*fds))))
     61 		die("malloc:");
     62 	if (argc < 2)
     63 		fns[0] = "-";
     64 	else
     65 		for (i = 1; i < argc; ++i)
     66 			fns[i - 1] = argv[i];
     67 	for (i = 0; i < nfds; ++i) {
     68 		if (!strcmp(fns[i], "-")) {
     69 			fds[i].fd = 0;
     70 			if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
     71 				die("fcntl:");
     72 			bns[i] = fns[i];
     73 		} else {
     74 			if ((fds[i].fd = open(fns[i], O_RDONLY|O_NONBLOCK)) < 0)
     75 				die("open `%s':", fns[i]);
     76 			bns[i] = (p = strrchr(fns[i], '/')) ? p + 1 : fns[i];
     77 		}
     78 		fds[i].events = POLLIN;
     79 	}
     80 	setvbuf(stdout, NULL, _IOLBF, 0);
     81 	for (;;) {
     82 		if ((ready = poll(fds, nfds, -1)) < 0)
     83 			die("poll:");
     84 		for (i = 0; i < nfds; ++i) {
     85 			if (fds[i].revents & (POLLNVAL|POLLERR))
     86 				die("error on pipe `%s'", bns[i]);
     87 			if (fds[i].revents & POLLIN) {
     88 				if (getlines(&lines, &siz, fds[i].fd)) {
     89 					for (p = lines; (q = strchr(p, '\n')); p = q + 1) {
     90 						*q = '\0';
     91 						printf("%s %s\n", bns[i], p);
     92 					}
     93 				} else {
     94 					fds[i].revents |= POLLHUP;
     95 				}
     96 			}
     97 			if (fds[i].revents & POLLHUP) {
     98 				if (fds[i].fd == 0)
     99 					goto done;
    100 				close(fds[i].fd);
    101 				printf("! %s\n", bns[i]);
    102 				if ((fds[i].fd = open(fns[i], O_RDONLY|O_NONBLOCK)) < 0)
    103 					die("open `%s':", fns[i]);
    104 			}
    105 			if (ferror(stdout))
    106 				die("cannot write to stdout");
    107 		}
    108 	}
    109 done:
    110 	free(lines);
    111 	for (i = 0; i < nfds; ++i)
    112 		if (fds[i].fd > 0)
    113 			close(fds[i].fd);
    114 	free(fns);
    115 	free(bns);
    116 	free(fds);
    117 	return 0;
    118 }