aboutsummaryrefslogtreecommitdiff
path: root/sh.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-07-17 19:14:41 +0000
committerEric Andersen <andersen@codepoet.org>2000-07-17 19:14:41 +0000
commita1d187a8a8a75cf36a45c8d6e0de86964eb2056f (patch)
tree94705b86b9a570bb1a97513bd8ec3e2e9f8466e5 /sh.c
parentbc0aed79a8c7bb24c32a21533893fdad660b7292 (diff)
downloadbusybox-w32-a1d187a8a8a75cf36a45c8d6e0de86964eb2056f.tar.gz
busybox-w32-a1d187a8a8a75cf36a45c8d6e0de86964eb2056f.tar.bz2
busybox-w32-a1d187a8a8a75cf36a45c8d6e0de86964eb2056f.zip
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
Diffstat (limited to 'sh.c')
-rw-r--r--sh.c115
1 files changed, 85 insertions, 30 deletions
diff --git a/sh.c b/sh.c
index 9b3435304..1dfce9e77 100644
--- a/sh.c
+++ b/sh.c
@@ -25,6 +25,11 @@
25 * 25 *
26 */ 26 */
27 27
28
29#define BB_FEATURE_SH_BACKTICKS
30
31
32
28#include "internal.h" 33#include "internal.h"
29#include <stdio.h> 34#include <stdio.h>
30#include <stdlib.h> 35#include <stdlib.h>
@@ -108,7 +113,7 @@ static void checkJobs(struct jobSet *jobList);
108static int getCommand(FILE * source, char *command); 113static int getCommand(FILE * source, char *command);
109static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); 114static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg);
110static int setupRedirections(struct childProgram *prog); 115static int setupRedirections(struct childProgram *prog);
111static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg); 116static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
112static int busy_loop(FILE * input); 117static int busy_loop(FILE * input);
113 118
114 119
@@ -420,6 +425,10 @@ static void checkJobs(struct jobSet *jobList)
420 break; 425 break;
421 } 426 }
422 427
428 /* This happens on backticked commands */
429 if(job==NULL)
430 return;
431
423 if (WIFEXITED(status) || WIFSIGNALED(status)) { 432 if (WIFEXITED(status) || WIFSIGNALED(status)) {
424 /* child exited */ 433 /* child exited */
425 job->runningProgs--; 434 job->runningProgs--;
@@ -697,7 +706,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
697 if (*prog->argv[argc]) 706 if (*prog->argv[argc])
698 argc++; 707 argc++;
699 if (!argc) { 708 if (!argc) {
700 errorMsg("empty command in pipe1\n"); 709 errorMsg("empty command in pipe\n");
701 freeJob(job); 710 freeJob(job);
702 job->numProgs=0; 711 job->numProgs=0;
703 return 1; 712 return 1;
@@ -723,7 +732,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
723 src++; 732 src++;
724 733
725 if (!*src) { 734 if (!*src) {
726 errorMsg("empty command in pipe2\n"); 735 errorMsg("empty command in pipe\n");
727 freeJob(job); 736 freeJob(job);
728 job->numProgs=0; 737 job->numProgs=0;
729 return 1; 738 return 1;
@@ -749,12 +758,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
749 if (*src == '*' || *src == '[' || *src == ']' 758 if (*src == '*' || *src == '[' || *src == ']'
750 || *src == '?') *buf++ = '\\'; 759 || *src == '?') *buf++ = '\\';
751 /* fallthrough */ 760 /* fallthrough */
761#ifdef BB_FEATURE_SH_BACKTICKS
752 case '`': 762 case '`':
753 /* Exec a backtick-ed command */ 763 /* Exec a backtick-ed command */
754 { 764 {
755 char* newcmd=NULL; 765 char* charptr1=NULL, *charptr2;
756 char* ptr=NULL; 766 char* ptr=NULL;
757 struct job newJob; 767 struct job *newJob;
768 struct jobSet njobList = { NULL, NULL };
769 int pipefd[2];
770 int size;
758 771
759 ptr=strchr(++src, '`'); 772 ptr=strchr(++src, '`');
760 if (ptr==NULL) { 773 if (ptr==NULL) {
@@ -763,19 +776,56 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
763 return 1; 776 return 1;
764 } 777 }
765 778
766 newcmd = xmalloc(1+ptr-src); 779 /* Make a copy of any stuff left over in the command
767 snprintf(newcmd, 1+ptr-src, src); 780 * line after the second backtick */
768 781 charptr2 = xmalloc(strlen(ptr)+1);
769 if (!parseCommand(&newcmd, &newJob, jobList, isBg) && 782 memcpy(charptr2, ptr+1, strlen(ptr));
770 newJob.numProgs) { 783
771 runCommand(&newJob, jobList, *isBg); 784 /* Make some space to hold just the backticked command */
785 charptr1 = xmalloc(1+ptr-src);
786 snprintf(charptr1, 1+ptr-src, src);
787 newJob = xmalloc(sizeof(struct job));
788 /* Now parse and run the backticked command */
789 if (!parseCommand(&charptr1, newJob, &njobList, isBg)
790 && newJob->numProgs) {
791 pipe(pipefd);
792 runCommand(newJob, &njobList, 0, pipefd);
772 } 793 }
773 794 checkJobs(jobList);
774 /* Clip out the the backticked command from the string */ 795 free(charptr1);
775 memmove(--src, ptr, strlen(ptr)+1); 796
776 free(newcmd); 797 /* Copy the output from the backtick-ed command into the
798 * command line, making extra room as needed */
799 --src;
800 charptr1 = xmalloc(BUFSIZ);
801 while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) {
802 int newSize=src - *commandPtr + size + 1 + strlen(charptr2);
803 if (newSize > BUFSIZ) {
804 *commandPtr=realloc(*commandPtr, src - *commandPtr +
805 size + 1 + strlen(charptr2));
806 }
807 memcpy(src, charptr1, size);
808 src+=size;
809 }
810 free(charptr1);
811 close(pipefd[0]);
812 if (*(src-1)=='\n')
813 --src;
814
815 /* Now paste into the *commandPtr all the stuff
816 * leftover after the second backtick */
817 memcpy(src, charptr2, strlen(charptr2));
818 fprintf(stderr,"*commandPtr='%s'\n", *commandPtr);
819 free(charptr2);
820
821
822 /* Now recursively call parseCommand to deal with the new
823 * and improved version of the command line with the backtick
824 * results expanded in place... */
825 return(parseCommand(commandPtr, job, jobList, isBg));
777 } 826 }
778 break; 827 break;
828#endif // BB_FEATURE_SH_BACKTICKS
779 default: 829 default:
780 *buf++ = *src; 830 *buf++ = *src;
781 } 831 }
@@ -810,25 +860,23 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
810} 860}
811 861
812 862
813static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg) 863static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
814{ 864{
815 struct job *job; 865 struct job *job;
866 int nextin=0, nextout, stdoutfd=fileno(stdout);
816 int i; 867 int i;
817 int nextin, nextout;
818 int pipefds[2]; /* pipefd[0] is for reading */ 868 int pipefds[2]; /* pipefd[0] is for reading */
819 struct builtInCommand *x; 869 struct builtInCommand *x;
820#ifdef BB_FEATURE_SH_STANDALONE_SHELL 870#ifdef BB_FEATURE_SH_STANDALONE_SHELL
821 const struct BB_applet *a = applets; 871 const struct BB_applet *a = applets;
822#endif 872#endif
823 873
824
825 nextin = 0, nextout = 1;
826 for (i = 0; i < newJob->numProgs; i++) { 874 for (i = 0; i < newJob->numProgs; i++) {
827 if ((i + 1) < newJob->numProgs) { 875 if ((i + 1) < newJob->numProgs) {
828 pipe(pipefds); 876 pipe(pipefds);
829 nextout = pipefds[1]; 877 nextout = pipefds[1];
830 } else { 878 } else {
831 nextout = 1; 879 nextout = stdoutfd;
832 } 880 }
833 881
834 /* Check if the command matches any non-forking builtins */ 882 /* Check if the command matches any non-forking builtins */
@@ -841,16 +889,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
841 if (!(newJob->progs[i].pid = fork())) { 889 if (!(newJob->progs[i].pid = fork())) {
842 signal(SIGTTOU, SIG_DFL); 890 signal(SIGTTOU, SIG_DFL);
843 891
844 if (nextin != 0) { 892 if (outPipe[1]!=-1) {
845 dup2(nextin, 0); 893 close(outPipe[0]);
846 close(nextin); 894 nextout = stdoutfd = outPipe[1];
847 }
848
849 if (nextout != 1) {
850 dup2(nextout, 1); 895 dup2(nextout, 1);
896 dup2(nextout, 2);
851 close(nextout); 897 close(nextout);
852 } 898 }
853 899
900 //dup2(nextin, 0);
901 //close(nextin);
902
854 /* explicit redirections override pipes */ 903 /* explicit redirections override pipes */
855 setupRedirections(newJob->progs + i); 904 setupRedirections(newJob->progs + i);
856 905
@@ -862,8 +911,8 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
862 } 911 }
863#ifdef BB_FEATURE_SH_STANDALONE_SHELL 912#ifdef BB_FEATURE_SH_STANDALONE_SHELL
864 /* Check if the command matches any busybox internal commands here */ 913 /* Check if the command matches any busybox internal commands here */
865 /* TODO: Add matching when paths are appended (i.e. 'cat' currently 914 /* TODO: Add matching on commands with paths appended (i.e. 'cat'
866 * works, but '/bin/cat' doesn't ) */ 915 * currently works, but '/bin/cat' doesn't ) */
867 while (a->name != 0) { 916 while (a->name != 0) {
868 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { 917 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
869 int argc; 918 int argc;
@@ -879,6 +928,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
879 fatalError("%s: %s\n", newJob->progs[i].argv[0], 928 fatalError("%s: %s\n", newJob->progs[i].argv[0],
880 strerror(errno)); 929 strerror(errno));
881 } 930 }
931 if (outPipe[1]!=-1) {
932 close(outPipe[1]);
933 }
882 934
883 /* put our child in the process group whose leader is the 935 /* put our child in the process group whose leader is the
884 first process in this pipe */ 936 first process in this pipe */
@@ -886,7 +938,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg)
886 938
887 if (nextin != 0) 939 if (nextin != 0)
888 close(nextin); 940 close(nextin);
889 if (nextout != 1) 941 if (nextout != stdoutfd)
890 close(nextout); 942 close(nextout);
891 943
892 /* If there isn't another process, nextin is garbage 944 /* If there isn't another process, nextin is garbage
@@ -1007,9 +1059,12 @@ static int busy_loop(FILE * input)
1007 1059
1008 if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && 1060 if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) &&
1009 newJob.numProgs) { 1061 newJob.numProgs) {
1010 runCommand(&newJob, &jobList, inBg); 1062 int pipefds[2] = {-1,-1};
1063 runCommand(&newJob, &jobList, inBg, pipefds);
1011 } else { 1064 } else {
1012 nextCommand=NULL; 1065 nextCommand=NULL;
1066 free(command);
1067 command = (char *) calloc(BUFSIZ, sizeof(char));
1013 } 1068 }
1014 } else { 1069 } else {
1015 /* a job is running in the foreground; wait for it */ 1070 /* a job is running in the foreground; wait for it */