More shell features.... if-then-else-fi is now basically usable (disable
by default pending further debugging). Added in some basic shell environment support (i.e. $?, $0-$9, $$, $!, $#). -Erik
This commit is contained in:
parent
7ce41ad692
commit
6a99aaf020
352
lash.c
352
lash.c
@ -26,9 +26,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
//#define BB_FEATURE_SH_BACKTICKS
|
||||||
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
//#define BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -57,14 +57,12 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
||||||
static const unsigned int IF_EXP_CONTEXT=0x2;
|
static const unsigned int IF_TRUE_CONTEXT=0x2;
|
||||||
static const unsigned int THEN_EXP_CONTEXT=0x4;
|
static const unsigned int IF_FALSE_CONTEXT=0x4;
|
||||||
static const unsigned int ELSE_EXP_CONTEXT=0x8;
|
static const unsigned int THEN_EXP_CONTEXT=0x8;
|
||||||
|
static const unsigned int ELSE_EXP_CONTEXT=0x10;
|
||||||
|
|
||||||
|
|
||||||
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
|||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
static void checkJobs(struct jobSet *jobList);
|
static void checkJobs(struct jobSet *jobList);
|
||||||
static int getCommand(FILE * source, char *command);
|
static int getCommand(FILE * source, char *command);
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
|
||||||
static int setupRedirections(struct childProgram *prog);
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
||||||
static int busy_loop(FILE * input);
|
static int busy_loop(FILE * input);
|
||||||
|
|
||||||
@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
|
|||||||
{"export", "Set environment variable", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
{"if", NULL, builtin_if},
|
||||||
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
|
|||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
|
||||||
{"if", NULL, builtin_if},
|
|
||||||
{"then", NULL, builtin_then},
|
|
||||||
{"else", NULL, builtin_else},
|
|
||||||
{"fi", NULL, builtin_fi},
|
|
||||||
#endif
|
|
||||||
{".", "Source-in and run commands in a file", builtin_source},
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
{"help", "List shell built-in commands", builtin_help},
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
@ -170,6 +167,13 @@ static char *cwd;
|
|||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
static char *promptStr = NULL;
|
static char *promptStr = NULL;
|
||||||
static struct jobSet jobList = { NULL, NULL };
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
static int argc;
|
||||||
|
static char **argv;
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
static int lastBgPid=-1;
|
||||||
|
static int lastReturnCode=-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
|
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
/* Built-in handler for 'if' commands */
|
/* Built-in handler for 'if' commands */
|
||||||
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
static int builtin_if(struct job *cmd, struct jobSet *jobList)
|
||||||
{
|
{
|
||||||
cmd->jobContext |= IF_EXP_CONTEXT;
|
int status;
|
||||||
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'if' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'if' now running '%s'\n", charptr1);
|
||||||
|
status = busy_loop(NULL); /* Frees local_pending_command */
|
||||||
|
printf("if test returned ");
|
||||||
|
if (status == 0) {
|
||||||
|
printf("TRUE\n");
|
||||||
|
cmd->jobContext |= IF_TRUE_CONTEXT;
|
||||||
|
} else {
|
||||||
|
printf("FALSE\n");
|
||||||
|
cmd->jobContext |= IF_FALSE_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'then' (part of the 'if' command) */
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
int status;
|
||||||
fprintf(stderr, "unexpected token `then'\n");
|
char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
|
||||||
fflush(stderr);
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `then'\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
/* If the if result was FALSE, skip the 'then' stuff */
|
||||||
|
if (cmd->jobContext & IF_TRUE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= THEN_EXP_CONTEXT;
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
//printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'then' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'then' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'else' (part of the 'if' command) */
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an else\n");
|
int status;
|
||||||
|
char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
|
||||||
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `else'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* If the if result was TRUE, skip the 'else' stuff */
|
||||||
|
if (cmd->jobContext & IF_FALSE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
return TRUE;
|
//printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
|
||||||
|
/* Now run the 'else' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'else' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'fi' (part of the 'if' command) */
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an fi\n");
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `fi'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* Clear out the if and then context bits */
|
||||||
|
cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
|
||||||
|
printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
|
|||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setupRedirections(struct childProgram *prog)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int openfd;
|
||||||
|
int mode = O_RDONLY;
|
||||||
|
struct redirectionSpecifier *redir = prog->redirections;
|
||||||
|
|
||||||
|
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
||||||
|
switch (redir->type) {
|
||||||
|
case REDIRECT_INPUT:
|
||||||
|
mode = O_RDONLY;
|
||||||
|
break;
|
||||||
|
case REDIRECT_OVERWRITE:
|
||||||
|
mode = O_RDWR | O_CREAT | O_TRUNC;
|
||||||
|
break;
|
||||||
|
case REDIRECT_APPEND:
|
||||||
|
mode = O_RDWR | O_CREAT | O_APPEND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
openfd = open(redir->filename, mode, 0666);
|
||||||
|
if (openfd < 0) {
|
||||||
|
/* this could get lost if stderr has been redirected, but
|
||||||
|
bash and ash both lose it as well (though zsh doesn't!) */
|
||||||
|
errorMsg("error opening %s: %s\n", redir->filename,
|
||||||
|
strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openfd != redir->fd) {
|
||||||
|
dup2(openfd, redir->fd);
|
||||||
|
close(openfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int getCommand(FILE * source, char *command)
|
static int getCommand(FILE * source, char *command)
|
||||||
{
|
{
|
||||||
if (source == NULL) {
|
if (source == NULL) {
|
||||||
@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
#define __MAX_INT_CHARS 7
|
||||||
|
static char* itoa(register int i)
|
||||||
|
{
|
||||||
|
static char a[__MAX_INT_CHARS];
|
||||||
|
register char *b = a + sizeof(a) - 1;
|
||||||
|
int sign = (i < 0);
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
i = -i;
|
||||||
|
*b = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*--b = '0' + (i % 10);
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
if (sign)
|
||||||
|
*--b = '-';
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
||||||
int *argcAllocedPtr)
|
int *argcAllocedPtr)
|
||||||
{
|
{
|
||||||
int argc = *argcPtr;
|
int argc_l = *argcPtr;
|
||||||
int argcAlloced = *argcAllocedPtr;
|
int argcAlloced = *argcAllocedPtr;
|
||||||
int rc;
|
int rc;
|
||||||
int flags;
|
int flags;
|
||||||
int i;
|
int i;
|
||||||
char *src, *dst, *var;
|
char *src, *dst, *var;
|
||||||
|
|
||||||
if (argc > 1) { /* cmd->globResult is already initialized */
|
if (argc_l > 1) { /* cmd->globResult is already initialized */
|
||||||
flags = GLOB_APPEND;
|
flags = GLOB_APPEND;
|
||||||
i = prog->globResult.gl_pathc;
|
i = prog->globResult.gl_pathc;
|
||||||
} else {
|
} else {
|
||||||
@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
/* do shell variable substitution */
|
/* do shell variable substitution */
|
||||||
if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1)))
|
if(*prog->argv[argc_l - 1] == '$') {
|
||||||
prog->argv[argc - 1] = var;
|
if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
|
||||||
|
prog->argv[argc_l - 1] = var;
|
||||||
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
else {
|
||||||
|
switch(*(prog->argv[argc_l - 1] + 1)) {
|
||||||
|
case '?':
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastReturnCode);
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
prog->argv[argc_l - 1] = itoa(getpid());
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
prog->argv[argc_l - 1] = itoa(argc-1);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
if (lastBgPid==-1)
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
else
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastBgPid);
|
||||||
|
break;
|
||||||
|
case '0':case '1':case '2':case '3':case '4':
|
||||||
|
case '5':case '6':case '7':case '8':case '9':
|
||||||
|
{
|
||||||
|
int index=*(prog->argv[argc_l - 1] + 1)-48;
|
||||||
|
if (index >= argc) {
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
} else {
|
||||||
|
prog->argv[argc_l - 1] = argv[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
|
rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
|
||||||
if (rc == GLOB_NOSPACE) {
|
if (rc == GLOB_NOSPACE) {
|
||||||
errorMsg("out of space during glob operation\n");
|
errorMsg("out of space during glob operation\n");
|
||||||
return;
|
return;
|
||||||
} else if (rc == GLOB_NOMATCH ||
|
} else if (rc == GLOB_NOMATCH ||
|
||||||
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
||||||
strcmp(prog->argv[argc - 1],
|
strcmp(prog->argv[argc_l - 1],
|
||||||
prog->globResult.gl_pathv[i]) == 0)) {
|
prog->globResult.gl_pathv[i]) == 0)) {
|
||||||
/* we need to remove whatever \ quoting is still present */
|
/* we need to remove whatever \ quoting is still present */
|
||||||
src = dst = prog->argv[argc - 1];
|
src = dst = prog->argv[argc_l - 1];
|
||||||
while (*src) {
|
while (*src) {
|
||||||
if (*src != '\\')
|
if (*src != '\\')
|
||||||
*dst++ = *src;
|
*dst++ = *src;
|
||||||
@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
argcAlloced += (prog->globResult.gl_pathc - i);
|
argcAlloced += (prog->globResult.gl_pathc - i);
|
||||||
prog->argv =
|
prog->argv =
|
||||||
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
||||||
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
|
memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
|
||||||
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
||||||
argc += (prog->globResult.gl_pathc - i - 1);
|
argc_l += (prog->globResult.gl_pathc - i - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
*argcAllocedPtr = argcAlloced;
|
*argcAllocedPtr = argcAlloced;
|
||||||
*argcPtr = argc;
|
*argcPtr = argc_l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
||||||
@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
the beginning of the next command (if the original command had more
|
the beginning of the next command (if the original command had more
|
||||||
then one job associated with it) or NULL if no more commands are
|
then one job associated with it) or NULL if no more commands are
|
||||||
present. */
|
present. */
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *returnCommand = NULL;
|
char *returnCommand = NULL;
|
||||||
char *src, *buf, *chptr;
|
char *src, *buf, *chptr;
|
||||||
int argc = 0;
|
int argc_l = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
int argvAlloced;
|
int argvAlloced;
|
||||||
int i;
|
int i;
|
||||||
@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*isBg = 0;
|
*inBg = 0;
|
||||||
job->numProgs = 1;
|
job->numProgs = 1;
|
||||||
job->progs = xmalloc(sizeof(*job->progs));
|
job->progs = xmalloc(sizeof(*job->progs));
|
||||||
|
|
||||||
@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
job->jobContext = REGULAR_JOB_CONTEXT;
|
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*src == ']') *buf++ = '\\';
|
*src == ']') *buf++ = '\\';
|
||||||
*buf++ = *src;
|
*buf++ = *src;
|
||||||
} else if (isspace(*src)) {
|
} else if (isspace(*src)) {
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
/* +1 here leaves room for the NULL which ends argv */
|
/* +1 here leaves room for the NULL which ends argv */
|
||||||
if ((argc + 1) == argvAlloced) {
|
if ((argc_l + 1) == argvAlloced) {
|
||||||
argvAlloced += 5;
|
argvAlloced += 5;
|
||||||
prog->argv = realloc(prog->argv,
|
prog->argv = realloc(prog->argv,
|
||||||
sizeof(*prog->argv) *
|
sizeof(*prog->argv) *
|
||||||
argvAlloced);
|
argvAlloced);
|
||||||
}
|
}
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
switch (*src) {
|
switch (*src) {
|
||||||
@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '#': /* comment */
|
case '#': /* comment */
|
||||||
done = 1;
|
if (*(src-1)== '$')
|
||||||
|
*buf++ = *src;
|
||||||
|
else
|
||||||
|
done = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '>': /* redirections */
|
case '>': /* redirections */
|
||||||
@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
(i + 1));
|
(i + 1));
|
||||||
|
|
||||||
prog->redirections[i].fd = -1;
|
prog->redirections[i].fd = -1;
|
||||||
if (buf != prog->argv[argc]) {
|
if (buf != prog->argv[argc_l]) {
|
||||||
/* the stuff before this character may be the file number
|
/* the stuff before this character may be the file number
|
||||||
being redirected */
|
being redirected */
|
||||||
prog->redirections[i].fd =
|
prog->redirections[i].fd =
|
||||||
strtol(prog->argv[argc], &chptr, 10);
|
strtol(prog->argv[argc_l], &chptr, 10);
|
||||||
|
|
||||||
if (*chptr && *prog->argv[argc]) {
|
if (*chptr && *prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*buf++ = *chptr++;
|
*buf++ = *chptr++;
|
||||||
|
|
||||||
src = chptr - 1; /* we src++ later */
|
src = chptr - 1; /* we src++ later */
|
||||||
prog->argv[argc] = ++buf;
|
prog->argv[argc_l] = ++buf;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '|': /* pipe */
|
case '|': /* pipe */
|
||||||
/* finish this command */
|
/* finish this command */
|
||||||
if (*prog->argv[argc])
|
if (*prog->argv[argc_l])
|
||||||
argc++;
|
argc_l++;
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
errorMsg("empty command in pipe\n");
|
errorMsg("empty command in pipe\n");
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
job->numProgs=0;
|
job->numProgs=0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
/* and start the next */
|
/* and start the next */
|
||||||
job->numProgs++;
|
job->numProgs++;
|
||||||
@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
prog->redirections = NULL;
|
prog->redirections = NULL;
|
||||||
prog->freeGlob = 0;
|
prog->freeGlob = 0;
|
||||||
argc = 0;
|
argc_l = 0;
|
||||||
|
|
||||||
argvAlloced = 5;
|
argvAlloced = 5;
|
||||||
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
||||||
@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '&': /* background */
|
case '&': /* background */
|
||||||
*isBg = 1;
|
*inBg = 1;
|
||||||
case ';': /* multiple commands */
|
case ';': /* multiple commands */
|
||||||
done = 1;
|
done = 1;
|
||||||
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
||||||
@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
snprintf(charptr1, 1+ptr-src, src);
|
snprintf(charptr1, 1+ptr-src, src);
|
||||||
newJob = xmalloc(sizeof(struct job));
|
newJob = xmalloc(sizeof(struct job));
|
||||||
/* Now parse and run the backticked command */
|
/* Now parse and run the backticked command */
|
||||||
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
|
if (!parseCommand(&charptr1, newJob, &njobList, inBg)
|
||||||
&& newJob->numProgs) {
|
&& newJob->numProgs) {
|
||||||
pipe(pipefd);
|
pipe(pipefd);
|
||||||
runCommand(newJob, &njobList, 0, pipefd);
|
runCommand(newJob, &njobList, 0, pipefd);
|
||||||
@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
* and improved version of the command line with the backtick
|
* and improved version of the command line with the backtick
|
||||||
* results expanded in place... */
|
* results expanded in place... */
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return(parseCommand(commandPtr, job, jobList, isBg));
|
return(parseCommand(commandPtr, job, jobList, inBg));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif // BB_FEATURE_SH_BACKTICKS
|
#endif // BB_FEATURE_SH_BACKTICKS
|
||||||
@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
argc++;
|
argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
}
|
}
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
if (!returnCommand) {
|
if (!returnCommand) {
|
||||||
job->text = xmalloc(strlen(*commandPtr) + 1);
|
job->text = xmalloc(strlen(*commandPtr) + 1);
|
||||||
@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
* works, but '/bin/cat' doesn't ) */
|
* works, but '/bin/cat' doesn't ) */
|
||||||
while (a->name != 0) {
|
while (a->name != 0) {
|
||||||
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
||||||
int argc;
|
int argc_l;
|
||||||
char** argv=newJob->progs[i].argv;
|
char** argv=newJob->progs[i].argv;
|
||||||
for(argc=0;*argv!=NULL; argv++, argc++);
|
for(argc_l=0;*argv!=NULL; argv++, argc_l++);
|
||||||
exit((*(a->main)) (argc, newJob->progs[i].argv));
|
exit((*(a->main)) (argc_l, newJob->progs[i].argv));
|
||||||
}
|
}
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
||||||
fatalError("sh: %s: %s\n", newJob->progs[i].argv[0],
|
fatalError("%s: %s\n", newJob->progs[i].argv[0],
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
if (outPipe[1]!=-1) {
|
if (outPipe[1]!=-1) {
|
||||||
@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
to the list of backgrounded theJobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", theJob->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = theJob;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setupRedirections(struct childProgram *prog)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int openfd;
|
|
||||||
int mode = O_RDONLY;
|
|
||||||
struct redirectionSpecifier *redir = prog->redirections;
|
|
||||||
|
|
||||||
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
|
||||||
switch (redir->type) {
|
|
||||||
case REDIRECT_INPUT:
|
|
||||||
mode = O_RDONLY;
|
|
||||||
break;
|
|
||||||
case REDIRECT_OVERWRITE:
|
|
||||||
mode = O_RDWR | O_CREAT | O_TRUNC;
|
|
||||||
break;
|
|
||||||
case REDIRECT_APPEND:
|
|
||||||
mode = O_RDWR | O_CREAT | O_APPEND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
openfd = open(redir->filename, mode, 0666);
|
|
||||||
if (openfd < 0) {
|
|
||||||
/* this could get lost if stderr has been redirected, but
|
|
||||||
bash and ash both lose it as well (though zsh doesn't!) */
|
|
||||||
errorMsg("error opening %s: %s\n", redir->filename,
|
|
||||||
strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openfd != redir->fd) {
|
|
||||||
dup2(openfd, redir->fd);
|
|
||||||
close(openfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int busy_loop(FILE * input)
|
static int busy_loop(FILE * input)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
|
|||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
int status;
|
|
||||||
int inBg;
|
int inBg;
|
||||||
|
int status;
|
||||||
|
newJob.jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
/* save current owner of TTY so we can restore it on exit */
|
/* save current owner of TTY so we can restore it on exit */
|
||||||
parent_pgrp = tcgetpgrp(0);
|
parent_pgrp = tcgetpgrp(0);
|
||||||
@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
|
|||||||
removeJob(&jobList, jobList.fg);
|
removeJob(&jobList, jobList.fg);
|
||||||
jobList.fg = NULL;
|
jobList.fg = NULL;
|
||||||
}
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastReturnCode=WEXITSTATUS(status);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* the child was stopped */
|
/* the child was stopped */
|
||||||
jobList.fg->stoppedProgs++;
|
jobList.fg->stoppedProgs++;
|
||||||
@ -1211,9 +1335,11 @@ void free_memory(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc_l, char **argv_l)
|
||||||
{
|
{
|
||||||
FILE *input = stdin;
|
FILE *input = stdin;
|
||||||
|
argc = argc_l;
|
||||||
|
argv = argv_l;
|
||||||
|
|
||||||
/* initialize the cwd -- this is never freed...*/
|
/* initialize the cwd -- this is never freed...*/
|
||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
|
352
sh.c
352
sh.c
@ -26,9 +26,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
//#define BB_FEATURE_SH_BACKTICKS
|
||||||
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
//#define BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -57,14 +57,12 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
||||||
static const unsigned int IF_EXP_CONTEXT=0x2;
|
static const unsigned int IF_TRUE_CONTEXT=0x2;
|
||||||
static const unsigned int THEN_EXP_CONTEXT=0x4;
|
static const unsigned int IF_FALSE_CONTEXT=0x4;
|
||||||
static const unsigned int ELSE_EXP_CONTEXT=0x8;
|
static const unsigned int THEN_EXP_CONTEXT=0x8;
|
||||||
|
static const unsigned int ELSE_EXP_CONTEXT=0x10;
|
||||||
|
|
||||||
|
|
||||||
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
|||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
static void checkJobs(struct jobSet *jobList);
|
static void checkJobs(struct jobSet *jobList);
|
||||||
static int getCommand(FILE * source, char *command);
|
static int getCommand(FILE * source, char *command);
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
|
||||||
static int setupRedirections(struct childProgram *prog);
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
||||||
static int busy_loop(FILE * input);
|
static int busy_loop(FILE * input);
|
||||||
|
|
||||||
@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
|
|||||||
{"export", "Set environment variable", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
{"if", NULL, builtin_if},
|
||||||
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
|
|||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
|
||||||
{"if", NULL, builtin_if},
|
|
||||||
{"then", NULL, builtin_then},
|
|
||||||
{"else", NULL, builtin_else},
|
|
||||||
{"fi", NULL, builtin_fi},
|
|
||||||
#endif
|
|
||||||
{".", "Source-in and run commands in a file", builtin_source},
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
{"help", "List shell built-in commands", builtin_help},
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
@ -170,6 +167,13 @@ static char *cwd;
|
|||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
static char *promptStr = NULL;
|
static char *promptStr = NULL;
|
||||||
static struct jobSet jobList = { NULL, NULL };
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
static int argc;
|
||||||
|
static char **argv;
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
static int lastBgPid=-1;
|
||||||
|
static int lastReturnCode=-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
|
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
/* Built-in handler for 'if' commands */
|
/* Built-in handler for 'if' commands */
|
||||||
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
static int builtin_if(struct job *cmd, struct jobSet *jobList)
|
||||||
{
|
{
|
||||||
cmd->jobContext |= IF_EXP_CONTEXT;
|
int status;
|
||||||
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'if' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'if' now running '%s'\n", charptr1);
|
||||||
|
status = busy_loop(NULL); /* Frees local_pending_command */
|
||||||
|
printf("if test returned ");
|
||||||
|
if (status == 0) {
|
||||||
|
printf("TRUE\n");
|
||||||
|
cmd->jobContext |= IF_TRUE_CONTEXT;
|
||||||
|
} else {
|
||||||
|
printf("FALSE\n");
|
||||||
|
cmd->jobContext |= IF_FALSE_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'then' (part of the 'if' command) */
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
int status;
|
||||||
fprintf(stderr, "unexpected token `then'\n");
|
char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
|
||||||
fflush(stderr);
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `then'\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
/* If the if result was FALSE, skip the 'then' stuff */
|
||||||
|
if (cmd->jobContext & IF_TRUE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= THEN_EXP_CONTEXT;
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
//printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'then' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'then' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'else' (part of the 'if' command) */
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an else\n");
|
int status;
|
||||||
|
char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
|
||||||
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `else'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* If the if result was TRUE, skip the 'else' stuff */
|
||||||
|
if (cmd->jobContext & IF_FALSE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
return TRUE;
|
//printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
|
||||||
|
/* Now run the 'else' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'else' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'fi' (part of the 'if' command) */
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an fi\n");
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `fi'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* Clear out the if and then context bits */
|
||||||
|
cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
|
||||||
|
printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
|
|||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setupRedirections(struct childProgram *prog)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int openfd;
|
||||||
|
int mode = O_RDONLY;
|
||||||
|
struct redirectionSpecifier *redir = prog->redirections;
|
||||||
|
|
||||||
|
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
||||||
|
switch (redir->type) {
|
||||||
|
case REDIRECT_INPUT:
|
||||||
|
mode = O_RDONLY;
|
||||||
|
break;
|
||||||
|
case REDIRECT_OVERWRITE:
|
||||||
|
mode = O_RDWR | O_CREAT | O_TRUNC;
|
||||||
|
break;
|
||||||
|
case REDIRECT_APPEND:
|
||||||
|
mode = O_RDWR | O_CREAT | O_APPEND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
openfd = open(redir->filename, mode, 0666);
|
||||||
|
if (openfd < 0) {
|
||||||
|
/* this could get lost if stderr has been redirected, but
|
||||||
|
bash and ash both lose it as well (though zsh doesn't!) */
|
||||||
|
errorMsg("error opening %s: %s\n", redir->filename,
|
||||||
|
strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openfd != redir->fd) {
|
||||||
|
dup2(openfd, redir->fd);
|
||||||
|
close(openfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int getCommand(FILE * source, char *command)
|
static int getCommand(FILE * source, char *command)
|
||||||
{
|
{
|
||||||
if (source == NULL) {
|
if (source == NULL) {
|
||||||
@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
#define __MAX_INT_CHARS 7
|
||||||
|
static char* itoa(register int i)
|
||||||
|
{
|
||||||
|
static char a[__MAX_INT_CHARS];
|
||||||
|
register char *b = a + sizeof(a) - 1;
|
||||||
|
int sign = (i < 0);
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
i = -i;
|
||||||
|
*b = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*--b = '0' + (i % 10);
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
if (sign)
|
||||||
|
*--b = '-';
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
||||||
int *argcAllocedPtr)
|
int *argcAllocedPtr)
|
||||||
{
|
{
|
||||||
int argc = *argcPtr;
|
int argc_l = *argcPtr;
|
||||||
int argcAlloced = *argcAllocedPtr;
|
int argcAlloced = *argcAllocedPtr;
|
||||||
int rc;
|
int rc;
|
||||||
int flags;
|
int flags;
|
||||||
int i;
|
int i;
|
||||||
char *src, *dst, *var;
|
char *src, *dst, *var;
|
||||||
|
|
||||||
if (argc > 1) { /* cmd->globResult is already initialized */
|
if (argc_l > 1) { /* cmd->globResult is already initialized */
|
||||||
flags = GLOB_APPEND;
|
flags = GLOB_APPEND;
|
||||||
i = prog->globResult.gl_pathc;
|
i = prog->globResult.gl_pathc;
|
||||||
} else {
|
} else {
|
||||||
@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
/* do shell variable substitution */
|
/* do shell variable substitution */
|
||||||
if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1)))
|
if(*prog->argv[argc_l - 1] == '$') {
|
||||||
prog->argv[argc - 1] = var;
|
if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
|
||||||
|
prog->argv[argc_l - 1] = var;
|
||||||
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
else {
|
||||||
|
switch(*(prog->argv[argc_l - 1] + 1)) {
|
||||||
|
case '?':
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastReturnCode);
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
prog->argv[argc_l - 1] = itoa(getpid());
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
prog->argv[argc_l - 1] = itoa(argc-1);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
if (lastBgPid==-1)
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
else
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastBgPid);
|
||||||
|
break;
|
||||||
|
case '0':case '1':case '2':case '3':case '4':
|
||||||
|
case '5':case '6':case '7':case '8':case '9':
|
||||||
|
{
|
||||||
|
int index=*(prog->argv[argc_l - 1] + 1)-48;
|
||||||
|
if (index >= argc) {
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
} else {
|
||||||
|
prog->argv[argc_l - 1] = argv[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
|
rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
|
||||||
if (rc == GLOB_NOSPACE) {
|
if (rc == GLOB_NOSPACE) {
|
||||||
errorMsg("out of space during glob operation\n");
|
errorMsg("out of space during glob operation\n");
|
||||||
return;
|
return;
|
||||||
} else if (rc == GLOB_NOMATCH ||
|
} else if (rc == GLOB_NOMATCH ||
|
||||||
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
||||||
strcmp(prog->argv[argc - 1],
|
strcmp(prog->argv[argc_l - 1],
|
||||||
prog->globResult.gl_pathv[i]) == 0)) {
|
prog->globResult.gl_pathv[i]) == 0)) {
|
||||||
/* we need to remove whatever \ quoting is still present */
|
/* we need to remove whatever \ quoting is still present */
|
||||||
src = dst = prog->argv[argc - 1];
|
src = dst = prog->argv[argc_l - 1];
|
||||||
while (*src) {
|
while (*src) {
|
||||||
if (*src != '\\')
|
if (*src != '\\')
|
||||||
*dst++ = *src;
|
*dst++ = *src;
|
||||||
@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
argcAlloced += (prog->globResult.gl_pathc - i);
|
argcAlloced += (prog->globResult.gl_pathc - i);
|
||||||
prog->argv =
|
prog->argv =
|
||||||
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
||||||
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
|
memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
|
||||||
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
||||||
argc += (prog->globResult.gl_pathc - i - 1);
|
argc_l += (prog->globResult.gl_pathc - i - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
*argcAllocedPtr = argcAlloced;
|
*argcAllocedPtr = argcAlloced;
|
||||||
*argcPtr = argc;
|
*argcPtr = argc_l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
||||||
@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
the beginning of the next command (if the original command had more
|
the beginning of the next command (if the original command had more
|
||||||
then one job associated with it) or NULL if no more commands are
|
then one job associated with it) or NULL if no more commands are
|
||||||
present. */
|
present. */
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *returnCommand = NULL;
|
char *returnCommand = NULL;
|
||||||
char *src, *buf, *chptr;
|
char *src, *buf, *chptr;
|
||||||
int argc = 0;
|
int argc_l = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
int argvAlloced;
|
int argvAlloced;
|
||||||
int i;
|
int i;
|
||||||
@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*isBg = 0;
|
*inBg = 0;
|
||||||
job->numProgs = 1;
|
job->numProgs = 1;
|
||||||
job->progs = xmalloc(sizeof(*job->progs));
|
job->progs = xmalloc(sizeof(*job->progs));
|
||||||
|
|
||||||
@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
job->jobContext = REGULAR_JOB_CONTEXT;
|
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*src == ']') *buf++ = '\\';
|
*src == ']') *buf++ = '\\';
|
||||||
*buf++ = *src;
|
*buf++ = *src;
|
||||||
} else if (isspace(*src)) {
|
} else if (isspace(*src)) {
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
/* +1 here leaves room for the NULL which ends argv */
|
/* +1 here leaves room for the NULL which ends argv */
|
||||||
if ((argc + 1) == argvAlloced) {
|
if ((argc_l + 1) == argvAlloced) {
|
||||||
argvAlloced += 5;
|
argvAlloced += 5;
|
||||||
prog->argv = realloc(prog->argv,
|
prog->argv = realloc(prog->argv,
|
||||||
sizeof(*prog->argv) *
|
sizeof(*prog->argv) *
|
||||||
argvAlloced);
|
argvAlloced);
|
||||||
}
|
}
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
switch (*src) {
|
switch (*src) {
|
||||||
@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '#': /* comment */
|
case '#': /* comment */
|
||||||
done = 1;
|
if (*(src-1)== '$')
|
||||||
|
*buf++ = *src;
|
||||||
|
else
|
||||||
|
done = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '>': /* redirections */
|
case '>': /* redirections */
|
||||||
@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
(i + 1));
|
(i + 1));
|
||||||
|
|
||||||
prog->redirections[i].fd = -1;
|
prog->redirections[i].fd = -1;
|
||||||
if (buf != prog->argv[argc]) {
|
if (buf != prog->argv[argc_l]) {
|
||||||
/* the stuff before this character may be the file number
|
/* the stuff before this character may be the file number
|
||||||
being redirected */
|
being redirected */
|
||||||
prog->redirections[i].fd =
|
prog->redirections[i].fd =
|
||||||
strtol(prog->argv[argc], &chptr, 10);
|
strtol(prog->argv[argc_l], &chptr, 10);
|
||||||
|
|
||||||
if (*chptr && *prog->argv[argc]) {
|
if (*chptr && *prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*buf++ = *chptr++;
|
*buf++ = *chptr++;
|
||||||
|
|
||||||
src = chptr - 1; /* we src++ later */
|
src = chptr - 1; /* we src++ later */
|
||||||
prog->argv[argc] = ++buf;
|
prog->argv[argc_l] = ++buf;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '|': /* pipe */
|
case '|': /* pipe */
|
||||||
/* finish this command */
|
/* finish this command */
|
||||||
if (*prog->argv[argc])
|
if (*prog->argv[argc_l])
|
||||||
argc++;
|
argc_l++;
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
errorMsg("empty command in pipe\n");
|
errorMsg("empty command in pipe\n");
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
job->numProgs=0;
|
job->numProgs=0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
/* and start the next */
|
/* and start the next */
|
||||||
job->numProgs++;
|
job->numProgs++;
|
||||||
@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
prog->redirections = NULL;
|
prog->redirections = NULL;
|
||||||
prog->freeGlob = 0;
|
prog->freeGlob = 0;
|
||||||
argc = 0;
|
argc_l = 0;
|
||||||
|
|
||||||
argvAlloced = 5;
|
argvAlloced = 5;
|
||||||
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
||||||
@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '&': /* background */
|
case '&': /* background */
|
||||||
*isBg = 1;
|
*inBg = 1;
|
||||||
case ';': /* multiple commands */
|
case ';': /* multiple commands */
|
||||||
done = 1;
|
done = 1;
|
||||||
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
||||||
@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
snprintf(charptr1, 1+ptr-src, src);
|
snprintf(charptr1, 1+ptr-src, src);
|
||||||
newJob = xmalloc(sizeof(struct job));
|
newJob = xmalloc(sizeof(struct job));
|
||||||
/* Now parse and run the backticked command */
|
/* Now parse and run the backticked command */
|
||||||
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
|
if (!parseCommand(&charptr1, newJob, &njobList, inBg)
|
||||||
&& newJob->numProgs) {
|
&& newJob->numProgs) {
|
||||||
pipe(pipefd);
|
pipe(pipefd);
|
||||||
runCommand(newJob, &njobList, 0, pipefd);
|
runCommand(newJob, &njobList, 0, pipefd);
|
||||||
@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
* and improved version of the command line with the backtick
|
* and improved version of the command line with the backtick
|
||||||
* results expanded in place... */
|
* results expanded in place... */
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return(parseCommand(commandPtr, job, jobList, isBg));
|
return(parseCommand(commandPtr, job, jobList, inBg));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif // BB_FEATURE_SH_BACKTICKS
|
#endif // BB_FEATURE_SH_BACKTICKS
|
||||||
@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
argc++;
|
argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
}
|
}
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
if (!returnCommand) {
|
if (!returnCommand) {
|
||||||
job->text = xmalloc(strlen(*commandPtr) + 1);
|
job->text = xmalloc(strlen(*commandPtr) + 1);
|
||||||
@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
* works, but '/bin/cat' doesn't ) */
|
* works, but '/bin/cat' doesn't ) */
|
||||||
while (a->name != 0) {
|
while (a->name != 0) {
|
||||||
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
||||||
int argc;
|
int argc_l;
|
||||||
char** argv=newJob->progs[i].argv;
|
char** argv=newJob->progs[i].argv;
|
||||||
for(argc=0;*argv!=NULL; argv++, argc++);
|
for(argc_l=0;*argv!=NULL; argv++, argc_l++);
|
||||||
exit((*(a->main)) (argc, newJob->progs[i].argv));
|
exit((*(a->main)) (argc_l, newJob->progs[i].argv));
|
||||||
}
|
}
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
||||||
fatalError("sh: %s: %s\n", newJob->progs[i].argv[0],
|
fatalError("%s: %s\n", newJob->progs[i].argv[0],
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
if (outPipe[1]!=-1) {
|
if (outPipe[1]!=-1) {
|
||||||
@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
to the list of backgrounded theJobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", theJob->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = theJob;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setupRedirections(struct childProgram *prog)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int openfd;
|
|
||||||
int mode = O_RDONLY;
|
|
||||||
struct redirectionSpecifier *redir = prog->redirections;
|
|
||||||
|
|
||||||
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
|
||||||
switch (redir->type) {
|
|
||||||
case REDIRECT_INPUT:
|
|
||||||
mode = O_RDONLY;
|
|
||||||
break;
|
|
||||||
case REDIRECT_OVERWRITE:
|
|
||||||
mode = O_RDWR | O_CREAT | O_TRUNC;
|
|
||||||
break;
|
|
||||||
case REDIRECT_APPEND:
|
|
||||||
mode = O_RDWR | O_CREAT | O_APPEND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
openfd = open(redir->filename, mode, 0666);
|
|
||||||
if (openfd < 0) {
|
|
||||||
/* this could get lost if stderr has been redirected, but
|
|
||||||
bash and ash both lose it as well (though zsh doesn't!) */
|
|
||||||
errorMsg("error opening %s: %s\n", redir->filename,
|
|
||||||
strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openfd != redir->fd) {
|
|
||||||
dup2(openfd, redir->fd);
|
|
||||||
close(openfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int busy_loop(FILE * input)
|
static int busy_loop(FILE * input)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
|
|||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
int status;
|
|
||||||
int inBg;
|
int inBg;
|
||||||
|
int status;
|
||||||
|
newJob.jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
/* save current owner of TTY so we can restore it on exit */
|
/* save current owner of TTY so we can restore it on exit */
|
||||||
parent_pgrp = tcgetpgrp(0);
|
parent_pgrp = tcgetpgrp(0);
|
||||||
@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
|
|||||||
removeJob(&jobList, jobList.fg);
|
removeJob(&jobList, jobList.fg);
|
||||||
jobList.fg = NULL;
|
jobList.fg = NULL;
|
||||||
}
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastReturnCode=WEXITSTATUS(status);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* the child was stopped */
|
/* the child was stopped */
|
||||||
jobList.fg->stoppedProgs++;
|
jobList.fg->stoppedProgs++;
|
||||||
@ -1211,9 +1335,11 @@ void free_memory(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc_l, char **argv_l)
|
||||||
{
|
{
|
||||||
FILE *input = stdin;
|
FILE *input = stdin;
|
||||||
|
argc = argc_l;
|
||||||
|
argv = argv_l;
|
||||||
|
|
||||||
/* initialize the cwd -- this is never freed...*/
|
/* initialize the cwd -- this is never freed...*/
|
||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
|
352
shell/lash.c
352
shell/lash.c
@ -26,9 +26,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
//#define BB_FEATURE_SH_BACKTICKS
|
||||||
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
//#define BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -57,14 +57,12 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
static const unsigned int REGULAR_JOB_CONTEXT=0x1;
|
||||||
static const unsigned int IF_EXP_CONTEXT=0x2;
|
static const unsigned int IF_TRUE_CONTEXT=0x2;
|
||||||
static const unsigned int THEN_EXP_CONTEXT=0x4;
|
static const unsigned int IF_FALSE_CONTEXT=0x4;
|
||||||
static const unsigned int ELSE_EXP_CONTEXT=0x8;
|
static const unsigned int THEN_EXP_CONTEXT=0x8;
|
||||||
|
static const unsigned int ELSE_EXP_CONTEXT=0x10;
|
||||||
|
|
||||||
|
|
||||||
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
|||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
static void checkJobs(struct jobSet *jobList);
|
static void checkJobs(struct jobSet *jobList);
|
||||||
static int getCommand(FILE * source, char *command);
|
static int getCommand(FILE * source, char *command);
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
|
||||||
static int setupRedirections(struct childProgram *prog);
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
|
||||||
static int busy_loop(FILE * input);
|
static int busy_loop(FILE * input);
|
||||||
|
|
||||||
@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
|
|||||||
{"export", "Set environment variable", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
{"if", NULL, builtin_if},
|
||||||
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
|
|||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
|
||||||
{"if", NULL, builtin_if},
|
|
||||||
{"then", NULL, builtin_then},
|
|
||||||
{"else", NULL, builtin_else},
|
|
||||||
{"fi", NULL, builtin_fi},
|
|
||||||
#endif
|
|
||||||
{".", "Source-in and run commands in a file", builtin_source},
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
{"help", "List shell built-in commands", builtin_help},
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
@ -170,6 +167,13 @@ static char *cwd;
|
|||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
static char *promptStr = NULL;
|
static char *promptStr = NULL;
|
||||||
static struct jobSet jobList = { NULL, NULL };
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
static int argc;
|
||||||
|
static char **argv;
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
static int lastBgPid=-1;
|
||||||
|
static int lastReturnCode=-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
|
|
||||||
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
/* Built-in handler for 'if' commands */
|
/* Built-in handler for 'if' commands */
|
||||||
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
static int builtin_if(struct job *cmd, struct jobSet *jobList)
|
||||||
{
|
{
|
||||||
cmd->jobContext |= IF_EXP_CONTEXT;
|
int status;
|
||||||
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'if' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'if' now running '%s'\n", charptr1);
|
||||||
|
status = busy_loop(NULL); /* Frees local_pending_command */
|
||||||
|
printf("if test returned ");
|
||||||
|
if (status == 0) {
|
||||||
|
printf("TRUE\n");
|
||||||
|
cmd->jobContext |= IF_TRUE_CONTEXT;
|
||||||
|
} else {
|
||||||
|
printf("FALSE\n");
|
||||||
|
cmd->jobContext |= IF_FALSE_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'then' (part of the 'if' command) */
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
int status;
|
||||||
fprintf(stderr, "unexpected token `then'\n");
|
char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
|
||||||
fflush(stderr);
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `then'\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
/* If the if result was FALSE, skip the 'then' stuff */
|
||||||
|
if (cmd->jobContext & IF_TRUE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= THEN_EXP_CONTEXT;
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
//printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
|
||||||
|
/* Now run the 'then' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'then' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'else' (part of the 'if' command) */
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an else\n");
|
int status;
|
||||||
|
char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
|
||||||
|
|
||||||
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `else'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* If the if result was TRUE, skip the 'else' stuff */
|
||||||
|
if (cmd->jobContext & IF_FALSE_CONTEXT) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
return TRUE;
|
//printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
|
||||||
|
/* Now run the 'else' command */
|
||||||
|
status=strlen(charptr1);
|
||||||
|
local_pending_command = xmalloc(status+1);
|
||||||
|
strncpy(local_pending_command, charptr1, status);
|
||||||
|
printf("'else' now running '%s'\n", charptr1);
|
||||||
|
return( busy_loop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in handler for 'fi' (part of the 'if' command) */
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
printf("Hit an fi\n");
|
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
|
||||||
|
errorMsg("unexpected token `fi'\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* Clear out the if and then context bits */
|
||||||
|
cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
|
||||||
|
printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
|
|||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setupRedirections(struct childProgram *prog)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int openfd;
|
||||||
|
int mode = O_RDONLY;
|
||||||
|
struct redirectionSpecifier *redir = prog->redirections;
|
||||||
|
|
||||||
|
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
||||||
|
switch (redir->type) {
|
||||||
|
case REDIRECT_INPUT:
|
||||||
|
mode = O_RDONLY;
|
||||||
|
break;
|
||||||
|
case REDIRECT_OVERWRITE:
|
||||||
|
mode = O_RDWR | O_CREAT | O_TRUNC;
|
||||||
|
break;
|
||||||
|
case REDIRECT_APPEND:
|
||||||
|
mode = O_RDWR | O_CREAT | O_APPEND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
openfd = open(redir->filename, mode, 0666);
|
||||||
|
if (openfd < 0) {
|
||||||
|
/* this could get lost if stderr has been redirected, but
|
||||||
|
bash and ash both lose it as well (though zsh doesn't!) */
|
||||||
|
errorMsg("error opening %s: %s\n", redir->filename,
|
||||||
|
strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openfd != redir->fd) {
|
||||||
|
dup2(openfd, redir->fd);
|
||||||
|
close(openfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int getCommand(FILE * source, char *command)
|
static int getCommand(FILE * source, char *command)
|
||||||
{
|
{
|
||||||
if (source == NULL) {
|
if (source == NULL) {
|
||||||
@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
#define __MAX_INT_CHARS 7
|
||||||
|
static char* itoa(register int i)
|
||||||
|
{
|
||||||
|
static char a[__MAX_INT_CHARS];
|
||||||
|
register char *b = a + sizeof(a) - 1;
|
||||||
|
int sign = (i < 0);
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
i = -i;
|
||||||
|
*b = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*--b = '0' + (i % 10);
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
while (i);
|
||||||
|
if (sign)
|
||||||
|
*--b = '-';
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
||||||
int *argcAllocedPtr)
|
int *argcAllocedPtr)
|
||||||
{
|
{
|
||||||
int argc = *argcPtr;
|
int argc_l = *argcPtr;
|
||||||
int argcAlloced = *argcAllocedPtr;
|
int argcAlloced = *argcAllocedPtr;
|
||||||
int rc;
|
int rc;
|
||||||
int flags;
|
int flags;
|
||||||
int i;
|
int i;
|
||||||
char *src, *dst, *var;
|
char *src, *dst, *var;
|
||||||
|
|
||||||
if (argc > 1) { /* cmd->globResult is already initialized */
|
if (argc_l > 1) { /* cmd->globResult is already initialized */
|
||||||
flags = GLOB_APPEND;
|
flags = GLOB_APPEND;
|
||||||
i = prog->globResult.gl_pathc;
|
i = prog->globResult.gl_pathc;
|
||||||
} else {
|
} else {
|
||||||
@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
/* do shell variable substitution */
|
/* do shell variable substitution */
|
||||||
if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1)))
|
if(*prog->argv[argc_l - 1] == '$') {
|
||||||
prog->argv[argc - 1] = var;
|
if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
|
||||||
|
prog->argv[argc_l - 1] = var;
|
||||||
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
else {
|
||||||
|
switch(*(prog->argv[argc_l - 1] + 1)) {
|
||||||
|
case '?':
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastReturnCode);
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
prog->argv[argc_l - 1] = itoa(getpid());
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
prog->argv[argc_l - 1] = itoa(argc-1);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
if (lastBgPid==-1)
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
else
|
||||||
|
prog->argv[argc_l - 1] = itoa(lastBgPid);
|
||||||
|
break;
|
||||||
|
case '0':case '1':case '2':case '3':case '4':
|
||||||
|
case '5':case '6':case '7':case '8':case '9':
|
||||||
|
{
|
||||||
|
int index=*(prog->argv[argc_l - 1] + 1)-48;
|
||||||
|
if (index >= argc) {
|
||||||
|
*(prog->argv[argc_l - 1])='\0';
|
||||||
|
} else {
|
||||||
|
prog->argv[argc_l - 1] = argv[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
|
rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
|
||||||
if (rc == GLOB_NOSPACE) {
|
if (rc == GLOB_NOSPACE) {
|
||||||
errorMsg("out of space during glob operation\n");
|
errorMsg("out of space during glob operation\n");
|
||||||
return;
|
return;
|
||||||
} else if (rc == GLOB_NOMATCH ||
|
} else if (rc == GLOB_NOMATCH ||
|
||||||
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
|
||||||
strcmp(prog->argv[argc - 1],
|
strcmp(prog->argv[argc_l - 1],
|
||||||
prog->globResult.gl_pathv[i]) == 0)) {
|
prog->globResult.gl_pathv[i]) == 0)) {
|
||||||
/* we need to remove whatever \ quoting is still present */
|
/* we need to remove whatever \ quoting is still present */
|
||||||
src = dst = prog->argv[argc - 1];
|
src = dst = prog->argv[argc_l - 1];
|
||||||
while (*src) {
|
while (*src) {
|
||||||
if (*src != '\\')
|
if (*src != '\\')
|
||||||
*dst++ = *src;
|
*dst++ = *src;
|
||||||
@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
argcAlloced += (prog->globResult.gl_pathc - i);
|
argcAlloced += (prog->globResult.gl_pathc - i);
|
||||||
prog->argv =
|
prog->argv =
|
||||||
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
|
||||||
memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
|
memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
|
||||||
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
|
||||||
argc += (prog->globResult.gl_pathc - i - 1);
|
argc_l += (prog->globResult.gl_pathc - i - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
*argcAllocedPtr = argcAlloced;
|
*argcAllocedPtr = argcAlloced;
|
||||||
*argcPtr = argc;
|
*argcPtr = argc_l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
|
||||||
@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
|
|||||||
the beginning of the next command (if the original command had more
|
the beginning of the next command (if the original command had more
|
||||||
then one job associated with it) or NULL if no more commands are
|
then one job associated with it) or NULL if no more commands are
|
||||||
present. */
|
present. */
|
||||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
|
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *returnCommand = NULL;
|
char *returnCommand = NULL;
|
||||||
char *src, *buf, *chptr;
|
char *src, *buf, *chptr;
|
||||||
int argc = 0;
|
int argc_l = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
int argvAlloced;
|
int argvAlloced;
|
||||||
int i;
|
int i;
|
||||||
@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*isBg = 0;
|
*inBg = 0;
|
||||||
job->numProgs = 1;
|
job->numProgs = 1;
|
||||||
job->progs = xmalloc(sizeof(*job->progs));
|
job->progs = xmalloc(sizeof(*job->progs));
|
||||||
|
|
||||||
@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
job->jobContext = REGULAR_JOB_CONTEXT;
|
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*src == ']') *buf++ = '\\';
|
*src == ']') *buf++ = '\\';
|
||||||
*buf++ = *src;
|
*buf++ = *src;
|
||||||
} else if (isspace(*src)) {
|
} else if (isspace(*src)) {
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
/* +1 here leaves room for the NULL which ends argv */
|
/* +1 here leaves room for the NULL which ends argv */
|
||||||
if ((argc + 1) == argvAlloced) {
|
if ((argc_l + 1) == argvAlloced) {
|
||||||
argvAlloced += 5;
|
argvAlloced += 5;
|
||||||
prog->argv = realloc(prog->argv,
|
prog->argv = realloc(prog->argv,
|
||||||
sizeof(*prog->argv) *
|
sizeof(*prog->argv) *
|
||||||
argvAlloced);
|
argvAlloced);
|
||||||
}
|
}
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
switch (*src) {
|
switch (*src) {
|
||||||
@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '#': /* comment */
|
case '#': /* comment */
|
||||||
done = 1;
|
if (*(src-1)== '$')
|
||||||
|
*buf++ = *src;
|
||||||
|
else
|
||||||
|
done = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '>': /* redirections */
|
case '>': /* redirections */
|
||||||
@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
(i + 1));
|
(i + 1));
|
||||||
|
|
||||||
prog->redirections[i].fd = -1;
|
prog->redirections[i].fd = -1;
|
||||||
if (buf != prog->argv[argc]) {
|
if (buf != prog->argv[argc_l]) {
|
||||||
/* the stuff before this character may be the file number
|
/* the stuff before this character may be the file number
|
||||||
being redirected */
|
being redirected */
|
||||||
prog->redirections[i].fd =
|
prog->redirections[i].fd =
|
||||||
strtol(prog->argv[argc], &chptr, 10);
|
strtol(prog->argv[argc_l], &chptr, 10);
|
||||||
|
|
||||||
if (*chptr && *prog->argv[argc]) {
|
if (*chptr && *prog->argv[argc_l]) {
|
||||||
buf++, argc++;
|
buf++, argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
prog->argv[argc] = buf;
|
prog->argv[argc_l] = buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
*buf++ = *chptr++;
|
*buf++ = *chptr++;
|
||||||
|
|
||||||
src = chptr - 1; /* we src++ later */
|
src = chptr - 1; /* we src++ later */
|
||||||
prog->argv[argc] = ++buf;
|
prog->argv[argc_l] = ++buf;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '|': /* pipe */
|
case '|': /* pipe */
|
||||||
/* finish this command */
|
/* finish this command */
|
||||||
if (*prog->argv[argc])
|
if (*prog->argv[argc_l])
|
||||||
argc++;
|
argc_l++;
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
errorMsg("empty command in pipe\n");
|
errorMsg("empty command in pipe\n");
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
job->numProgs=0;
|
job->numProgs=0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
/* and start the next */
|
/* and start the next */
|
||||||
job->numProgs++;
|
job->numProgs++;
|
||||||
@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
prog->redirections = NULL;
|
prog->redirections = NULL;
|
||||||
prog->freeGlob = 0;
|
prog->freeGlob = 0;
|
||||||
argc = 0;
|
argc_l = 0;
|
||||||
|
|
||||||
argvAlloced = 5;
|
argvAlloced = 5;
|
||||||
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
|
||||||
@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '&': /* background */
|
case '&': /* background */
|
||||||
*isBg = 1;
|
*inBg = 1;
|
||||||
case ';': /* multiple commands */
|
case ';': /* multiple commands */
|
||||||
done = 1;
|
done = 1;
|
||||||
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
returnCommand = *commandPtr + (src - *commandPtr) + 1;
|
||||||
@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
snprintf(charptr1, 1+ptr-src, src);
|
snprintf(charptr1, 1+ptr-src, src);
|
||||||
newJob = xmalloc(sizeof(struct job));
|
newJob = xmalloc(sizeof(struct job));
|
||||||
/* Now parse and run the backticked command */
|
/* Now parse and run the backticked command */
|
||||||
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
|
if (!parseCommand(&charptr1, newJob, &njobList, inBg)
|
||||||
&& newJob->numProgs) {
|
&& newJob->numProgs) {
|
||||||
pipe(pipefd);
|
pipe(pipefd);
|
||||||
runCommand(newJob, &njobList, 0, pipefd);
|
runCommand(newJob, &njobList, 0, pipefd);
|
||||||
@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
* and improved version of the command line with the backtick
|
* and improved version of the command line with the backtick
|
||||||
* results expanded in place... */
|
* results expanded in place... */
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return(parseCommand(commandPtr, job, jobList, isBg));
|
return(parseCommand(commandPtr, job, jobList, inBg));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif // BB_FEATURE_SH_BACKTICKS
|
#endif // BB_FEATURE_SH_BACKTICKS
|
||||||
@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*prog->argv[argc]) {
|
if (*prog->argv[argc_l]) {
|
||||||
argc++;
|
argc_l++;
|
||||||
globLastArgument(prog, &argc, &argvAlloced);
|
globLastArgument(prog, &argc_l, &argvAlloced);
|
||||||
}
|
}
|
||||||
if (!argc) {
|
if (!argc_l) {
|
||||||
freeJob(job);
|
freeJob(job);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
prog->argv[argc] = NULL;
|
prog->argv[argc_l] = NULL;
|
||||||
|
|
||||||
if (!returnCommand) {
|
if (!returnCommand) {
|
||||||
job->text = xmalloc(strlen(*commandPtr) + 1);
|
job->text = xmalloc(strlen(*commandPtr) + 1);
|
||||||
@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
* works, but '/bin/cat' doesn't ) */
|
* works, but '/bin/cat' doesn't ) */
|
||||||
while (a->name != 0) {
|
while (a->name != 0) {
|
||||||
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
|
||||||
int argc;
|
int argc_l;
|
||||||
char** argv=newJob->progs[i].argv;
|
char** argv=newJob->progs[i].argv;
|
||||||
for(argc=0;*argv!=NULL; argv++, argc++);
|
for(argc_l=0;*argv!=NULL; argv++, argc_l++);
|
||||||
exit((*(a->main)) (argc, newJob->progs[i].argv));
|
exit((*(a->main)) (argc_l, newJob->progs[i].argv));
|
||||||
}
|
}
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
|
||||||
fatalError("sh: %s: %s\n", newJob->progs[i].argv[0],
|
fatalError("%s: %s\n", newJob->progs[i].argv[0],
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
if (outPipe[1]!=-1) {
|
if (outPipe[1]!=-1) {
|
||||||
@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
to the list of backgrounded theJobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", theJob->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = theJob;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setupRedirections(struct childProgram *prog)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int openfd;
|
|
||||||
int mode = O_RDONLY;
|
|
||||||
struct redirectionSpecifier *redir = prog->redirections;
|
|
||||||
|
|
||||||
for (i = 0; i < prog->numRedirections; i++, redir++) {
|
|
||||||
switch (redir->type) {
|
|
||||||
case REDIRECT_INPUT:
|
|
||||||
mode = O_RDONLY;
|
|
||||||
break;
|
|
||||||
case REDIRECT_OVERWRITE:
|
|
||||||
mode = O_RDWR | O_CREAT | O_TRUNC;
|
|
||||||
break;
|
|
||||||
case REDIRECT_APPEND:
|
|
||||||
mode = O_RDWR | O_CREAT | O_APPEND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
openfd = open(redir->filename, mode, 0666);
|
|
||||||
if (openfd < 0) {
|
|
||||||
/* this could get lost if stderr has been redirected, but
|
|
||||||
bash and ash both lose it as well (though zsh doesn't!) */
|
|
||||||
errorMsg("error opening %s: %s\n", redir->filename,
|
|
||||||
strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openfd != redir->fd) {
|
|
||||||
dup2(openfd, redir->fd);
|
|
||||||
close(openfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int busy_loop(FILE * input)
|
static int busy_loop(FILE * input)
|
||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
|
|||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
int status;
|
|
||||||
int inBg;
|
int inBg;
|
||||||
|
int status;
|
||||||
|
newJob.jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
/* save current owner of TTY so we can restore it on exit */
|
/* save current owner of TTY so we can restore it on exit */
|
||||||
parent_pgrp = tcgetpgrp(0);
|
parent_pgrp = tcgetpgrp(0);
|
||||||
@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
|
|||||||
removeJob(&jobList, jobList.fg);
|
removeJob(&jobList, jobList.fg);
|
||||||
jobList.fg = NULL;
|
jobList.fg = NULL;
|
||||||
}
|
}
|
||||||
|
#ifdef BB_FEATURE_SH_ENVIRONMENT
|
||||||
|
lastReturnCode=WEXITSTATUS(status);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* the child was stopped */
|
/* the child was stopped */
|
||||||
jobList.fg->stoppedProgs++;
|
jobList.fg->stoppedProgs++;
|
||||||
@ -1211,9 +1335,11 @@ void free_memory(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc_l, char **argv_l)
|
||||||
{
|
{
|
||||||
FILE *input = stdin;
|
FILE *input = stdin;
|
||||||
|
argc = argc_l;
|
||||||
|
argv = argv_l;
|
||||||
|
|
||||||
/* initialize the cwd -- this is never freed...*/
|
/* initialize the cwd -- this is never freed...*/
|
||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user