ref: ba3a4b9f50ac53f5753efc115c24a250b3168cb8
dir: /driver/posix/scc.c/
/* See LICENSE file for copyright and license details. */
#define _POSIX_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../inc/arg.h"
#include "../../inc/cc.h"
#define NARGS 64
struct tool {
char cmd[FILENAME_MAX];
char *args[NARGS];
char bin[16];
char name[8];
int in, out;
pid_t pid;
};
typedef struct tool Tool;
char *argv0;
static Tool cc1 = { .name = "cc1" },
cc2 = { .name = "cc2" },
qbe = { .name = "qbe", .bin = "qbe", .cmd = "qbe" };
static char *arch;
static void
terminate(void)
{
if (cc1.pid)
kill(cc1.pid, SIGTERM);
if (cc2.pid)
kill(cc2.pid, SIGTERM);
if (qbe.pid)
kill(qbe.pid, SIGTERM);
}
Tool *
settool(Tool *tool, int pipeout)
{
char *namefmt, *cmdfmt;
int fds[2], n;
static int fdin;
if (tool != &qbe) {
n = snprintf(tool->bin, sizeof(tool->bin),
arch ? "%s-%s" : "%s", tool->name, arch);
if (n < 0 || n >= sizeof(tool->bin))
die("scc: target tool name too long");
n = snprintf(tool->cmd, sizeof(tool->cmd),
"%s/libexec/scc/%s", PREFIX, tool->bin);
if (n < 0 || n >= sizeof(tool->cmd))
die("scc: target tool path too long");
}
tool->args[0] = tool->bin;
if (fdin) {
tool->in = fdin;
fdin = 0;
}
if (pipeout) {
if (pipe(fds))
die("scc: pipe: %s", strerror(errno));
tool->out = fds[1];
fdin = fds[0];
}
return tool;
}
void
spawn(Tool *tool)
{
switch (tool->pid = fork()) {
case -1:
die("scc: %s: %s", tool->name, strerror(errno));
case 0:
if (tool->out)
dup2(tool->out, 1);
if (tool->in)
dup2(tool->in, 0);
execvp(tool->cmd, tool->args);
fprintf(stderr, "scc: execv %s: %s\n",
tool->cmd, strerror(errno));
_exit(1);
default:
if (tool->in)
close(tool->in);
if (tool->out)
close(tool->out);
break;
}
}
static void
usage(void)
{
die("usage: %s [-m arch] input ...");
}
int
main(int argc, char *argv[])
{
int st, i;
pid_t pid;
atexit(terminate);
arch = getenv("ARCH");
ARGBEGIN {
case 'm':
arch = EARGF(usage());
break;
case '-':
printf("scc: ignored parameter --%s\n", EARGF(usage()));
break;
default:
usage();
} ARGEND
if (!argc)
die("scc: fatal error: no input files");
cc1.args[1] = *argv;
spawn(settool(&cc1, 1));
if (!arch || strcmp(arch, "qbe")) {
spawn(settool(&cc2, 0));
} else {
spawn(settool(&cc2, 1));
spawn(settool(&qbe, 0));
}
for (i = 0; i < 3; ++i) {
if ((pid = wait(&st)) < 0)
break;
if (pid == cc1.pid)
cc1.pid = 0;
else if (pid == cc2.pid)
cc2.pid = 0;
else if (pid == qbe.pid)
qbe.pid = 0;
if (!WIFEXITED(st) || WEXITSTATUS(st) != 0)
exit(-1);
}
return 0;
}