164 lines
2.6 KiB
C
164 lines
2.6 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
#include <sys/select.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/wait.h>
|
|
|
|
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;
|
|
}
|