#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "newt.h"
#include "log.h"
#include "run.h"
#include "windows.h"
int runProgramRoot(enum runType runType, char * root, char * name,
char ** args) {
return runProgramIORoot(runType, root, name, args, NULL, NULL);
}
int runProgramIO(enum runType runType, char * name, char ** args, char * in,
char ** out) {
return runProgramIORoot(runType, NULL, name, args, in, out);
}
int runProgramIORoot(enum runType runType, char * root, char * name,
char ** args, char * in, char ** out) {
char * buf;
int infd, outfd, errfd, status, i;
int resultfd = 0;
pid_t pid;
char ** currarg;
int inputPipe[2], outputPipe[2];
char resultbuf[200];
char * result;
int resultSize;
char fullname[200];
/* if "in" is set, it better be short. We assume one write() call is
enough */
if (root) {
sprintf(fullname, "%s/%s", root, name);
} else
strcpy(fullname, name);
i = 0;
i = strlen(name) + 50;
currarg = args;
while (*currarg) {
i += strlen(*currarg) + 1;
currarg++;
}
buf = alloca(i);
if (testing)
strcpy(buf, "if I weren't testing I would run:\n\n");
else
strcpy(buf, "running: ");
strcat(buf, name);
strcat(buf, " ");
currarg = args;
while (*currarg) {
strcat(buf, *currarg);
strcat(buf, " ");
currarg++;
}
if (testing) {
newtComponent t, f, succeed, fail;
newtOpenWindow(17, 4, 45, 15, "Running");
succeed = newtButton(8, 10, "Succeed");
fail = newtButton(28, 10, "Fail");
t = newtTextbox(2, 1, 40, 13, NEWT_TEXTBOX_WRAP | NEWT_TEXTBOX_SCROLL);
newtTextboxSetText(t, buf);
f = newtForm(NULL, NULL, 0);
newtFormAddComponents(f, t, succeed, fail, NULL);
t = newtRunForm(f);
newtFormDestroy(f);
newtPopWindow();
return t == fail;
}
if (access(fullname, X_OK)) {
logMessage("cannot run %s: %s", fullname, strerror(errno));
messageWindow("Error", "I cannot run %s: %s", fullname,
strerror(errno));
return -1;
}
logMessage(buf);
if (root)
logMessage(" root is %s", root);
if (in) {
pipe(inputPipe);
write(inputPipe[1], in, strlen(in));
close(inputPipe[1]);
infd = inputPipe[0];
} else {
infd = open("/dev/null", O_RDONLY);
}
errfd = open("/dev/tty5", O_APPEND | O_CREAT);
if (errfd < 0)
errfd = open("/tmp/exec.log", O_APPEND | O_CREAT);
if (out) {
pipe(outputPipe);
outfd = outputPipe[1];
resultfd = outputPipe[0];
} else if (runType & RUN_LOG) {
outfd = open("/dev/tty5", O_RDWR);
if (outfd < 0)
outfd = open("/tmp/exec.log", O_APPEND | O_CREAT);
} else
outfd = open("/dev/null", O_RDWR);
if (!(pid = fork())) {
close(0);
close(1);
close(2);
if (root) {
chroot(root);
chdir("/");
}
dup2(infd, 0);
dup2(outfd, 1);
dup2(errfd, 2);
close(infd);
close(outfd);
close(errfd);
if (out) close(resultfd);
execv(name, args);
logMessage("exec of %s failed: %s", name, strerror(errno));
exit(-1);
}
close(infd);
close(outfd);
close(errfd);
if (out) {
resultSize = 0;
result = NULL;
do {
i = read(resultfd, resultbuf, sizeof(resultbuf));
if (!result) {
result = malloc(i + 1);
} else
result = realloc(result, resultSize + i + 1);
memcpy(result + resultSize, resultbuf, i);
resultSize += i;
result[resultSize] = '\0';
} while (i > 0);
close(resultfd);
*out = result;
}
waitpid(pid, &status, 0);
if (WIFEXITED(status))
return WEXITSTATUS(status);
return -1;
}
int runProgram(enum runType runType, char * name, char ** args) {
return runProgramIO(runType, name, args, NULL, NULL);
}