infobar

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

fifolog.c (2652B)


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