version 1.11, 2020/01/16 16:07:18 |
version 1.12, 2023/08/31 06:53:28 |
|
|
#include <sys/wait.h> |
#include <sys/wait.h> |
#include <errno.h> |
#include <errno.h> |
#include <stdio.h> |
#include <stdio.h> |
|
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
#include "config.h" |
#include "config.h" |
#include "defines.h" |
#include "defines.h" |
|
|
#include "memory.h" |
#include "memory.h" |
#include "pathnames.h" |
#include "pathnames.h" |
#include "job.h" |
#include "job.h" |
|
#include "str.h" |
|
|
|
/* The following array is used to make a fast determination of which |
|
* characters are interpreted specially by the shell. If a command |
|
* contains any of these characters, it is executed by the shell, not |
|
* directly by us. */ |
|
static char meta[256]; |
|
|
|
void |
|
CmdExec_Init(void) |
|
{ |
|
char *p; |
|
|
|
for (p = "#=|^(){};&<>*?[]:$`\\\n~"; *p != '\0'; p++) |
|
meta[(unsigned char) *p] = 1; |
|
/* The null character serves as a sentinel in the string. */ |
|
meta[0] = 1; |
|
} |
|
|
|
static char ** |
|
recheck_command_for_shell(char **av) |
|
{ |
|
char *runsh[] = { |
|
"!", "alias", "cd", "eval", "exit", "read", "set", "ulimit", |
|
"unalias", "unset", "wait", "umask", NULL |
|
}; |
|
|
|
char **p; |
|
|
|
/* optimization: if exec cmd, we avoid the intermediate shell */ |
|
if (strcmp(av[0], "exec") == 0) |
|
av++; |
|
|
|
if (!av[0]) |
|
return NULL; |
|
|
|
for (p = runsh; *p; p++) |
|
if (strcmp(av[0], *p) == 0) |
|
return NULL; |
|
|
|
return av; |
|
} |
|
|
|
void |
|
run_command(const char *cmd, bool errCheck) |
|
{ |
|
const char *p; |
|
char *shargv[4]; |
|
char **todo; |
|
|
|
shargv[0] = _PATH_BSHELL; |
|
|
|
shargv[1] = errCheck ? "-ec" : "-c"; |
|
shargv[2] = (char *)cmd; |
|
shargv[3] = NULL; |
|
|
|
todo = shargv; |
|
|
|
|
|
/* Search for meta characters in the command. If there are no meta |
|
* characters, there's no need to execute a shell to execute the |
|
* command. */ |
|
for (p = cmd; !meta[(unsigned char)*p]; p++) |
|
continue; |
|
if (*p == '\0') { |
|
char *bp; |
|
char **av; |
|
int argc; |
|
/* No meta-characters, so probably no need to exec a shell. |
|
* Break the command into words to form an argument vector |
|
* we can execute. */ |
|
av = brk_string(cmd, &argc, &bp); |
|
av = recheck_command_for_shell(av); |
|
if (av != NULL) |
|
todo = av; |
|
} |
|
execvp(todo[0], todo); |
|
if (errno == ENOENT) |
|
fprintf(stderr, "%s: not found\n", todo[0]); |
|
else |
|
perror(todo[0]); |
|
_exit(1); |
|
} |
|
|
char * |
char * |
Cmd_Exec(const char *cmd, char **err) |
Cmd_Exec(const char *cmd, char **err) |
{ |
{ |
char *args[4]; /* Args for invoking the shell */ |
|
int fds[2]; /* Pipe streams */ |
int fds[2]; /* Pipe streams */ |
pid_t cpid; /* Child PID */ |
pid_t cpid; /* Child PID */ |
char *result; /* Result */ |
char *result; /* Result */ |
|
|
|
|
*err = NULL; |
*err = NULL; |
|
|
/* Set up arguments for the shell. */ |
|
args[0] = "sh"; |
|
args[1] = "-c"; |
|
args[2] = (char *)cmd; |
|
args[3] = NULL; |
|
|
|
/* Open a pipe for retrieving shell's output. */ |
/* Open a pipe for retrieving shell's output. */ |
if (pipe(fds) == -1) { |
if (pipe(fds) == -1) { |
*err = "Couldn't create pipe for \"%s\""; |
*err = "Couldn't create pipe for \"%s\""; |
|
|
(void)close(fds[1]); |
(void)close(fds[1]); |
} |
} |
|
|
(void)execv(_PATH_BSHELL, args); |
run_command(cmd, false); |
_exit(1); |
|
/*NOTREACHED*/ |
/*NOTREACHED*/ |
|
|
case -1: |
case -1: |