#include <sys/wait.h>
#include <alloca.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <mksh/dosys.h>
#include <mksh/macro.h>
#include <mksh/misc.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ulimit.h>
#include <unistd.h>
#include <stdlib.h>
#include <libintl.h>
static Boolean exec_vp(char *name, char **argv, char **envp, Boolean ignore_error, pathpt vroot_path);
int
my_open(const char *path, int oflag, mode_t mode) {
int res = open(path, oflag, mode);
if (res < 0 && (errno == ESTALE || errno == EAGAIN)) {
res = open(path, oflag, mode);
}
return res;
}
void
redirect_io(char *stdout_file, char *stderr_file)
{
int i;
(void) closefrom(3);
if ((i = my_open(stdout_file,
O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
S_IREAD | S_IWRITE)) < 0) {
fatal_mksh(gettext("Couldn't open standard out temp file `%s': %s"),
stdout_file,
errmsg(errno));
} else {
if (dup2(i, 1) == -1) {
fatal_mksh("*** Error: dup2(3, 1) failed: %s",
errmsg(errno));
}
close(i);
}
if (stderr_file == NULL) {
if (dup2(1, 2) == -1) {
fatal_mksh("*** Error: dup2(1, 2) failed: %s",
errmsg(errno));
}
} else if ((i = my_open(stderr_file,
O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
S_IREAD | S_IWRITE)) < 0) {
fatal_mksh(gettext("Couldn't open standard error temp file `%s': %s"),
stderr_file,
errmsg(errno));
} else {
if (dup2(i, 2) == -1) {
fatal_mksh("*** Error: dup2(3, 2) failed: %s",
errmsg(errno));
}
close(i);
}
}
int
doshell(wchar_t *command, Boolean ignore_error, char *stdout_file, char *stderr_file, int nice_prio)
{
char *argv[6];
int argv_index = 0;
int cmd_argv_index;
int length;
char nice_prio_buf[MAXPATHLEN];
Name shell = getvar(shell_name);
char *shellname;
char *tmp_mbs_buffer;
if (IS_EQUAL(shell->string_mb, "")) {
shell = shell_name;
}
if ((shellname = strrchr(shell->string_mb, (int) slash_char)) == NULL) {
shellname = shell->string_mb;
} else {
shellname++;
}
if (nice_prio != 0) {
argv[argv_index++] = (char *)"nice";
(void) sprintf(nice_prio_buf, "-%d", nice_prio);
argv[argv_index++] = strdup(nice_prio_buf);
}
argv[argv_index++] = shellname;
argv[argv_index++] = (char*)(ignore_error ? "-c" : "-ce");
if ((length = wcslen(command)) >= MAXPATHLEN) {
tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
(void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
cmd_argv_index = argv_index;
argv[argv_index++] = strdup(tmp_mbs_buffer);
retmem_mb(tmp_mbs_buffer);
} else {
WCSTOMBS(mbs_buffer, command);
cmd_argv_index = argv_index;
argv[argv_index++] = strdup(mbs_buffer);
}
argv[argv_index] = NULL;
(void) fflush(stdout);
if ((childPid = fork()) == 0) {
enable_interrupt((void (*) (int)) SIG_DFL);
#if 0
if (filter_stderr) {
redirect_stderr();
}
#endif
if (nice_prio != 0) {
(void) execve("/usr/bin/nice", argv, environ);
fatal_mksh(gettext("Could not load `/usr/bin/nice': %s"),
errmsg(errno));
} else {
(void) execve(shell->string_mb, argv, environ);
fatal_mksh(gettext("Could not load Shell from `%s': %s"),
shell->string_mb,
errmsg(errno));
}
}
if (childPid == -1) {
fatal_mksh(gettext("fork failed: %s"),
errmsg(errno));
}
retmem_mb(argv[cmd_argv_index]);
return childPid;
}
static Boolean
exec_vp(char *name, char **argv, char **envp, Boolean ignore_error, pathpt vroot_path)
{
Name shell = getvar(shell_name);
char *shellname;
char *shargv[4];
Name tmp_shell;
if (IS_EQUAL(shell->string_mb, "")) {
shell = shell_name;
}
for (int i = 0; i < 5; i++) {
(void) execve_vroot(name,
argv + 1,
envp,
vroot_path,
VROOT_DEFAULT);
switch (errno) {
case ENOEXEC:
case ENOENT:
shellname = strrchr(shell->string_mb, (int) slash_char);
if (shellname == NULL) {
shellname = shell->string_mb;
} else {
shellname++;
}
shargv[0] = shellname;
shargv[1] = (char*)(ignore_error ? "-c" : "-ce");
shargv[2] = argv[0];
shargv[3] = NULL;
tmp_shell = getvar(shell_name);
if (IS_EQUAL(tmp_shell->string_mb, "")) {
tmp_shell = shell_name;
}
(void) execve_vroot(tmp_shell->string_mb,
shargv,
envp,
vroot_path,
VROOT_DEFAULT);
return failed;
case ETXTBSY:
(void) sleep((unsigned) i);
case EAGAIN:
break;
default:
return failed;
}
}
return failed;
}
int
doexec(wchar_t *command, Boolean ignore_error, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio)
{
int arg_count = 5;
char **argv;
int length;
char nice_prio_buf[MAXPATHLEN];
char **p;
wchar_t *q;
wchar_t *t;
char *tmp_mbs_buffer;
if (nice_prio != 0) {
arg_count += 2;
}
for (t = command; *t != (int) nul_char; t++) {
if (iswspace(*t)) {
arg_count++;
}
}
argv = (char **)alloca(arg_count * (sizeof(char *)));
p = &argv[1];
if ((length = wcslen(command)) >= MAXPATHLEN) {
tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
(void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
argv[0] = strdup(tmp_mbs_buffer);
retmem_mb(tmp_mbs_buffer);
} else {
WCSTOMBS(mbs_buffer, command);
argv[0] = strdup(mbs_buffer);
}
if (nice_prio != 0) {
*p++ = strdup("/usr/bin/nice");
(void) sprintf(nice_prio_buf, "-%d", nice_prio);
*p++ = strdup(nice_prio_buf);
}
for (t = command; *t;) {
if (p >= &argv[arg_count]) {
WCSTOMBS(mbs_buffer, command);
fatal_mksh(gettext("Command `%s' has more than %d arguments"),
mbs_buffer,
arg_count);
}
q = t;
while (!iswspace(*t) && (*t != (int) nul_char)) {
t++;
}
if (*t) {
for (*t++ = (int) nul_char; iswspace(*t); t++);
}
if ((length = wcslen(q)) >= MAXPATHLEN) {
tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
(void) wcstombs(tmp_mbs_buffer, q, (length * MB_LEN_MAX) + 1);
*p++ = strdup(tmp_mbs_buffer);
retmem_mb(tmp_mbs_buffer);
} else {
WCSTOMBS(mbs_buffer, q);
*p++ = strdup(mbs_buffer);
}
}
*p = NULL;
(void) fflush(stdout);
if ((childPid = fork()) == 0) {
enable_interrupt((void (*) (int)) SIG_DFL);
#if 0
if (filter_stderr) {
redirect_stderr();
}
#endif
(void) exec_vp(argv[1], argv, environ, ignore_error, vroot_path);
fatal_mksh(gettext("Cannot load command `%s': %s"), argv[1], errmsg(errno));
}
if (childPid == -1) {
fatal_mksh(gettext("fork failed: %s"),
errmsg(errno));
}
for (int i = 0; argv[i] != NULL; i++) {
retmem_mb(argv[i]);
}
return childPid;
}
Boolean
await(Boolean ignore_error, Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, void *xdrs_p, int job_msg_id)
{
int status;
char *buffer;
int core_dumped;
int exit_status;
FILE *outfp;
pid_t pid;
struct stat stat_buff;
int termination_signal;
while ((pid = wait(&status)) != running_pid) {
if (pid == -1) {
fatal_mksh(gettext("wait() failed: %s"), errmsg(errno));
}
}
(void) fflush(stdout);
(void) fflush(stderr);
if (status == 0) {
#ifdef PRINT_EXIT_STATUS
warning_mksh("I'm in await(), and status is 0.");
#endif
return succeeded;
}
#ifdef PRINT_EXIT_STATUS
warning_mksh("I'm in await(), and status is *NOT* 0.");
#endif
exit_status = WEXITSTATUS(status);
#ifdef PRINT_EXIT_STATUS
warning_mksh("I'm in await(), and exit_status is %d.", exit_status);
#endif
termination_signal = WTERMSIG(status);
core_dumped = WCOREDUMP(status);
if (!silent_error) {
if (exit_status != 0) {
(void) fprintf(stdout,
gettext("*** Error code %d"),
exit_status);
} else {
(void) fprintf(stdout,
gettext("*** Signal %d"),
termination_signal);
if (core_dumped) {
(void) fprintf(stdout,
gettext(" - core dumped"));
}
}
if (ignore_error) {
(void) fprintf(stdout,
gettext(" (ignored)"));
}
(void) fprintf(stdout, "\n");
(void) fflush(stdout);
}
#ifdef PRINT_EXIT_STATUS
warning_mksh("I'm in await(), returning failed.");
#endif
return failed;
}
void
sh_command2string(String command, String destination)
{
FILE *fd;
int chr;
int status;
Boolean command_generated_output = false;
command->text.p = NULL;
WCSTOMBS(mbs_buffer, command->buffer.start);
if ((fd = popen(mbs_buffer, "r")) == NULL) {
WCSTOMBS(mbs_buffer, command->buffer.start);
fatal_mksh(gettext("Could not run command `%s' for :sh transformation"),
mbs_buffer);
}
while ((chr = getc(fd)) != EOF) {
if (chr == (int) newline_char) {
chr = (int) space_char;
}
command_generated_output = true;
append_char(chr, destination);
}
if (command_generated_output){
if ( *(destination->text.p-1) == (int) space_char) {
* (-- destination->text.p) = '\0';
}
} else {
*(destination->text.p) = '\0';
}
status = pclose(fd);
if (status != 0) {
WCSTOMBS(mbs_buffer, command->buffer.start);
fatal_mksh(gettext("The command `%s' returned status `%d'"),
mbs_buffer,
WEXITSTATUS(status));
}
}