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:
parent
bc0aed79a8
commit
a1d187a8a8
111
lash.c
111
lash.c
@ -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
111
sh.c
@ -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
shell/lash.c
111
shell/lash.c
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user