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:
		
							
								
								
									
										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_ENVIRONMENT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#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 IF_EXP_CONTEXT=0x2;
 | 
			
		||||
static const unsigned int THEN_EXP_CONTEXT=0x4;
 | 
			
		||||
static const unsigned int ELSE_EXP_CONTEXT=0x8;
 | 
			
		||||
static const unsigned int IF_TRUE_CONTEXT=0x2;
 | 
			
		||||
static const unsigned int IF_FALSE_CONTEXT=0x4;
 | 
			
		||||
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 job *head;			/* head of list of running jobs */
 | 
			
		||||
	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 */
 | 
			
		||||
static void checkJobs(struct jobSet *jobList);
 | 
			
		||||
static int getCommand(FILE * source, char *command);
 | 
			
		||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
 | 
			
		||||
static int setupRedirections(struct childProgram *prog);
 | 
			
		||||
static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
 | 
			
		||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
 | 
			
		||||
static int busy_loop(FILE * input);
 | 
			
		||||
 | 
			
		||||
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
 | 
			
		||||
	{"export", "Set environment variable", builtin_export},
 | 
			
		||||
	{"unset", "Unset environment variable", builtin_unset},
 | 
			
		||||
	{"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}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
 | 
			
		||||
static struct builtInCommand bltins_forking[] = {
 | 
			
		||||
	{"env", "Print all environment variables", builtin_env},
 | 
			
		||||
	{"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},
 | 
			
		||||
	{"help", "List shell built-in commands", builtin_help},
 | 
			
		||||
	{NULL, NULL, NULL}
 | 
			
		||||
@@ -170,6 +167,13 @@ static char *cwd;
 | 
			
		||||
static char *local_pending_command = NULL;
 | 
			
		||||
static char *promptStr = 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
 | 
			
		||||
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
 | 
			
		||||
/* 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;
 | 
			
		||||
	printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
 | 
			
		||||
	return TRUE;
 | 
			
		||||
	int status;
 | 
			
		||||
	char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
 | 
			
		||||
 | 
			
		||||
	/* 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) */
 | 
			
		||||
static int builtin_then(struct job *cmd, struct jobSet *junk)
 | 
			
		||||
{
 | 
			
		||||
	if (cmd->jobContext & IF_EXP_CONTEXT) {
 | 
			
		||||
		fprintf(stderr, "unexpected token `then'\n");
 | 
			
		||||
		fflush(stderr);
 | 
			
		||||
	int status;
 | 
			
		||||
	char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
 | 
			
		||||
 | 
			
		||||
	if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
 | 
			
		||||
		errorMsg("unexpected token `then'\n");
 | 
			
		||||
		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;
 | 
			
		||||
	printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
 | 
			
		||||
	return TRUE;
 | 
			
		||||
	//printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
 | 
			
		||||
 | 
			
		||||
	/* 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) */
 | 
			
		||||
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;
 | 
			
		||||
	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) */
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
 | 
			
		||||
		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)
 | 
			
		||||
{
 | 
			
		||||
	if (source == NULL) {
 | 
			
		||||
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
 | 
			
		||||
	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,
 | 
			
		||||
							 int *argcAllocedPtr)
 | 
			
		||||
{
 | 
			
		||||
	int argc = *argcPtr;
 | 
			
		||||
	int argc_l = *argcPtr;
 | 
			
		||||
	int argcAlloced = *argcAllocedPtr;
 | 
			
		||||
	int rc;
 | 
			
		||||
	int flags;
 | 
			
		||||
	int i;
 | 
			
		||||
	char *src, *dst, *var;
 | 
			
		||||
 | 
			
		||||
	if (argc > 1) {				/* cmd->globResult is already initialized */
 | 
			
		||||
	if (argc_l > 1) {				/* cmd->globResult is already initialized */
 | 
			
		||||
		flags = GLOB_APPEND;
 | 
			
		||||
		i = prog->globResult.gl_pathc;
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
 | 
			
		||||
		i = 0;
 | 
			
		||||
	}
 | 
			
		||||
	/* do shell variable substitution */
 | 
			
		||||
	if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1)))
 | 
			
		||||
		prog->argv[argc - 1] = var;
 | 
			
		||||
	if(*prog->argv[argc_l - 1] == '$') {
 | 
			
		||||
		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) {
 | 
			
		||||
		errorMsg("out of space during glob operation\n");
 | 
			
		||||
		return;
 | 
			
		||||
	} else if (rc == GLOB_NOMATCH ||
 | 
			
		||||
			   (!rc && (prog->globResult.gl_pathc - i) == 1 &&
 | 
			
		||||
				strcmp(prog->argv[argc - 1],
 | 
			
		||||
				strcmp(prog->argv[argc_l - 1],
 | 
			
		||||
						prog->globResult.gl_pathv[i]) == 0)) {
 | 
			
		||||
		/* we need to remove whatever \ quoting is still present */
 | 
			
		||||
		src = dst = prog->argv[argc - 1];
 | 
			
		||||
		src = dst = prog->argv[argc_l - 1];
 | 
			
		||||
		while (*src) {
 | 
			
		||||
			if (*src != '\\')
 | 
			
		||||
				*dst++ = *src;
 | 
			
		||||
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
 | 
			
		||||
		argcAlloced += (prog->globResult.gl_pathc - i);
 | 
			
		||||
		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));
 | 
			
		||||
		argc += (prog->globResult.gl_pathc - i - 1);
 | 
			
		||||
		argc_l += (prog->globResult.gl_pathc - i - 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*argcAllocedPtr = argcAlloced;
 | 
			
		||||
	*argcPtr = argc;
 | 
			
		||||
	*argcPtr = argc_l;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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 
 | 
			
		||||
   then one job associated with it) or NULL if no more commands are 
 | 
			
		||||
   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 *returnCommand = NULL;
 | 
			
		||||
	char *src, *buf, *chptr;
 | 
			
		||||
	int argc = 0;
 | 
			
		||||
	int argc_l = 0;
 | 
			
		||||
	int done = 0;
 | 
			
		||||
	int argvAlloced;
 | 
			
		||||
	int i;
 | 
			
		||||
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*isBg = 0;
 | 
			
		||||
	*inBg = 0;
 | 
			
		||||
	job->numProgs = 1;
 | 
			
		||||
	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) */
 | 
			
		||||
	job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
 | 
			
		||||
	job->text = NULL;
 | 
			
		||||
	job->jobContext = REGULAR_JOB_CONTEXT;
 | 
			
		||||
 | 
			
		||||
	prog = job->progs;
 | 
			
		||||
	prog->numRedirections = 0;
 | 
			
		||||
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
					   *src == ']') *buf++ = '\\';
 | 
			
		||||
			*buf++ = *src;
 | 
			
		||||
		} else if (isspace(*src)) {
 | 
			
		||||
			if (*prog->argv[argc]) {
 | 
			
		||||
				buf++, argc++;
 | 
			
		||||
			if (*prog->argv[argc_l]) {
 | 
			
		||||
				buf++, argc_l++;
 | 
			
		||||
				/* +1 here leaves room for the NULL which ends argv */
 | 
			
		||||
				if ((argc + 1) == argvAlloced) {
 | 
			
		||||
				if ((argc_l + 1) == argvAlloced) {
 | 
			
		||||
					argvAlloced += 5;
 | 
			
		||||
					prog->argv = realloc(prog->argv,
 | 
			
		||||
										 sizeof(*prog->argv) *
 | 
			
		||||
										 argvAlloced);
 | 
			
		||||
				}
 | 
			
		||||
				globLastArgument(prog, &argc, &argvAlloced);
 | 
			
		||||
				prog->argv[argc] = buf;
 | 
			
		||||
				globLastArgument(prog, &argc_l, &argvAlloced);
 | 
			
		||||
				prog->argv[argc_l] = buf;
 | 
			
		||||
			}
 | 
			
		||||
		} else
 | 
			
		||||
			switch (*src) {
 | 
			
		||||
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case '#':			/* comment */
 | 
			
		||||
				done = 1;
 | 
			
		||||
				if (*(src-1)== '$')
 | 
			
		||||
					*buf++ = *src;
 | 
			
		||||
				else
 | 
			
		||||
					done = 1;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case '>':			/* redirections */
 | 
			
		||||
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
											 (i + 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 
 | 
			
		||||
					   being redirected */
 | 
			
		||||
					prog->redirections[i].fd =
 | 
			
		||||
						strtol(prog->argv[argc], &chptr, 10);
 | 
			
		||||
						strtol(prog->argv[argc_l], &chptr, 10);
 | 
			
		||||
 | 
			
		||||
					if (*chptr && *prog->argv[argc]) {
 | 
			
		||||
						buf++, argc++;
 | 
			
		||||
						globLastArgument(prog, &argc, &argvAlloced);
 | 
			
		||||
						prog->argv[argc] = buf;
 | 
			
		||||
					if (*chptr && *prog->argv[argc_l]) {
 | 
			
		||||
						buf++, argc_l++;
 | 
			
		||||
						globLastArgument(prog, &argc_l, &argvAlloced);
 | 
			
		||||
						prog->argv[argc_l] = buf;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
					*buf++ = *chptr++;
 | 
			
		||||
 | 
			
		||||
				src = chptr - 1;	/* we src++ later */
 | 
			
		||||
				prog->argv[argc] = ++buf;
 | 
			
		||||
				prog->argv[argc_l] = ++buf;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case '|':			/* pipe */
 | 
			
		||||
				/* finish this command */
 | 
			
		||||
				if (*prog->argv[argc])
 | 
			
		||||
					argc++;
 | 
			
		||||
				if (!argc) {
 | 
			
		||||
				if (*prog->argv[argc_l])
 | 
			
		||||
					argc_l++;
 | 
			
		||||
				if (!argc_l) {
 | 
			
		||||
					errorMsg("empty command in pipe\n");
 | 
			
		||||
					freeJob(job);
 | 
			
		||||
					job->numProgs=0;
 | 
			
		||||
					return 1;
 | 
			
		||||
				}
 | 
			
		||||
				prog->argv[argc] = NULL;
 | 
			
		||||
				prog->argv[argc_l] = NULL;
 | 
			
		||||
 | 
			
		||||
				/* and start the next */
 | 
			
		||||
				job->numProgs++;
 | 
			
		||||
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
				prog->numRedirections = 0;
 | 
			
		||||
				prog->redirections = NULL;
 | 
			
		||||
				prog->freeGlob = 0;
 | 
			
		||||
				argc = 0;
 | 
			
		||||
				argc_l = 0;
 | 
			
		||||
 | 
			
		||||
				argvAlloced = 5;
 | 
			
		||||
				prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
 | 
			
		||||
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case '&':			/* background */
 | 
			
		||||
				*isBg = 1;
 | 
			
		||||
				*inBg = 1;
 | 
			
		||||
			case ';':			/* multiple commands */
 | 
			
		||||
				done = 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);
 | 
			
		||||
					newJob = xmalloc(sizeof(struct job));
 | 
			
		||||
					/* Now parse and run the backticked command */
 | 
			
		||||
					if (!parseCommand(&charptr1, newJob, &njobList, isBg) 
 | 
			
		||||
					if (!parseCommand(&charptr1, newJob, &njobList, inBg) 
 | 
			
		||||
							&& newJob->numProgs) {
 | 
			
		||||
						pipe(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
 | 
			
		||||
					 * results expanded in place... */
 | 
			
		||||
					freeJob(job);
 | 
			
		||||
					return(parseCommand(commandPtr, job, jobList, isBg));
 | 
			
		||||
					return(parseCommand(commandPtr, job, jobList, inBg));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
#endif // BB_FEATURE_SH_BACKTICKS
 | 
			
		||||
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
 | 
			
		||||
		src++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*prog->argv[argc]) {
 | 
			
		||||
		argc++;
 | 
			
		||||
		globLastArgument(prog, &argc, &argvAlloced);
 | 
			
		||||
	if (*prog->argv[argc_l]) {
 | 
			
		||||
		argc_l++;
 | 
			
		||||
		globLastArgument(prog, &argc_l, &argvAlloced);
 | 
			
		||||
	}
 | 
			
		||||
	if (!argc) {
 | 
			
		||||
	if (!argc_l) {
 | 
			
		||||
		freeJob(job);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	prog->argv[argc] = NULL;
 | 
			
		||||
	prog->argv[argc_l] = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!returnCommand) {
 | 
			
		||||
		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 ) */
 | 
			
		||||
			while (a->name != 0) {
 | 
			
		||||
				if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
 | 
			
		||||
					int argc;
 | 
			
		||||
					int argc_l;
 | 
			
		||||
					char** argv=newJob->progs[i].argv;
 | 
			
		||||
					for(argc=0;*argv!=NULL; argv++, argc++);
 | 
			
		||||
					exit((*(a->main)) (argc, newJob->progs[i].argv));
 | 
			
		||||
					for(argc_l=0;*argv!=NULL; argv++, argc_l++);
 | 
			
		||||
					exit((*(a->main)) (argc_l, newJob->progs[i].argv));
 | 
			
		||||
				}
 | 
			
		||||
				a++;
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			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));
 | 
			
		||||
		}
 | 
			
		||||
		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 */
 | 
			
		||||
		printf("[%d] %d\n", theJob->jobId,
 | 
			
		||||
			   newJob->progs[newJob->numProgs - 1].pid);
 | 
			
		||||
#ifdef BB_FEATURE_SH_ENVIRONMENT
 | 
			
		||||
		lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
 | 
			
		||||
#endif
 | 
			
		||||
	} else {
 | 
			
		||||
		jobList->fg = theJob;
 | 
			
		||||
 | 
			
		||||
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	char *command;
 | 
			
		||||
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
 | 
			
		||||
	struct job newJob;
 | 
			
		||||
	pid_t  parent_pgrp;
 | 
			
		||||
	int i;
 | 
			
		||||
	int status;
 | 
			
		||||
	int inBg;
 | 
			
		||||
	int status;
 | 
			
		||||
	newJob.jobContext = REGULAR_JOB_CONTEXT;
 | 
			
		||||
 | 
			
		||||
	/* save current owner of TTY so we can restore it on exit */
 | 
			
		||||
	parent_pgrp = tcgetpgrp(0);
 | 
			
		||||
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
 | 
			
		||||
					removeJob(&jobList, jobList.fg);
 | 
			
		||||
					jobList.fg = NULL;
 | 
			
		||||
				}
 | 
			
		||||
#ifdef BB_FEATURE_SH_ENVIRONMENT
 | 
			
		||||
				lastReturnCode=WEXITSTATUS(status);
 | 
			
		||||
#endif
 | 
			
		||||
			} else {
 | 
			
		||||
				/* the child was stopped */
 | 
			
		||||
				jobList.fg->stoppedProgs++;
 | 
			
		||||
@@ -1211,9 +1335,11 @@ void free_memory(void)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int shell_main(int argc, char **argv)
 | 
			
		||||
int shell_main(int argc_l, char **argv_l)
 | 
			
		||||
{
 | 
			
		||||
	FILE *input = stdin;
 | 
			
		||||
	argc = argc_l;
 | 
			
		||||
	argv = argv_l;
 | 
			
		||||
 | 
			
		||||
	/* initialize the cwd -- this is never freed...*/
 | 
			
		||||
	cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user