#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef errno
extern int errno;
#endif
extern char *strerror();
#ifdef _POSIX_VERSION
#include <sys/wait.h>
#define PID_T pid_t
#else
#define WIFEXITED(s) (((s) & 0377) == 0)
#define WIFSTOPPED(s) (((s) & 0377) == 0177)
#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
#define WEXITSTATUS(s) (((s) >> 8) & 0377)
#define WTERMSIG(s) ((s) & 0177)
#define WSTOPSIG(s) (((s) >> 8) & 0377)
#ifndef WCOREFLAG
#define WCOREFLAG 0200
#endif
#define PID_T int
#endif
#ifndef WCOREFLAG
#ifdef WCOREFLG
#define WCOREFLAG WCOREFLG
#endif
#endif
#ifndef WCOREDUMP
#ifdef WCOREFLAG
#define WCOREDUMP(s) ((s) & WCOREFLAG)
#else
#define WCOREDUMP(s) (0)
#endif
#endif
#include "pipeline.h"
#ifdef __STDC__
#define P(parms) parms
#else
#define P(parms) ()
#define const
#endif
#define error c_error
extern void error P((const char *, const char *, const char *, const char *));
extern void c_fatal P((const char *, const char *, const char *, const char *));
static void sys_fatal P((const char *));
static const char *xstrsignal P((int));
static char *itoa P((int));
int run_pipeline(ncommands, commands)
int ncommands;
char ***commands;
{
int i;
int last_input = 0;
PID_T pids[MAX_COMMANDS];
int ret = 0;
int proc_count = ncommands;
for (i = 0; i < ncommands; i++) {
int pdes[2];
PID_T pid;
if (i != ncommands - 1) {
if (pipe(pdes) < 0)
sys_fatal("pipe");
}
pid = fork();
if (pid < 0)
sys_fatal("fork");
if (pid == 0) {
if (last_input != 0) {
if (close(0) < 0)
sys_fatal("close");
if (dup(last_input) < 0)
sys_fatal("dup");
if (close(last_input) < 0)
sys_fatal("close");
}
if (i != ncommands - 1) {
if (close(1) < 0)
sys_fatal("close");
if (dup(pdes[1]) < 0)
sys_fatal("dup");
if (close(pdes[1]) < 0)
sys_fatal("close");
if (close(pdes[0]))
sys_fatal("close");
}
execvp(commands[i][0], commands[i]);
error("couldn't exec %1: %2", commands[i][0],
strerror(errno), (char *)0);
fflush(stderr);
_exit(EXEC_FAILED_EXIT_STATUS);
}
if (last_input != 0) {
if (close(last_input) < 0)
sys_fatal("close");
}
if (i != ncommands - 1) {
if (close(pdes[1]) < 0)
sys_fatal("close");
last_input = pdes[0];
}
pids[i] = pid;
}
while (proc_count > 0) {
int status;
PID_T pid = wait(&status);
if (pid < 0)
sys_fatal("wait");
for (i = 0; i < ncommands; i++)
if (pids[i] == pid) {
pids[i] = -1;
--proc_count;
if (WIFSIGNALED(status)) {
int sig = WTERMSIG(status);
#ifdef SIGPIPE
if (sig == SIGPIPE) {
if (i == ncommands - 1) {
int j;
for (j = 0; j < ncommands; j++)
if (pids[j] > 0)
(void)kill(pids[j], SIGPIPE);
}
}
else
#endif
{
error("%1: %2%3",
commands[i][0],
xstrsignal(sig),
WCOREDUMP(status) ? " (core dumped)" : "");
ret |= 2;
}
}
else if (WIFEXITED(status)) {
int exit_status = WEXITSTATUS(status);
if (exit_status == EXEC_FAILED_EXIT_STATUS)
ret |= 4;
else if (exit_status != 0)
ret |= 1;
}
else
error("unexpected status %1",
itoa(status), (char *)0, (char *)0);
break;
}
}
return ret;
}
static void sys_fatal(s)
const char *s;
{
c_fatal("%1: %2", s, strerror(errno), (char *)0);
}
static char *itoa(n)
int n;
{
static char buf[12];
sprintf(buf, "%d", n);
return buf;
}
static const char *xstrsignal(n)
int n;
{
static char buf[sizeof("Signal ") + 1 + sizeof(int)*3];
#ifdef NSIG
#ifdef SYS_SIGLIST_DECLARED
if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
return sys_siglist[n];
#endif
#endif
sprintf(buf, "Signal %d", n);
return buf;
}