#include #include #include #include #include #include #include #include #include #include typedef struct Process Process; struct Process { pid_t pid; int fd; char str[64]; Process *next; }; static Process *list = NULL; int max(int a, int b) { return (a > b ? a : b); } Process * newproc(const char *command) { Process *p; int pipes[2]; pid_t pid; if(pipe(pipes) < 0) { perror("pipe()"); exit(EXIT_FAILURE); } switch((pid = fork())) { case -1: perror("fork()"); exit(EXIT_FAILURE); case 0: close(0); close(1); dup2(pipes[1], 1); close(pipes[0]); close(pipes[1]); execl("/bin/sh", "/bin/sh", "-c", command, NULL); exit(EXIT_SUCCESS); return NULL; default: close(pipes[1]); p = malloc(sizeof *p); if(!p) { perror("malloc()"); exit(EXIT_FAILURE); } memset(p, 0, sizeof *p); p->pid = pid; p->fd = pipes[0]; return p; } } static void sigtrap(int sig) { if(sig != SIGINT) return; for(Process *p = list; p; p = p->next) { killpg(p->pid, sig); } while(wait(NULL) != -1 || errno == EINTR); /* let the operating take care of the memory leak, fuck it */ exit(EXIT_SUCCESS); } int linerd(int fd, char *line, int linesize) { int i; for(i = 0; i < linesize; i++) { char c; if(read(fd, &c, sizeof c) <= 0) { break; } if(c == '\n') { line[i] = 0; break; } line[i] = c; } line[linesize - 1] = 0; return i; } int main(int argc, char *argv[]) { int maxfd = 0, i, c; fd_set rdset; Process *p; signal(SIGINT, sigtrap); signal(SIGTERM, sigtrap); signal(SIGKILL, sigtrap); FD_ZERO(&rdset); while((c = getopt(argc, argv, "c:")) > 0) { switch(c) { case 'c': p = newproc(optarg); FD_SET(p->fd, &rdset); maxfd = max(maxfd, p->fd); p->next = list; list = p; break; default: fprintf(stderr, "Unknown option: %c\n", c); exit(EXIT_FAILURE); } } if(!list) { fprintf(stderr, "usage: %s -c command [-c command2 ]...\n", argv[0]); exit(EXIT_FAILURE); } for(;;) { int n; fd_set copy; FD_ZERO(©); memcpy(©, &rdset, sizeof rdset); n = select(maxfd + 1, ©, NULL, NULL, NULL); if(n < 0) { perror("select()"); continue; } for(Process *p = list; p; p = p->next) if(FD_ISSET(p->fd, ©)) { if(linerd(p->fd, p->str, sizeof p->str) <= 0) { FD_CLR(p->fd, &rdset); close(p->fd); } } for(Process *p = list; p; p = p->next) printf("%s%s", p->str, p->next ? " | " : ""); printf("\n"); fflush(stdout); } return 0; }