Backtick support to infinite (memory limited) levels of nesting is

now implemented...  So now busybox shell can do cool stuff like:

    /home/andersen/CVS/busybox # echo foo `wc README` bar
    foo 71 422 2951 README bar

I love writing cool new features....  Muhahahaha...  (I think this is
leaking a little bit of memory every time it expands a backtick process,
so I still needs to do a bit of cleanup...)
 -Erik
This commit is contained in:
Eric Andersen 2000-07-17 19:14:41 +00:00
parent bc0aed79a8
commit a1d187a8a8
3 changed files with 249 additions and 84 deletions

111
lash.c
View File

@ -25,6 +25,11 @@
* *
*/ */
#define BB_FEATURE_SH_BACKTICKS
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -108,7 +113,7 @@ 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 *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, int outPipe[2]);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -420,6 +425,10 @@ static void checkJobs(struct jobSet *jobList)
break; break;
} }
/* This happens on backticked commands */
if(job==NULL)
return;
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
/* child exited */ /* child exited */
job->runningProgs--; job->runningProgs--;
@ -697,7 +706,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
errorMsg("empty command in pipe1\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -723,7 +732,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
src++; src++;
if (!*src) { if (!*src) {
errorMsg("empty command in pipe2\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -749,12 +758,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
#ifdef BB_FEATURE_SH_BACKTICKS
case '`': case '`':
/* Exec a backtick-ed command */ /* Exec a backtick-ed command */
{ {
char* newcmd=NULL; char* charptr1=NULL, *charptr2;
char* ptr=NULL; char* ptr=NULL;
struct job newJob; struct job *newJob;
struct jobSet njobList = { NULL, NULL };
int pipefd[2];
int size;
ptr=strchr(++src, '`'); ptr=strchr(++src, '`');
if (ptr==NULL) { if (ptr==NULL) {
@ -763,19 +776,56 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
return 1; return 1;
} }
newcmd = xmalloc(1+ptr-src); /* Make a copy of any stuff left over in the command
snprintf(newcmd, 1+ptr-src, src); * line after the second backtick */
charptr2 = xmalloc(strlen(ptr)+1);
memcpy(charptr2, ptr+1, strlen(ptr));
if (!parseCommand(&newcmd, &newJob, jobList, isBg) && /* Make some space to hold just the backticked command */
newJob.numProgs) { charptr1 = xmalloc(1+ptr-src);
runCommand(&newJob, jobList, *isBg); snprintf(charptr1, 1+ptr-src, src);
newJob = xmalloc(sizeof(struct job));
/* Now parse and run the backticked command */
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
&& newJob->numProgs) {
pipe(pipefd);
runCommand(newJob, &njobList, 0, pipefd);
} }
checkJobs(jobList);
free(charptr1);
/* Clip out the the backticked command from the string */ /* Copy the output from the backtick-ed command into the
memmove(--src, ptr, strlen(ptr)+1); * command line, making extra room as needed */
free(newcmd); --src;
charptr1 = xmalloc(BUFSIZ);
while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) {
int newSize=src - *commandPtr + size + 1 + strlen(charptr2);
if (newSize > BUFSIZ) {
*commandPtr=realloc(*commandPtr, src - *commandPtr +
size + 1 + strlen(charptr2));
}
memcpy(src, charptr1, size);
src+=size;
}
free(charptr1);
close(pipefd[0]);
if (*(src-1)=='\n')
--src;
/* Now paste into the *commandPtr all the stuff
* leftover after the second backtick */
memcpy(src, charptr2, strlen(charptr2));
fprintf(stderr,"*commandPtr='%s'\n", *commandPtr);
free(charptr2);
/* Now recursively call parseCommand to deal with the new
* and improved version of the command line with the backtick
* results expanded in place... */
return(parseCommand(commandPtr, job, jobList, isBg));
} }
break; break;
#endif // BB_FEATURE_SH_BACKTICKS
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -810,25 +860,23 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
} }
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
{ {
struct job *job; struct job *job;
int nextin=0, nextout, stdoutfd=fileno(stdout);
int i; int i;
int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
struct builtInCommand *x; struct builtInCommand *x;
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
const struct BB_applet *a = applets; const struct BB_applet *a = applets;
#endif #endif
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 {
nextout = 1; nextout = stdoutfd;
} }
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
@ -841,16 +889,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (!(newJob->progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (outPipe[1]!=-1) {
dup2(nextin, 0); close(outPipe[0]);
close(nextin); nextout = stdoutfd = outPipe[1];
}
if (nextout != 1) {
dup2(nextout, 1); dup2(nextout, 1);
dup2(nextout, 2);
close(nextout); close(nextout);
} }
//dup2(nextin, 0);
//close(nextin);
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob->progs + i); setupRedirections(newJob->progs + i);
@ -862,8 +911,8 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
/* Check if the command matches any busybox internal commands here */ /* Check if the command matches any busybox internal commands here */
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching on commands with paths appended (i.e. 'cat'
* works, but '/bin/cat' doesn't ) */ * currently 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;
@ -879,6 +928,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
fatalError("%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) {
close(outPipe[1]);
}
/* 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 */
@ -886,7 +938,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
if (nextout != 1) if (nextout != stdoutfd)
close(nextout); close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
@ -1007,9 +1059,12 @@ static int busy_loop(FILE * input)
if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(&newJob, &jobList, inBg); int pipefds[2] = {-1,-1};
runCommand(&newJob, &jobList, inBg, pipefds);
} else { } else {
nextCommand=NULL; nextCommand=NULL;
free(command);
command = (char *) calloc(BUFSIZ, sizeof(char));
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */

111
sh.c
View File

@ -25,6 +25,11 @@
* *
*/ */
#define BB_FEATURE_SH_BACKTICKS
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -108,7 +113,7 @@ 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 *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, int outPipe[2]);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -420,6 +425,10 @@ static void checkJobs(struct jobSet *jobList)
break; break;
} }
/* This happens on backticked commands */
if(job==NULL)
return;
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
/* child exited */ /* child exited */
job->runningProgs--; job->runningProgs--;
@ -697,7 +706,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
errorMsg("empty command in pipe1\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -723,7 +732,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
src++; src++;
if (!*src) { if (!*src) {
errorMsg("empty command in pipe2\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -749,12 +758,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
#ifdef BB_FEATURE_SH_BACKTICKS
case '`': case '`':
/* Exec a backtick-ed command */ /* Exec a backtick-ed command */
{ {
char* newcmd=NULL; char* charptr1=NULL, *charptr2;
char* ptr=NULL; char* ptr=NULL;
struct job newJob; struct job *newJob;
struct jobSet njobList = { NULL, NULL };
int pipefd[2];
int size;
ptr=strchr(++src, '`'); ptr=strchr(++src, '`');
if (ptr==NULL) { if (ptr==NULL) {
@ -763,19 +776,56 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
return 1; return 1;
} }
newcmd = xmalloc(1+ptr-src); /* Make a copy of any stuff left over in the command
snprintf(newcmd, 1+ptr-src, src); * line after the second backtick */
charptr2 = xmalloc(strlen(ptr)+1);
memcpy(charptr2, ptr+1, strlen(ptr));
if (!parseCommand(&newcmd, &newJob, jobList, isBg) && /* Make some space to hold just the backticked command */
newJob.numProgs) { charptr1 = xmalloc(1+ptr-src);
runCommand(&newJob, jobList, *isBg); snprintf(charptr1, 1+ptr-src, src);
newJob = xmalloc(sizeof(struct job));
/* Now parse and run the backticked command */
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
&& newJob->numProgs) {
pipe(pipefd);
runCommand(newJob, &njobList, 0, pipefd);
} }
checkJobs(jobList);
free(charptr1);
/* Clip out the the backticked command from the string */ /* Copy the output from the backtick-ed command into the
memmove(--src, ptr, strlen(ptr)+1); * command line, making extra room as needed */
free(newcmd); --src;
charptr1 = xmalloc(BUFSIZ);
while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) {
int newSize=src - *commandPtr + size + 1 + strlen(charptr2);
if (newSize > BUFSIZ) {
*commandPtr=realloc(*commandPtr, src - *commandPtr +
size + 1 + strlen(charptr2));
}
memcpy(src, charptr1, size);
src+=size;
}
free(charptr1);
close(pipefd[0]);
if (*(src-1)=='\n')
--src;
/* Now paste into the *commandPtr all the stuff
* leftover after the second backtick */
memcpy(src, charptr2, strlen(charptr2));
fprintf(stderr,"*commandPtr='%s'\n", *commandPtr);
free(charptr2);
/* Now recursively call parseCommand to deal with the new
* and improved version of the command line with the backtick
* results expanded in place... */
return(parseCommand(commandPtr, job, jobList, isBg));
} }
break; break;
#endif // BB_FEATURE_SH_BACKTICKS
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -810,25 +860,23 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
} }
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
{ {
struct job *job; struct job *job;
int nextin=0, nextout, stdoutfd=fileno(stdout);
int i; int i;
int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
struct builtInCommand *x; struct builtInCommand *x;
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
const struct BB_applet *a = applets; const struct BB_applet *a = applets;
#endif #endif
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 {
nextout = 1; nextout = stdoutfd;
} }
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
@ -841,16 +889,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (!(newJob->progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (outPipe[1]!=-1) {
dup2(nextin, 0); close(outPipe[0]);
close(nextin); nextout = stdoutfd = outPipe[1];
}
if (nextout != 1) {
dup2(nextout, 1); dup2(nextout, 1);
dup2(nextout, 2);
close(nextout); close(nextout);
} }
//dup2(nextin, 0);
//close(nextin);
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob->progs + i); setupRedirections(newJob->progs + i);
@ -862,8 +911,8 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
/* Check if the command matches any busybox internal commands here */ /* Check if the command matches any busybox internal commands here */
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching on commands with paths appended (i.e. 'cat'
* works, but '/bin/cat' doesn't ) */ * currently 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;
@ -879,6 +928,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
fatalError("%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) {
close(outPipe[1]);
}
/* 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 */
@ -886,7 +938,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
if (nextout != 1) if (nextout != stdoutfd)
close(nextout); close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
@ -1007,9 +1059,12 @@ static int busy_loop(FILE * input)
if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(&newJob, &jobList, inBg); int pipefds[2] = {-1,-1};
runCommand(&newJob, &jobList, inBg, pipefds);
} else { } else {
nextCommand=NULL; nextCommand=NULL;
free(command);
command = (char *) calloc(BUFSIZ, sizeof(char));
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */

View File

@ -25,6 +25,11 @@
* *
*/ */
#define BB_FEATURE_SH_BACKTICKS
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -108,7 +113,7 @@ 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 *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, int outPipe[2]);
static int busy_loop(FILE * input); static int busy_loop(FILE * input);
@ -420,6 +425,10 @@ static void checkJobs(struct jobSet *jobList)
break; break;
} }
/* This happens on backticked commands */
if(job==NULL)
return;
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
/* child exited */ /* child exited */
job->runningProgs--; job->runningProgs--;
@ -697,7 +706,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*prog->argv[argc]) if (*prog->argv[argc])
argc++; argc++;
if (!argc) { if (!argc) {
errorMsg("empty command in pipe1\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -723,7 +732,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
src++; src++;
if (!*src) { if (!*src) {
errorMsg("empty command in pipe2\n"); errorMsg("empty command in pipe\n");
freeJob(job); freeJob(job);
job->numProgs=0; job->numProgs=0;
return 1; return 1;
@ -749,12 +758,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
if (*src == '*' || *src == '[' || *src == ']' if (*src == '*' || *src == '[' || *src == ']'
|| *src == '?') *buf++ = '\\'; || *src == '?') *buf++ = '\\';
/* fallthrough */ /* fallthrough */
#ifdef BB_FEATURE_SH_BACKTICKS
case '`': case '`':
/* Exec a backtick-ed command */ /* Exec a backtick-ed command */
{ {
char* newcmd=NULL; char* charptr1=NULL, *charptr2;
char* ptr=NULL; char* ptr=NULL;
struct job newJob; struct job *newJob;
struct jobSet njobList = { NULL, NULL };
int pipefd[2];
int size;
ptr=strchr(++src, '`'); ptr=strchr(++src, '`');
if (ptr==NULL) { if (ptr==NULL) {
@ -763,19 +776,56 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
return 1; return 1;
} }
newcmd = xmalloc(1+ptr-src); /* Make a copy of any stuff left over in the command
snprintf(newcmd, 1+ptr-src, src); * line after the second backtick */
charptr2 = xmalloc(strlen(ptr)+1);
memcpy(charptr2, ptr+1, strlen(ptr));
if (!parseCommand(&newcmd, &newJob, jobList, isBg) && /* Make some space to hold just the backticked command */
newJob.numProgs) { charptr1 = xmalloc(1+ptr-src);
runCommand(&newJob, jobList, *isBg); snprintf(charptr1, 1+ptr-src, src);
newJob = xmalloc(sizeof(struct job));
/* Now parse and run the backticked command */
if (!parseCommand(&charptr1, newJob, &njobList, isBg)
&& newJob->numProgs) {
pipe(pipefd);
runCommand(newJob, &njobList, 0, pipefd);
} }
checkJobs(jobList);
free(charptr1);
/* Clip out the the backticked command from the string */ /* Copy the output from the backtick-ed command into the
memmove(--src, ptr, strlen(ptr)+1); * command line, making extra room as needed */
free(newcmd); --src;
charptr1 = xmalloc(BUFSIZ);
while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) {
int newSize=src - *commandPtr + size + 1 + strlen(charptr2);
if (newSize > BUFSIZ) {
*commandPtr=realloc(*commandPtr, src - *commandPtr +
size + 1 + strlen(charptr2));
}
memcpy(src, charptr1, size);
src+=size;
}
free(charptr1);
close(pipefd[0]);
if (*(src-1)=='\n')
--src;
/* Now paste into the *commandPtr all the stuff
* leftover after the second backtick */
memcpy(src, charptr2, strlen(charptr2));
fprintf(stderr,"*commandPtr='%s'\n", *commandPtr);
free(charptr2);
/* Now recursively call parseCommand to deal with the new
* and improved version of the command line with the backtick
* results expanded in place... */
return(parseCommand(commandPtr, job, jobList, isBg));
} }
break; break;
#endif // BB_FEATURE_SH_BACKTICKS
default: default:
*buf++ = *src; *buf++ = *src;
} }
@ -810,25 +860,23 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
} }
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg) static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
{ {
struct job *job; struct job *job;
int nextin=0, nextout, stdoutfd=fileno(stdout);
int i; int i;
int nextin, nextout;
int pipefds[2]; /* pipefd[0] is for reading */ int pipefds[2]; /* pipefd[0] is for reading */
struct builtInCommand *x; struct builtInCommand *x;
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
const struct BB_applet *a = applets; const struct BB_applet *a = applets;
#endif #endif
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 {
nextout = 1; nextout = stdoutfd;
} }
/* Check if the command matches any non-forking builtins */ /* Check if the command matches any non-forking builtins */
@ -841,16 +889,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (!(newJob->progs[i].pid = fork())) { if (!(newJob->progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL); signal(SIGTTOU, SIG_DFL);
if (nextin != 0) { if (outPipe[1]!=-1) {
dup2(nextin, 0); close(outPipe[0]);
close(nextin); nextout = stdoutfd = outPipe[1];
}
if (nextout != 1) {
dup2(nextout, 1); dup2(nextout, 1);
dup2(nextout, 2);
close(nextout); close(nextout);
} }
//dup2(nextin, 0);
//close(nextin);
/* explicit redirections override pipes */ /* explicit redirections override pipes */
setupRedirections(newJob->progs + i); setupRedirections(newJob->progs + i);
@ -862,8 +911,8 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
} }
#ifdef BB_FEATURE_SH_STANDALONE_SHELL #ifdef BB_FEATURE_SH_STANDALONE_SHELL
/* Check if the command matches any busybox internal commands here */ /* Check if the command matches any busybox internal commands here */
/* TODO: Add matching when paths are appended (i.e. 'cat' currently /* TODO: Add matching on commands with paths appended (i.e. 'cat'
* works, but '/bin/cat' doesn't ) */ * currently 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;
@ -879,6 +928,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
fatalError("%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) {
close(outPipe[1]);
}
/* 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 */
@ -886,7 +938,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
if (nextin != 0) if (nextin != 0)
close(nextin); close(nextin);
if (nextout != 1) if (nextout != stdoutfd)
close(nextout); close(nextout);
/* If there isn't another process, nextin is garbage /* If there isn't another process, nextin is garbage
@ -1007,9 +1059,12 @@ static int busy_loop(FILE * input)
if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
newJob.numProgs) { newJob.numProgs) {
runCommand(&newJob, &jobList, inBg); int pipefds[2] = {-1,-1};
runCommand(&newJob, &jobList, inBg, pipefds);
} else { } else {
nextCommand=NULL; nextCommand=NULL;
free(command);
command = (char *) calloc(BUFSIZ, sizeof(char));
} }
} else { } else {
/* a job is running in the foreground; wait for it */ /* a job is running in the foreground; wait for it */