#include "config.h"
#include <sys/queue.h>
#include <sys/wait.h>
#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../common/common.h"
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
int
ex_shell(SCR *sp, EXCMD *cmdp)
{
int rval;
char buf[PATH_MAX];
if (opts_empty(sp, O_SHELL, 0))
return (1);
(void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
(void)sp->gp->scr_rename(sp, NULL, 0);
rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
F_SET(sp, SC_EX_WAIT_NO);
return (rval);
}
int
ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg,
int need_newline)
{
GS *gp;
const char *name;
pid_t pid;
gp = sp->gp;
if (opts_empty(sp, O_SHELL, 0))
return (1);
if (F_ISSET(sp, SC_VI)) {
if (gp->scr_screen(sp, SC_EX)) {
ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
return (1);
}
(void)gp->scr_attr(sp, SA_ALTERNATE, 0);
F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
}
if (need_newline)
(void)ex_puts(sp, "\n");
if (msg != NULL) {
(void)ex_puts(sp, msg);
(void)ex_puts(sp, "\n");
}
(void)ex_fflush(sp);
switch (pid = vfork()) {
case -1:
msgq(sp, M_SYSERR, "vfork");
return (1);
case 0:
if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
name = O_STR(sp, O_SHELL);
else
++name;
execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
_exit(127);
default:
return (proc_wait(sp, pid, cmd, 0, 0));
}
}
int
proc_wait(SCR *sp, pid_t pid, const char *cmd, int silent, int okpipe)
{
size_t len;
int nf, pstat;
char *p;
for (;;) {
errno = 0;
if (waitpid(pid, &pstat, 0) != -1)
break;
if (errno != EINTR) {
msgq(sp, M_SYSERR, "waitpid");
return (1);
}
}
if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
for (; isblank(*cmd); ++cmd);
p = msg_print(sp, cmd, &nf);
len = strlen(p);
msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
MINIMUM(len, 20), p, len > 20 ? " ..." : "",
strsignal(WTERMSIG(pstat)),
WCOREDUMP(pstat) ? "; core dumped" : "");
if (nf)
FREE_SPACE(sp, p, 0);
return (1);
}
if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
if (!silent) {
for (; isblank(*cmd); ++cmd);
p = msg_print(sp, cmd, &nf);
len = strlen(p);
msgq(sp, M_ERR, "%.*s%s: exited with status %d",
MINIMUM(len, 20), p, len > 20 ? " ..." : "",
WEXITSTATUS(pstat));
if (nf)
FREE_SPACE(sp, p, 0);
}
return (1);
}
return (0);
}