Add in redimentary backtick suport (doesn't work properly yet, but is

close).
 -Erik
This commit is contained in:
Eric Andersen 2000-07-14 01:13:11 +00:00
parent 34623db618
commit ec10b9d534
3 changed files with 219 additions and 120 deletions

113
lash.c
View File

@ -106,9 +106,9 @@ static int builtin_read(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, int *isBg); static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
static int setupRedirections(struct childProgram *prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -389,6 +389,7 @@ static void freeJob(struct job *cmd)
if (cmd->text) if (cmd->text)
free(cmd->text); free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
memset(cmd, 0, sizeof(struct job));
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
@ -471,7 +472,7 @@ static int getCommand(FILE * source, char *command)
char *promptStr; char *promptStr;
len=fprintf(stdout, "%s %s", cwd, prompt); len=fprintf(stdout, "%s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
promptStr=(char*)malloc(sizeof(char)*(len+1)); promptStr=(char*)xmalloc(sizeof(char)*(len+1));
sprintf(promptStr, "%s %s", cwd, prompt); sprintf(promptStr, "%s %s", cwd, prompt);
cmdedit_read_input(promptStr, command); cmdedit_read_input(promptStr, command);
free( promptStr); free( promptStr);
@ -550,7 +551,7 @@ 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, int *isBg) static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
{ {
char *command; char *command;
char *returnCommand = NULL; char *returnCommand = NULL;
@ -569,14 +570,13 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr == '#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs=0;
*commandPtr = NULL;
return 0; return 0;
} }
*isBg = 0; *isBg = 0;
job->numProgs = 1; job->numProgs = 1;
job->progs = malloc(sizeof(*job->progs)); job->progs = xmalloc(sizeof(*job->progs));
/* We set the argv elements to point inside of this string. The /* We set the argv elements to point inside of this string. The
memory is freed by freeJob(). Allocate twice the original memory is freed by freeJob(). Allocate twice the original
@ -595,7 +595,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->isStopped = 0; prog->isStopped = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = job->cmdBuf; prog->argv[0] = job->cmdBuf;
buf = command; buf = command;
@ -688,6 +688,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
@ -704,8 +705,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe1.\n");
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
@ -721,7 +723,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
argc = 0; argc = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
@ -729,7 +731,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
src++; src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe2\n");
freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
src--; /* we'll ++ it at the end of the loop */ src--; /* we'll ++ it at the end of the loop */
@ -746,13 +750,40 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
case '\\': case '\\':
src++; src++;
if (!*src) { if (!*src) {
freeJob(job);
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
freeJob(job);
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
case '`':
/* Exec a backtick-ed command */
{
char* newcmd=NULL;
char* ptr=NULL;
struct job newJob;
ptr=strchr(++src, '`');
if (ptr==NULL) {
fprintf(stderr, "Unmatched '`' in command\n");
freeJob(job);
return 1;
}
newcmd = xmalloc(1+ptr-src);
snprintf(newcmd, 1+ptr-src, src);
if (!parseCommand(&newcmd, &newJob, jobList, isBg) &&
newJob.numProgs) {
runCommand(&newJob, jobList, *isBg);
}
/* Clip out the the backticked command from the string */
memmove(--src, ptr, strlen(ptr)+1);
free(newcmd);
}
break;
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -771,12 +802,12 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
if (!returnCommand) { if (!returnCommand) {
job->text = malloc(strlen(*commandPtr) + 1); job->text = xmalloc(strlen(*commandPtr) + 1);
strcpy(job->text, *commandPtr); strcpy(job->text, *commandPtr);
} else { } else {
/* This leaves any trailing spaces, which is a bit sloppy */ /* This leaves any trailing spaces, which is a bit sloppy */
count = returnCommand - *commandPtr; count = returnCommand - *commandPtr;
job->text = malloc(count + 1); job->text = xmalloc(count + 1);
strncpy(job->text, *commandPtr, count); strncpy(job->text, *commandPtr, count);
job->text[count] = '\0'; job->text[count] = '\0';
} }
@ -787,7 +818,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
} }
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
{ {
struct job *job; struct job *job;
int i; int i;
@ -800,8 +831,8 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = 0, nextout = 1; nextin = 0, nextout = 1;
for (i = 0; i < newJob.numProgs; i++) { for (i = 0; i < newJob->numProgs; i++) {
if ((i + 1) < newJob.numProgs) { if ((i + 1) < newJob->numProgs) {
pipe(pipefds); pipe(pipefds);
nextout = pipefds[1]; nextout = pipefds[1];
} else { } else {
@ -810,12 +841,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
for (x = bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
return (x->function(&newJob, jobList)); return (x->function(newJob, jobList));
} }
} }
if (!(newJob.progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (nextin != 0) {
@ -829,12 +860,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
} }
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob.progs + i); setupRedirections(newJob->progs + i);
/* Check if the command matches any of the other builtins */ /* Check if the command matches any of the other builtins */
for (x = bltins_forking; x->cmd; x++) { for (x = bltins_forking; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
exit (x->function(&newJob, jobList)); exit (x->function(newJob, jobList));
} }
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
@ -842,24 +873,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching when paths are appended (i.e. 'cat' currently
* 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;
char** argv=newJob.progs[i].argv; char** argv=newJob->progs[i].argv;
for(argc=0;*argv!=NULL; argv++, argc++); for(argc=0;*argv!=NULL; argv++, argc++);
exit((*(a->main)) (argc, newJob.progs[i].argv)); exit((*(a->main)) (argc, 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("%s: %s\n", newJob.progs[i].argv[0], fatalError("%s: %s\n", newJob->progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
/* put our child in the process group whose leader is the /* put our child in the process group whose leader is the
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob->progs[i].pid, newJob->progs[0].pid);
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
@ -871,24 +902,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = pipefds[0]; nextin = pipefds[0];
} }
newJob.pgrp = newJob.progs[0].pid; newJob->pgrp = newJob->progs[0].pid;
/* find the ID for the job to use */ /* find the ID for the job to use */
newJob.jobId = 1; newJob->jobId = 1;
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId >= newJob.jobId) if (job->jobId >= newJob->jobId)
newJob.jobId = job->jobId + 1; newJob->jobId = job->jobId + 1;
/* add the job to the list of running jobs */ /* add the job to the list of running jobs */
if (!jobList->head) { if (!jobList->head) {
job = jobList->head = malloc(sizeof(*job)); job = jobList->head = xmalloc(sizeof(*job));
} else { } else {
for (job = jobList->head; job->next; job = job->next); for (job = jobList->head; job->next; job = job->next);
job->next = malloc(sizeof(*job)); job->next = xmalloc(sizeof(*job));
job = job->next; job = job->next;
} }
*job = newJob; *job = *newJob;
job->next = NULL; job->next = NULL;
job->runningProgs = job->numProgs; job->runningProgs = job->numProgs;
job->stoppedProgs = 0; job->stoppedProgs = 0;
@ -897,13 +928,13 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* we don't wait for background jobs to return -- append it /* we don't wait for background jobs to return -- append it
to the list of backgrounded jobs and leave it alone */ to the list of backgrounded jobs and leave it alone */
printf("[%d] %d\n", job->jobId, printf("[%d] %d\n", job->jobId,
newJob.progs[newJob.numProgs - 1].pid); newJob->progs[newJob->numProgs - 1].pid);
} else { } else {
jobList->fg = job; jobList->fg = job;
/* move the new process group into the foreground */ /* move the new process group into the foreground */
/* suppress messages when run from /linuxrc mag@sysgo.de */ /* suppress messages when run from /linuxrc mag@sysgo.de */
if (tcsetpgrp(0, newJob.pgrp) && errno != ENOTTY) if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
perror("tcsetpgrp"); perror("tcsetpgrp");
} }
@ -982,9 +1013,11 @@ static int busy_loop(FILE * input)
nextCommand = command; nextCommand = command;
} }
if (!parseCommand(&nextCommand, &newJob, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(newJob, &jobList, inBg); runCommand(&newJob, &jobList, inBg);
} else {
nextCommand=NULL;
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */

113
sh.c
View File

@ -106,9 +106,9 @@ static int builtin_read(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, int *isBg); static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
static int setupRedirections(struct childProgram *prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -389,6 +389,7 @@ static void freeJob(struct job *cmd)
if (cmd->text) if (cmd->text)
free(cmd->text); free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
memset(cmd, 0, sizeof(struct job));
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
@ -471,7 +472,7 @@ static int getCommand(FILE * source, char *command)
char *promptStr; char *promptStr;
len=fprintf(stdout, "%s %s", cwd, prompt); len=fprintf(stdout, "%s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
promptStr=(char*)malloc(sizeof(char)*(len+1)); promptStr=(char*)xmalloc(sizeof(char)*(len+1));
sprintf(promptStr, "%s %s", cwd, prompt); sprintf(promptStr, "%s %s", cwd, prompt);
cmdedit_read_input(promptStr, command); cmdedit_read_input(promptStr, command);
free( promptStr); free( promptStr);
@ -550,7 +551,7 @@ 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, int *isBg) static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
{ {
char *command; char *command;
char *returnCommand = NULL; char *returnCommand = NULL;
@ -569,14 +570,13 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr == '#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs=0;
*commandPtr = NULL;
return 0; return 0;
} }
*isBg = 0; *isBg = 0;
job->numProgs = 1; job->numProgs = 1;
job->progs = malloc(sizeof(*job->progs)); job->progs = xmalloc(sizeof(*job->progs));
/* We set the argv elements to point inside of this string. The /* We set the argv elements to point inside of this string. The
memory is freed by freeJob(). Allocate twice the original memory is freed by freeJob(). Allocate twice the original
@ -595,7 +595,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->isStopped = 0; prog->isStopped = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = job->cmdBuf; prog->argv[0] = job->cmdBuf;
buf = command; buf = command;
@ -688,6 +688,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
@ -704,8 +705,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe1.\n");
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
@ -721,7 +723,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
argc = 0; argc = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
@ -729,7 +731,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
src++; src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe2\n");
freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
src--; /* we'll ++ it at the end of the loop */ src--; /* we'll ++ it at the end of the loop */
@ -746,13 +750,40 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
case '\\': case '\\':
src++; src++;
if (!*src) { if (!*src) {
freeJob(job);
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
freeJob(job);
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
case '`':
/* Exec a backtick-ed command */
{
char* newcmd=NULL;
char* ptr=NULL;
struct job newJob;
ptr=strchr(++src, '`');
if (ptr==NULL) {
fprintf(stderr, "Unmatched '`' in command\n");
freeJob(job);
return 1;
}
newcmd = xmalloc(1+ptr-src);
snprintf(newcmd, 1+ptr-src, src);
if (!parseCommand(&newcmd, &newJob, jobList, isBg) &&
newJob.numProgs) {
runCommand(&newJob, jobList, *isBg);
}
/* Clip out the the backticked command from the string */
memmove(--src, ptr, strlen(ptr)+1);
free(newcmd);
}
break;
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -771,12 +802,12 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
if (!returnCommand) { if (!returnCommand) {
job->text = malloc(strlen(*commandPtr) + 1); job->text = xmalloc(strlen(*commandPtr) + 1);
strcpy(job->text, *commandPtr); strcpy(job->text, *commandPtr);
} else { } else {
/* This leaves any trailing spaces, which is a bit sloppy */ /* This leaves any trailing spaces, which is a bit sloppy */
count = returnCommand - *commandPtr; count = returnCommand - *commandPtr;
job->text = malloc(count + 1); job->text = xmalloc(count + 1);
strncpy(job->text, *commandPtr, count); strncpy(job->text, *commandPtr, count);
job->text[count] = '\0'; job->text[count] = '\0';
} }
@ -787,7 +818,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
} }
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
{ {
struct job *job; struct job *job;
int i; int i;
@ -800,8 +831,8 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = 0, nextout = 1; nextin = 0, nextout = 1;
for (i = 0; i < newJob.numProgs; i++) { for (i = 0; i < newJob->numProgs; i++) {
if ((i + 1) < newJob.numProgs) { if ((i + 1) < newJob->numProgs) {
pipe(pipefds); pipe(pipefds);
nextout = pipefds[1]; nextout = pipefds[1];
} else { } else {
@ -810,12 +841,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
for (x = bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
return (x->function(&newJob, jobList)); return (x->function(newJob, jobList));
} }
} }
if (!(newJob.progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (nextin != 0) {
@ -829,12 +860,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
} }
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob.progs + i); setupRedirections(newJob->progs + i);
/* Check if the command matches any of the other builtins */ /* Check if the command matches any of the other builtins */
for (x = bltins_forking; x->cmd; x++) { for (x = bltins_forking; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
exit (x->function(&newJob, jobList)); exit (x->function(newJob, jobList));
} }
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
@ -842,24 +873,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching when paths are appended (i.e. 'cat' currently
* 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;
char** argv=newJob.progs[i].argv; char** argv=newJob->progs[i].argv;
for(argc=0;*argv!=NULL; argv++, argc++); for(argc=0;*argv!=NULL; argv++, argc++);
exit((*(a->main)) (argc, newJob.progs[i].argv)); exit((*(a->main)) (argc, 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("%s: %s\n", newJob.progs[i].argv[0], fatalError("%s: %s\n", newJob->progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
/* put our child in the process group whose leader is the /* put our child in the process group whose leader is the
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob->progs[i].pid, newJob->progs[0].pid);
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
@ -871,24 +902,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = pipefds[0]; nextin = pipefds[0];
} }
newJob.pgrp = newJob.progs[0].pid; newJob->pgrp = newJob->progs[0].pid;
/* find the ID for the job to use */ /* find the ID for the job to use */
newJob.jobId = 1; newJob->jobId = 1;
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId >= newJob.jobId) if (job->jobId >= newJob->jobId)
newJob.jobId = job->jobId + 1; newJob->jobId = job->jobId + 1;
/* add the job to the list of running jobs */ /* add the job to the list of running jobs */
if (!jobList->head) { if (!jobList->head) {
job = jobList->head = malloc(sizeof(*job)); job = jobList->head = xmalloc(sizeof(*job));
} else { } else {
for (job = jobList->head; job->next; job = job->next); for (job = jobList->head; job->next; job = job->next);
job->next = malloc(sizeof(*job)); job->next = xmalloc(sizeof(*job));
job = job->next; job = job->next;
} }
*job = newJob; *job = *newJob;
job->next = NULL; job->next = NULL;
job->runningProgs = job->numProgs; job->runningProgs = job->numProgs;
job->stoppedProgs = 0; job->stoppedProgs = 0;
@ -897,13 +928,13 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* we don't wait for background jobs to return -- append it /* we don't wait for background jobs to return -- append it
to the list of backgrounded jobs and leave it alone */ to the list of backgrounded jobs and leave it alone */
printf("[%d] %d\n", job->jobId, printf("[%d] %d\n", job->jobId,
newJob.progs[newJob.numProgs - 1].pid); newJob->progs[newJob->numProgs - 1].pid);
} else { } else {
jobList->fg = job; jobList->fg = job;
/* move the new process group into the foreground */ /* move the new process group into the foreground */
/* suppress messages when run from /linuxrc mag@sysgo.de */ /* suppress messages when run from /linuxrc mag@sysgo.de */
if (tcsetpgrp(0, newJob.pgrp) && errno != ENOTTY) if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
perror("tcsetpgrp"); perror("tcsetpgrp");
} }
@ -982,9 +1013,11 @@ static int busy_loop(FILE * input)
nextCommand = command; nextCommand = command;
} }
if (!parseCommand(&nextCommand, &newJob, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(newJob, &jobList, inBg); runCommand(&newJob, &jobList, inBg);
} else {
nextCommand=NULL;
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */

View File

@ -106,9 +106,9 @@ static int builtin_read(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, int *isBg); static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
static int setupRedirections(struct childProgram *prog); static int setupRedirections(struct childProgram *prog);
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg); static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -389,6 +389,7 @@ static void freeJob(struct job *cmd)
if (cmd->text) if (cmd->text)
free(cmd->text); free(cmd->text);
free(cmd->cmdBuf); free(cmd->cmdBuf);
memset(cmd, 0, sizeof(struct job));
} }
/* remove a job from the jobList */ /* remove a job from the jobList */
@ -471,7 +472,7 @@ static int getCommand(FILE * source, char *command)
char *promptStr; char *promptStr;
len=fprintf(stdout, "%s %s", cwd, prompt); len=fprintf(stdout, "%s %s", cwd, prompt);
fflush(stdout); fflush(stdout);
promptStr=(char*)malloc(sizeof(char)*(len+1)); promptStr=(char*)xmalloc(sizeof(char)*(len+1));
sprintf(promptStr, "%s %s", cwd, prompt); sprintf(promptStr, "%s %s", cwd, prompt);
cmdedit_read_input(promptStr, command); cmdedit_read_input(promptStr, command);
free( promptStr); free( promptStr);
@ -550,7 +551,7 @@ 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, int *isBg) static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg)
{ {
char *command; char *command;
char *returnCommand = NULL; char *returnCommand = NULL;
@ -569,14 +570,13 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
/* this handles empty lines or leading '#' characters */ /* this handles empty lines or leading '#' characters */
if (!**commandPtr || (**commandPtr == '#')) { if (!**commandPtr || (**commandPtr == '#')) {
job->numProgs = 0; job->numProgs=0;
*commandPtr = NULL;
return 0; return 0;
} }
*isBg = 0; *isBg = 0;
job->numProgs = 1; job->numProgs = 1;
job->progs = malloc(sizeof(*job->progs)); job->progs = xmalloc(sizeof(*job->progs));
/* We set the argv elements to point inside of this string. The /* We set the argv elements to point inside of this string. The
memory is freed by freeJob(). Allocate twice the original memory is freed by freeJob(). Allocate twice the original
@ -595,7 +595,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->isStopped = 0; prog->isStopped = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = job->cmdBuf; prog->argv[0] = job->cmdBuf;
buf = command; buf = command;
@ -688,6 +688,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (!*chptr) { if (!*chptr) {
fprintf(stderr, "file name expected after %c\n", *src); fprintf(stderr, "file name expected after %c\n", *src);
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
@ -704,8 +705,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe1.\n");
freeJob(job); freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
@ -721,7 +723,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
argc = 0; argc = 0;
argvAlloced = 5; argvAlloced = 5;
prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
prog->argv[0] = ++buf; prog->argv[0] = ++buf;
src++; src++;
@ -729,7 +731,9 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
src++; src++;
if (!*src) { if (!*src) {
fprintf(stderr, "empty command in pipe\n"); fprintf(stderr, "empty command in pipe2\n");
freeJob(job);
job->numProgs=0;
return 1; return 1;
} }
src--; /* we'll ++ it at the end of the loop */ src--; /* we'll ++ it at the end of the loop */
@ -746,13 +750,40 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
case '\\': case '\\':
src++; src++;
if (!*src) { if (!*src) {
freeJob(job);
fprintf(stderr, "character expected after \\\n"); fprintf(stderr, "character expected after \\\n");
freeJob(job);
return 1; return 1;
} }
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
case '`':
/* Exec a backtick-ed command */
{
char* newcmd=NULL;
char* ptr=NULL;
struct job newJob;
ptr=strchr(++src, '`');
if (ptr==NULL) {
fprintf(stderr, "Unmatched '`' in command\n");
freeJob(job);
return 1;
}
newcmd = xmalloc(1+ptr-src);
snprintf(newcmd, 1+ptr-src, src);
if (!parseCommand(&newcmd, &newJob, jobList, isBg) &&
newJob.numProgs) {
runCommand(&newJob, jobList, *isBg);
}
/* Clip out the the backticked command from the string */
memmove(--src, ptr, strlen(ptr)+1);
free(newcmd);
}
break;
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -771,12 +802,12 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
prog->argv[argc] = NULL; prog->argv[argc] = NULL;
if (!returnCommand) { if (!returnCommand) {
job->text = malloc(strlen(*commandPtr) + 1); job->text = xmalloc(strlen(*commandPtr) + 1);
strcpy(job->text, *commandPtr); strcpy(job->text, *commandPtr);
} else { } else {
/* This leaves any trailing spaces, which is a bit sloppy */ /* This leaves any trailing spaces, which is a bit sloppy */
count = returnCommand - *commandPtr; count = returnCommand - *commandPtr;
job->text = malloc(count + 1); job->text = xmalloc(count + 1);
strncpy(job->text, *commandPtr, count); strncpy(job->text, *commandPtr, count);
job->text[count] = '\0'; job->text[count] = '\0';
} }
@ -787,7 +818,7 @@ static int parseCommand(char **commandPtr, struct job *job, int *isBg)
} }
static int runCommand(struct job newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
{ {
struct job *job; struct job *job;
int i; int i;
@ -800,8 +831,8 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = 0, nextout = 1; nextin = 0, nextout = 1;
for (i = 0; i < newJob.numProgs; i++) { for (i = 0; i < newJob->numProgs; i++) {
if ((i + 1) < newJob.numProgs) { if ((i + 1) < newJob->numProgs) {
pipe(pipefds); pipe(pipefds);
nextout = pipefds[1]; nextout = pipefds[1];
} else { } else {
@ -810,12 +841,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
for (x = bltins; x->cmd; x++) { for (x = bltins; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
return (x->function(&newJob, jobList)); return (x->function(newJob, jobList));
} }
} }
if (!(newJob.progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (nextin != 0) {
@ -829,12 +860,12 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
} }
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob.progs + i); setupRedirections(newJob->progs + i);
/* Check if the command matches any of the other builtins */ /* Check if the command matches any of the other builtins */
for (x = bltins_forking; x->cmd; x++) { for (x = bltins_forking; x->cmd; x++) {
if (!strcmp(newJob.progs[i].argv[0], x->cmd)) { if (!strcmp(newJob->progs[i].argv[0], x->cmd)) {
exit (x->function(&newJob, jobList)); exit (x->function(newJob, jobList));
} }
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
@ -842,24 +873,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching when paths are appended (i.e. 'cat' currently
* 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;
char** argv=newJob.progs[i].argv; char** argv=newJob->progs[i].argv;
for(argc=0;*argv!=NULL; argv++, argc++); for(argc=0;*argv!=NULL; argv++, argc++);
exit((*(a->main)) (argc, newJob.progs[i].argv)); exit((*(a->main)) (argc, 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("%s: %s\n", newJob.progs[i].argv[0], fatalError("%s: %s\n", newJob->progs[i].argv[0],
strerror(errno)); strerror(errno));
} }
/* put our child in the process group whose leader is the /* put our child in the process group whose leader is the
first process in this pipe */ first process in this pipe */
setpgid(newJob.progs[i].pid, newJob.progs[0].pid); setpgid(newJob->progs[i].pid, newJob->progs[0].pid);
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
@ -871,24 +902,24 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
nextin = pipefds[0]; nextin = pipefds[0];
} }
newJob.pgrp = newJob.progs[0].pid; newJob->pgrp = newJob->progs[0].pid;
/* find the ID for the job to use */ /* find the ID for the job to use */
newJob.jobId = 1; newJob->jobId = 1;
for (job = jobList->head; job; job = job->next) for (job = jobList->head; job; job = job->next)
if (job->jobId >= newJob.jobId) if (job->jobId >= newJob->jobId)
newJob.jobId = job->jobId + 1; newJob->jobId = job->jobId + 1;
/* add the job to the list of running jobs */ /* add the job to the list of running jobs */
if (!jobList->head) { if (!jobList->head) {
job = jobList->head = malloc(sizeof(*job)); job = jobList->head = xmalloc(sizeof(*job));
} else { } else {
for (job = jobList->head; job->next; job = job->next); for (job = jobList->head; job->next; job = job->next);
job->next = malloc(sizeof(*job)); job->next = xmalloc(sizeof(*job));
job = job->next; job = job->next;
} }
*job = newJob; *job = *newJob;
job->next = NULL; job->next = NULL;
job->runningProgs = job->numProgs; job->runningProgs = job->numProgs;
job->stoppedProgs = 0; job->stoppedProgs = 0;
@ -897,13 +928,13 @@ static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
/* we don't wait for background jobs to return -- append it /* we don't wait for background jobs to return -- append it
to the list of backgrounded jobs and leave it alone */ to the list of backgrounded jobs and leave it alone */
printf("[%d] %d\n", job->jobId, printf("[%d] %d\n", job->jobId,
newJob.progs[newJob.numProgs - 1].pid); newJob->progs[newJob->numProgs - 1].pid);
} else { } else {
jobList->fg = job; jobList->fg = job;
/* move the new process group into the foreground */ /* move the new process group into the foreground */
/* suppress messages when run from /linuxrc mag@sysgo.de */ /* suppress messages when run from /linuxrc mag@sysgo.de */
if (tcsetpgrp(0, newJob.pgrp) && errno != ENOTTY) if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
perror("tcsetpgrp"); perror("tcsetpgrp");
} }
@ -982,9 +1013,11 @@ static int busy_loop(FILE * input)
nextCommand = command; nextCommand = command;
} }
if (!parseCommand(&nextCommand, &newJob, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(newJob, &jobList, inBg); runCommand(&newJob, &jobList, inBg);
} else {
nextCommand=NULL;
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */