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 }