aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-03-08 17:17:13 +0000
committerEric Andersen <andersen@codepoet.org>2001-03-08 17:17:13 +0000
commitca6045955d8e51b268e242f59f3b63b9fdcf90e6 (patch)
tree7114ee07aff93918d343d2b4afb156b6413cf9ca
parente2c44fc966d30ba719dcf3bc65c60f275ee7d8a4 (diff)
downloadbusybox-w32-ca6045955d8e51b268e242f59f3b63b9fdcf90e6.tar.gz
busybox-w32-ca6045955d8e51b268e242f59f3b63b9fdcf90e6.tar.bz2
busybox-w32-ca6045955d8e51b268e242f59f3b63b9fdcf90e6.zip
Rework environment variable handling to use wordexp, per a suggestion from
Larry Doolittle a couple of months ago. This makes the stuff-expansion in lash be ever so standards compliant. This change needs testing by everyone, but appears to be solid enough to let us close bug #1090. It works for me; however, please test this change! -Erik
-rw-r--r--lash.c191
-rw-r--r--sh.c191
-rw-r--r--shell/lash.c191
-rw-r--r--utility.c2
4 files changed, 250 insertions, 325 deletions
diff --git a/lash.c b/lash.c
index 150055bb1..874c0aca9 100644
--- a/lash.c
+++ b/lash.c
@@ -54,7 +54,7 @@
54#include <ctype.h> 54#include <ctype.h>
55#include <errno.h> 55#include <errno.h>
56#include <fcntl.h> 56#include <fcntl.h>
57#include <glob.h> 57#include <wordexp.h>
58#include <signal.h> 58#include <signal.h>
59#include <string.h> 59#include <string.h>
60#include <sys/ioctl.h> 60#include <sys/ioctl.h>
@@ -96,8 +96,6 @@ struct child_prog {
96 char **argv; /* program name and arguments */ 96 char **argv; /* program name and arguments */
97 int num_redirects; /* elements in redirection array */ 97 int num_redirects; /* elements in redirection array */
98 struct redir_struct *redirects; /* I/O redirects */ 98 struct redir_struct *redirects; /* I/O redirects */
99 glob_t glob_result; /* result of parameter globbing */
100 int free_glob; /* should we globfree(&glob_result)? */
101 int is_stopped; /* is the program currently running? */ 99 int is_stopped; /* is the program currently running? */
102 struct job *family; /* pointer back to the child's parent job */ 100 struct job *family; /* pointer back to the child's parent job */
103}; 101};
@@ -209,9 +207,9 @@ static int argc;
209static char **argv; 207static char **argv;
210static struct close_me *close_me_head; 208static struct close_me *close_me_head;
211#ifdef BB_FEATURE_SH_ENVIRONMENT 209#ifdef BB_FEATURE_SH_ENVIRONMENT
212static int last_bg_pid=-1; 210static int last_bg_pid;
213static int last_return_code=-1; 211static int last_return_code;
214static int show_x_trace=FALSE; 212static int show_x_trace;
215#endif 213#endif
216#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 214#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
217static char syntax_err[]="syntax error near unexpected token"; 215static char syntax_err[]="syntax error near unexpected token";
@@ -650,8 +648,6 @@ static void free_job(struct job *cmd)
650 free(cmd->progs[i].argv); 648 free(cmd->progs[i].argv);
651 if (cmd->progs[i].redirects) 649 if (cmd->progs[i].redirects)
652 free(cmd->progs[i].redirects); 650 free(cmd->progs[i].redirects);
653 if (cmd->progs[i].free_glob)
654 globfree(&cmd->progs[i].glob_result);
655 } 651 }
656 free(cmd->progs); 652 free(cmd->progs);
657 if (cmd->text) 653 if (cmd->text)
@@ -875,7 +871,7 @@ static int get_command(FILE * source, char *command)
875 } 871 }
876 872
877 /* remove trailing newline */ 873 /* remove trailing newline */
878 command[strlen(command) - 1] = '\0'; 874 chomp(command);
879 875
880 return 0; 876 return 0;
881} 877}
@@ -900,125 +896,102 @@ static char* itoa(register int i)
900 *--b = '-'; 896 *--b = '-';
901 return b; 897 return b;
902} 898}
903#endif 899#endif
904 900
905static void expand_argument(struct child_prog *prog, int *argcPtr, 901static int expand_arguments(char *command)
906 int *argv_alloced_ptr)
907{ 902{
908 int argc_l = *argcPtr; 903#ifdef BB_FEATURE_SH_ENVIRONMENT
909 int argv_alloced = *argv_alloced_ptr; 904 wordexp_t wrdexp;
910 int rc;
911 int flags;
912 int i;
913 char *src, *dst, *var; 905 char *src, *dst, *var;
906 int i=0, length, total_length=0, retval;
907#endif
908
909 /* get rid of the terminating \n */
910 chomp(command);
914 911
915 if (argc_l > 1) { /* cmd->glob_result is already initialized */
916 flags = GLOB_APPEND;
917 i = prog->glob_result.gl_pathc;
918 } else {
919 prog->free_glob = 1;
920 flags = 0;
921 i = 0;
922 }
923#ifdef BB_FEATURE_SH_ENVIRONMENT 912#ifdef BB_FEATURE_SH_ENVIRONMENT
924 /* do shell variable substitution */ 913
925 src = prog->argv[argc_l - 1]; 914 /* This first part uses wordexp() which is a wonderful C lib
915 * function which expands nearly everything. */
916
917 retval = wordexp (command, &wrdexp, 0);
918
919 if (retval == WRDE_NOSPACE) {
920 /* Mem may have been allocated... */
921 wordfree (&wrdexp);
922 error_msg("out of space during expansion");
923 return FALSE;
924 }
925 if (retval < 0) {
926 /* Some other error. */
927 error_msg("syntax error");
928 return FALSE;
929 }
930
931 /* Convert from char** (one word per string) to a simple char*,
932 * but don't overflow command which is BUFSIZ in length */
933 *command = '\0';
934 while (i < wrdexp.we_wordc && total_length < BUFSIZ) {
935 length=strlen(wrdexp.we_wordv[i])+1;
936 if (BUFSIZ-total_length-length <= 0) {
937 error_msg("out of space during expansion");
938 return FALSE;
939 }
940 strcat(command+total_length, wrdexp.we_wordv[i++]);
941 strcat(command+total_length, " ");
942 total_length+=length;
943 }
944 wordfree (&wrdexp);
945
946
947 /* Now do the shell variable substitutions which
948 * wordexp can't do for us, namely $? and $! */
949 src = command;
926 while((dst = strchr(src,'$')) != NULL){ 950 while((dst = strchr(src,'$')) != NULL){
927 if (!(var = getenv(dst + 1))) { 951 if (!(var = getenv(dst + 1))) {
928 switch(*(dst+1)) { 952 switch(*(dst+1)) {
929 case '?': 953 case '?':
930 var = itoa(last_return_code); 954 var = itoa(last_return_code);
931 break; 955 break;
932 case '$':
933 var = itoa(getpid());
934 break;
935 case '#':
936 var = itoa(argc-1);
937 break;
938 case '!': 956 case '!':
939 if (last_bg_pid==-1) 957 if (last_bg_pid==-1)
940 *(var)='\0'; 958 *(var)='\0';
941 else 959 else
942 var = itoa(last_bg_pid); 960 var = itoa(last_bg_pid);
943 break; 961 break;
962#if 0
963 /* Everything else like $$, $#, $[0-9], etcshould all be
964 * expanded by wordexp(), so we can skip that stuff here */
965 case '$':
966 case '#':
944 case '0':case '1':case '2':case '3':case '4': 967 case '0':case '1':case '2':case '3':case '4':
945 case '5':case '6':case '7':case '8':case '9': 968 case '5':case '6':case '7':case '8':case '9':
946 {
947 int index=*(dst + 1)-48;
948 if (index >= argc) {
949 var='\0';
950 } else {
951 var = argv[index];
952 }
953 }
954 break; 969 break;
970#endif
955 } 971 }
956 } 972 }
957 if (var) { 973 if (var) {
958 int offset = dst-src; 974 int subst_len = strlen(var);
959#warning I have a memory leak which needs to be plugged somehow 975 char *next_dst;
960 src = (char*)xmalloc(strlen(src)-strlen(dst)+strlen(var)+1); 976 if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?")) == NULL) {
961 strncpy(src, prog->argv[argc_l -1], offset); 977 next_dst = dst;
962 safe_strncpy(src+offset, var, strlen(var)+1);
963 /* If there are any remaining $ variables in the src string, put them back */
964 if ((dst = strchr(prog->argv[argc_l -1]+offset+1,'$')) != NULL) {
965 offset=strlen(src);
966 safe_strncpy(src+strlen(src), dst, strlen(dst)+1);
967 } 978 }
968 prog->argv[argc_l -1] = src; 979 src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1);
969 } else { 980 /* Move stuff to the end of the string to accommodate filling
970 memset(dst, 0, strlen(src)-strlen(dst)); 981 * the created gap with the new stuff */
982 memmove(dst+subst_len, next_dst+1, subst_len);
983 /* Now copy in the new stuff */
984 strncpy(dst, var, subst_len);
971 } 985 }
986 src = dst;
987 src++;
972 } 988 }
973#endif
974 989
975 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 990
976 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result); 991
977 if (rc == GLOB_NOSPACE) { 992
978 error_msg("out of space during glob operation"); 993#endif
979 return; 994 return TRUE;
980 } else if (rc == GLOB_NOMATCH ||
981 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
982 strcmp(prog->argv[argc_l - 1],
983 prog->glob_result.gl_pathv[i]) == 0)) {
984 /* we need to remove whatever \ quoting is still present */
985 src = dst = prog->argv[argc_l - 1];
986 while (*src) {
987 if (*src == '\\') {
988 src++;
989 *dst++ = process_escape_sequence(&src);
990 } else {
991 *dst++ = *src;
992 src++;
993 }
994 }
995 *dst = '\0';
996 } else if (!rc) {
997 argv_alloced += (prog->glob_result.gl_pathc - i);
998 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
999 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
1000 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
1001 argc_l += (prog->glob_result.gl_pathc - i - 1);
1002 }
1003 }else{
1004 src = dst = prog->argv[argc_l - 1];
1005 while (*src) {
1006 if (*src == '\\') {
1007 src++;
1008 *dst++ = process_escape_sequence(&src);
1009 } else {
1010 *dst++ = *src;
1011 src++;
1012 }
1013 }
1014 *dst = '\0';
1015
1016 prog->glob_result.gl_pathc=0;
1017 if (flags==0)
1018 prog->glob_result.gl_pathv=NULL;
1019 }
1020 *argv_alloced_ptr = argv_alloced;
1021 *argcPtr = argc_l;
1022} 995}
1023 996
1024/* Return cmd->num_progs as 0 if no command is present (e.g. an empty 997/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
@@ -1066,7 +1039,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1066 prog = job->progs; 1039 prog = job->progs;
1067 prog->num_redirects = 0; 1040 prog->num_redirects = 0;
1068 prog->redirects = NULL; 1041 prog->redirects = NULL;
1069 prog->free_glob = 0;
1070 prog->is_stopped = 0; 1042 prog->is_stopped = 0;
1071 prog->family = job; 1043 prog->family = job;
1072 1044
@@ -1106,7 +1078,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1106 sizeof(*prog->argv) * 1078 sizeof(*prog->argv) *
1107 argv_alloced); 1079 argv_alloced);
1108 } 1080 }
1109 expand_argument(prog, &argc_l, &argv_alloced);
1110 prog->argv[argc_l] = buf; 1081 prog->argv[argc_l] = buf;
1111 } 1082 }
1112 } else 1083 } else
@@ -1139,7 +1110,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1139 1110
1140 if (*chptr && *prog->argv[argc_l]) { 1111 if (*chptr && *prog->argv[argc_l]) {
1141 buf++, argc_l++; 1112 buf++, argc_l++;
1142 expand_argument(prog, &argc_l, &argv_alloced);
1143 prog->argv[argc_l] = buf; 1113 prog->argv[argc_l] = buf;
1144 } 1114 }
1145 } 1115 }
@@ -1200,7 +1170,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1200 prog = job->progs + (job->num_progs - 1); 1170 prog = job->progs + (job->num_progs - 1);
1201 prog->num_redirects = 0; 1171 prog->num_redirects = 0;
1202 prog->redirects = NULL; 1172 prog->redirects = NULL;
1203 prog->free_glob = 0;
1204 prog->is_stopped = 0; 1173 prog->is_stopped = 0;
1205 prog->family = job; 1174 prog->family = job;
1206 argc_l = 0; 1175 argc_l = 0;
@@ -1356,7 +1325,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1356 1325
1357 if (*prog->argv[argc_l]) { 1326 if (*prog->argv[argc_l]) {
1358 argc_l++; 1327 argc_l++;
1359 expand_argument(prog, &argc_l, &argv_alloced);
1360 } 1328 }
1361 if (!argc_l) { 1329 if (!argc_l) {
1362 free_job(job); 1330 free_job(job);
@@ -1624,6 +1592,13 @@ static int busy_loop(FILE * input)
1624 next_command = command; 1592 next_command = command;
1625 } 1593 }
1626 1594
1595 if (expand_arguments(next_command) == FALSE) {
1596 free(command);
1597 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1598 next_command = NULL;
1599 continue;
1600 }
1601
1627 if (!parse_command(&next_command, &newjob, &inbg) && 1602 if (!parse_command(&next_command, &newjob, &inbg) &&
1628 newjob.num_progs) { 1603 newjob.num_progs) {
1629 int pipefds[2] = {-1,-1}; 1604 int pipefds[2] = {-1,-1};
@@ -1723,8 +1698,8 @@ int shell_main(int argc_l, char **argv_l)
1723 job_list.head = NULL; 1698 job_list.head = NULL;
1724 job_list.fg = NULL; 1699 job_list.fg = NULL;
1725#ifdef BB_FEATURE_SH_ENVIRONMENT 1700#ifdef BB_FEATURE_SH_ENVIRONMENT
1726 last_bg_pid=-1; 1701 last_bg_pid=1;
1727 last_return_code=-1; 1702 last_return_code=1;
1728 show_x_trace=FALSE; 1703 show_x_trace=FALSE;
1729#endif 1704#endif
1730 1705
diff --git a/sh.c b/sh.c
index 150055bb1..874c0aca9 100644
--- a/sh.c
+++ b/sh.c
@@ -54,7 +54,7 @@
54#include <ctype.h> 54#include <ctype.h>
55#include <errno.h> 55#include <errno.h>
56#include <fcntl.h> 56#include <fcntl.h>
57#include <glob.h> 57#include <wordexp.h>
58#include <signal.h> 58#include <signal.h>
59#include <string.h> 59#include <string.h>
60#include <sys/ioctl.h> 60#include <sys/ioctl.h>
@@ -96,8 +96,6 @@ struct child_prog {
96 char **argv; /* program name and arguments */ 96 char **argv; /* program name and arguments */
97 int num_redirects; /* elements in redirection array */ 97 int num_redirects; /* elements in redirection array */
98 struct redir_struct *redirects; /* I/O redirects */ 98 struct redir_struct *redirects; /* I/O redirects */
99 glob_t glob_result; /* result of parameter globbing */
100 int free_glob; /* should we globfree(&glob_result)? */
101 int is_stopped; /* is the program currently running? */ 99 int is_stopped; /* is the program currently running? */
102 struct job *family; /* pointer back to the child's parent job */ 100 struct job *family; /* pointer back to the child's parent job */
103}; 101};
@@ -209,9 +207,9 @@ static int argc;
209static char **argv; 207static char **argv;
210static struct close_me *close_me_head; 208static struct close_me *close_me_head;
211#ifdef BB_FEATURE_SH_ENVIRONMENT 209#ifdef BB_FEATURE_SH_ENVIRONMENT
212static int last_bg_pid=-1; 210static int last_bg_pid;
213static int last_return_code=-1; 211static int last_return_code;
214static int show_x_trace=FALSE; 212static int show_x_trace;
215#endif 213#endif
216#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 214#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
217static char syntax_err[]="syntax error near unexpected token"; 215static char syntax_err[]="syntax error near unexpected token";
@@ -650,8 +648,6 @@ static void free_job(struct job *cmd)
650 free(cmd->progs[i].argv); 648 free(cmd->progs[i].argv);
651 if (cmd->progs[i].redirects) 649 if (cmd->progs[i].redirects)
652 free(cmd->progs[i].redirects); 650 free(cmd->progs[i].redirects);
653 if (cmd->progs[i].free_glob)
654 globfree(&cmd->progs[i].glob_result);
655 } 651 }
656 free(cmd->progs); 652 free(cmd->progs);
657 if (cmd->text) 653 if (cmd->text)
@@ -875,7 +871,7 @@ static int get_command(FILE * source, char *command)
875 } 871 }
876 872
877 /* remove trailing newline */ 873 /* remove trailing newline */
878 command[strlen(command) - 1] = '\0'; 874 chomp(command);
879 875
880 return 0; 876 return 0;
881} 877}
@@ -900,125 +896,102 @@ static char* itoa(register int i)
900 *--b = '-'; 896 *--b = '-';
901 return b; 897 return b;
902} 898}
903#endif 899#endif
904 900
905static void expand_argument(struct child_prog *prog, int *argcPtr, 901static int expand_arguments(char *command)
906 int *argv_alloced_ptr)
907{ 902{
908 int argc_l = *argcPtr; 903#ifdef BB_FEATURE_SH_ENVIRONMENT
909 int argv_alloced = *argv_alloced_ptr; 904 wordexp_t wrdexp;
910 int rc;
911 int flags;
912 int i;
913 char *src, *dst, *var; 905 char *src, *dst, *var;
906 int i=0, length, total_length=0, retval;
907#endif
908
909 /* get rid of the terminating \n */
910 chomp(command);
914 911
915 if (argc_l > 1) { /* cmd->glob_result is already initialized */
916 flags = GLOB_APPEND;
917 i = prog->glob_result.gl_pathc;
918 } else {
919 prog->free_glob = 1;
920 flags = 0;
921 i = 0;
922 }
923#ifdef BB_FEATURE_SH_ENVIRONMENT 912#ifdef BB_FEATURE_SH_ENVIRONMENT
924 /* do shell variable substitution */ 913
925 src = prog->argv[argc_l - 1]; 914 /* This first part uses wordexp() which is a wonderful C lib
915 * function which expands nearly everything. */
916
917 retval = wordexp (command, &wrdexp, 0);
918
919 if (retval == WRDE_NOSPACE) {
920 /* Mem may have been allocated... */
921 wordfree (&wrdexp);
922 error_msg("out of space during expansion");
923 return FALSE;
924 }
925 if (retval < 0) {
926 /* Some other error. */
927 error_msg("syntax error");
928 return FALSE;
929 }
930
931 /* Convert from char** (one word per string) to a simple char*,
932 * but don't overflow command which is BUFSIZ in length */
933 *command = '\0';
934 while (i < wrdexp.we_wordc && total_length < BUFSIZ) {
935 length=strlen(wrdexp.we_wordv[i])+1;
936 if (BUFSIZ-total_length-length <= 0) {
937 error_msg("out of space during expansion");
938 return FALSE;
939 }
940 strcat(command+total_length, wrdexp.we_wordv[i++]);
941 strcat(command+total_length, " ");
942 total_length+=length;
943 }
944 wordfree (&wrdexp);
945
946
947 /* Now do the shell variable substitutions which
948 * wordexp can't do for us, namely $? and $! */
949 src = command;
926 while((dst = strchr(src,'$')) != NULL){ 950 while((dst = strchr(src,'$')) != NULL){
927 if (!(var = getenv(dst + 1))) { 951 if (!(var = getenv(dst + 1))) {
928 switch(*(dst+1)) { 952 switch(*(dst+1)) {
929 case '?': 953 case '?':
930 var = itoa(last_return_code); 954 var = itoa(last_return_code);
931 break; 955 break;
932 case '$':
933 var = itoa(getpid());
934 break;
935 case '#':
936 var = itoa(argc-1);
937 break;
938 case '!': 956 case '!':
939 if (last_bg_pid==-1) 957 if (last_bg_pid==-1)
940 *(var)='\0'; 958 *(var)='\0';
941 else 959 else
942 var = itoa(last_bg_pid); 960 var = itoa(last_bg_pid);
943 break; 961 break;
962#if 0
963 /* Everything else like $$, $#, $[0-9], etcshould all be
964 * expanded by wordexp(), so we can skip that stuff here */
965 case '$':
966 case '#':
944 case '0':case '1':case '2':case '3':case '4': 967 case '0':case '1':case '2':case '3':case '4':
945 case '5':case '6':case '7':case '8':case '9': 968 case '5':case '6':case '7':case '8':case '9':
946 {
947 int index=*(dst + 1)-48;
948 if (index >= argc) {
949 var='\0';
950 } else {
951 var = argv[index];
952 }
953 }
954 break; 969 break;
970#endif
955 } 971 }
956 } 972 }
957 if (var) { 973 if (var) {
958 int offset = dst-src; 974 int subst_len = strlen(var);
959#warning I have a memory leak which needs to be plugged somehow 975 char *next_dst;
960 src = (char*)xmalloc(strlen(src)-strlen(dst)+strlen(var)+1); 976 if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?")) == NULL) {
961 strncpy(src, prog->argv[argc_l -1], offset); 977 next_dst = dst;
962 safe_strncpy(src+offset, var, strlen(var)+1);
963 /* If there are any remaining $ variables in the src string, put them back */
964 if ((dst = strchr(prog->argv[argc_l -1]+offset+1,'$')) != NULL) {
965 offset=strlen(src);
966 safe_strncpy(src+strlen(src), dst, strlen(dst)+1);
967 } 978 }
968 prog->argv[argc_l -1] = src; 979 src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1);
969 } else { 980 /* Move stuff to the end of the string to accommodate filling
970 memset(dst, 0, strlen(src)-strlen(dst)); 981 * the created gap with the new stuff */
982 memmove(dst+subst_len, next_dst+1, subst_len);
983 /* Now copy in the new stuff */
984 strncpy(dst, var, subst_len);
971 } 985 }
986 src = dst;
987 src++;
972 } 988 }
973#endif
974 989
975 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 990
976 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result); 991
977 if (rc == GLOB_NOSPACE) { 992
978 error_msg("out of space during glob operation"); 993#endif
979 return; 994 return TRUE;
980 } else if (rc == GLOB_NOMATCH ||
981 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
982 strcmp(prog->argv[argc_l - 1],
983 prog->glob_result.gl_pathv[i]) == 0)) {
984 /* we need to remove whatever \ quoting is still present */
985 src = dst = prog->argv[argc_l - 1];
986 while (*src) {
987 if (*src == '\\') {
988 src++;
989 *dst++ = process_escape_sequence(&src);
990 } else {
991 *dst++ = *src;
992 src++;
993 }
994 }
995 *dst = '\0';
996 } else if (!rc) {
997 argv_alloced += (prog->glob_result.gl_pathc - i);
998 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
999 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
1000 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
1001 argc_l += (prog->glob_result.gl_pathc - i - 1);
1002 }
1003 }else{
1004 src = dst = prog->argv[argc_l - 1];
1005 while (*src) {
1006 if (*src == '\\') {
1007 src++;
1008 *dst++ = process_escape_sequence(&src);
1009 } else {
1010 *dst++ = *src;
1011 src++;
1012 }
1013 }
1014 *dst = '\0';
1015
1016 prog->glob_result.gl_pathc=0;
1017 if (flags==0)
1018 prog->glob_result.gl_pathv=NULL;
1019 }
1020 *argv_alloced_ptr = argv_alloced;
1021 *argcPtr = argc_l;
1022} 995}
1023 996
1024/* Return cmd->num_progs as 0 if no command is present (e.g. an empty 997/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
@@ -1066,7 +1039,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1066 prog = job->progs; 1039 prog = job->progs;
1067 prog->num_redirects = 0; 1040 prog->num_redirects = 0;
1068 prog->redirects = NULL; 1041 prog->redirects = NULL;
1069 prog->free_glob = 0;
1070 prog->is_stopped = 0; 1042 prog->is_stopped = 0;
1071 prog->family = job; 1043 prog->family = job;
1072 1044
@@ -1106,7 +1078,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1106 sizeof(*prog->argv) * 1078 sizeof(*prog->argv) *
1107 argv_alloced); 1079 argv_alloced);
1108 } 1080 }
1109 expand_argument(prog, &argc_l, &argv_alloced);
1110 prog->argv[argc_l] = buf; 1081 prog->argv[argc_l] = buf;
1111 } 1082 }
1112 } else 1083 } else
@@ -1139,7 +1110,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1139 1110
1140 if (*chptr && *prog->argv[argc_l]) { 1111 if (*chptr && *prog->argv[argc_l]) {
1141 buf++, argc_l++; 1112 buf++, argc_l++;
1142 expand_argument(prog, &argc_l, &argv_alloced);
1143 prog->argv[argc_l] = buf; 1113 prog->argv[argc_l] = buf;
1144 } 1114 }
1145 } 1115 }
@@ -1200,7 +1170,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1200 prog = job->progs + (job->num_progs - 1); 1170 prog = job->progs + (job->num_progs - 1);
1201 prog->num_redirects = 0; 1171 prog->num_redirects = 0;
1202 prog->redirects = NULL; 1172 prog->redirects = NULL;
1203 prog->free_glob = 0;
1204 prog->is_stopped = 0; 1173 prog->is_stopped = 0;
1205 prog->family = job; 1174 prog->family = job;
1206 argc_l = 0; 1175 argc_l = 0;
@@ -1356,7 +1325,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1356 1325
1357 if (*prog->argv[argc_l]) { 1326 if (*prog->argv[argc_l]) {
1358 argc_l++; 1327 argc_l++;
1359 expand_argument(prog, &argc_l, &argv_alloced);
1360 } 1328 }
1361 if (!argc_l) { 1329 if (!argc_l) {
1362 free_job(job); 1330 free_job(job);
@@ -1624,6 +1592,13 @@ static int busy_loop(FILE * input)
1624 next_command = command; 1592 next_command = command;
1625 } 1593 }
1626 1594
1595 if (expand_arguments(next_command) == FALSE) {
1596 free(command);
1597 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1598 next_command = NULL;
1599 continue;
1600 }
1601
1627 if (!parse_command(&next_command, &newjob, &inbg) && 1602 if (!parse_command(&next_command, &newjob, &inbg) &&
1628 newjob.num_progs) { 1603 newjob.num_progs) {
1629 int pipefds[2] = {-1,-1}; 1604 int pipefds[2] = {-1,-1};
@@ -1723,8 +1698,8 @@ int shell_main(int argc_l, char **argv_l)
1723 job_list.head = NULL; 1698 job_list.head = NULL;
1724 job_list.fg = NULL; 1699 job_list.fg = NULL;
1725#ifdef BB_FEATURE_SH_ENVIRONMENT 1700#ifdef BB_FEATURE_SH_ENVIRONMENT
1726 last_bg_pid=-1; 1701 last_bg_pid=1;
1727 last_return_code=-1; 1702 last_return_code=1;
1728 show_x_trace=FALSE; 1703 show_x_trace=FALSE;
1729#endif 1704#endif
1730 1705
diff --git a/shell/lash.c b/shell/lash.c
index 150055bb1..874c0aca9 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -54,7 +54,7 @@
54#include <ctype.h> 54#include <ctype.h>
55#include <errno.h> 55#include <errno.h>
56#include <fcntl.h> 56#include <fcntl.h>
57#include <glob.h> 57#include <wordexp.h>
58#include <signal.h> 58#include <signal.h>
59#include <string.h> 59#include <string.h>
60#include <sys/ioctl.h> 60#include <sys/ioctl.h>
@@ -96,8 +96,6 @@ struct child_prog {
96 char **argv; /* program name and arguments */ 96 char **argv; /* program name and arguments */
97 int num_redirects; /* elements in redirection array */ 97 int num_redirects; /* elements in redirection array */
98 struct redir_struct *redirects; /* I/O redirects */ 98 struct redir_struct *redirects; /* I/O redirects */
99 glob_t glob_result; /* result of parameter globbing */
100 int free_glob; /* should we globfree(&glob_result)? */
101 int is_stopped; /* is the program currently running? */ 99 int is_stopped; /* is the program currently running? */
102 struct job *family; /* pointer back to the child's parent job */ 100 struct job *family; /* pointer back to the child's parent job */
103}; 101};
@@ -209,9 +207,9 @@ static int argc;
209static char **argv; 207static char **argv;
210static struct close_me *close_me_head; 208static struct close_me *close_me_head;
211#ifdef BB_FEATURE_SH_ENVIRONMENT 209#ifdef BB_FEATURE_SH_ENVIRONMENT
212static int last_bg_pid=-1; 210static int last_bg_pid;
213static int last_return_code=-1; 211static int last_return_code;
214static int show_x_trace=FALSE; 212static int show_x_trace;
215#endif 213#endif
216#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 214#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
217static char syntax_err[]="syntax error near unexpected token"; 215static char syntax_err[]="syntax error near unexpected token";
@@ -650,8 +648,6 @@ static void free_job(struct job *cmd)
650 free(cmd->progs[i].argv); 648 free(cmd->progs[i].argv);
651 if (cmd->progs[i].redirects) 649 if (cmd->progs[i].redirects)
652 free(cmd->progs[i].redirects); 650 free(cmd->progs[i].redirects);
653 if (cmd->progs[i].free_glob)
654 globfree(&cmd->progs[i].glob_result);
655 } 651 }
656 free(cmd->progs); 652 free(cmd->progs);
657 if (cmd->text) 653 if (cmd->text)
@@ -875,7 +871,7 @@ static int get_command(FILE * source, char *command)
875 } 871 }
876 872
877 /* remove trailing newline */ 873 /* remove trailing newline */
878 command[strlen(command) - 1] = '\0'; 874 chomp(command);
879 875
880 return 0; 876 return 0;
881} 877}
@@ -900,125 +896,102 @@ static char* itoa(register int i)
900 *--b = '-'; 896 *--b = '-';
901 return b; 897 return b;
902} 898}
903#endif 899#endif
904 900
905static void expand_argument(struct child_prog *prog, int *argcPtr, 901static int expand_arguments(char *command)
906 int *argv_alloced_ptr)
907{ 902{
908 int argc_l = *argcPtr; 903#ifdef BB_FEATURE_SH_ENVIRONMENT
909 int argv_alloced = *argv_alloced_ptr; 904 wordexp_t wrdexp;
910 int rc;
911 int flags;
912 int i;
913 char *src, *dst, *var; 905 char *src, *dst, *var;
906 int i=0, length, total_length=0, retval;
907#endif
908
909 /* get rid of the terminating \n */
910 chomp(command);
914 911
915 if (argc_l > 1) { /* cmd->glob_result is already initialized */
916 flags = GLOB_APPEND;
917 i = prog->glob_result.gl_pathc;
918 } else {
919 prog->free_glob = 1;
920 flags = 0;
921 i = 0;
922 }
923#ifdef BB_FEATURE_SH_ENVIRONMENT 912#ifdef BB_FEATURE_SH_ENVIRONMENT
924 /* do shell variable substitution */ 913
925 src = prog->argv[argc_l - 1]; 914 /* This first part uses wordexp() which is a wonderful C lib
915 * function which expands nearly everything. */
916
917 retval = wordexp (command, &wrdexp, 0);
918
919 if (retval == WRDE_NOSPACE) {
920 /* Mem may have been allocated... */
921 wordfree (&wrdexp);
922 error_msg("out of space during expansion");
923 return FALSE;
924 }
925 if (retval < 0) {
926 /* Some other error. */
927 error_msg("syntax error");
928 return FALSE;
929 }
930
931 /* Convert from char** (one word per string) to a simple char*,
932 * but don't overflow command which is BUFSIZ in length */
933 *command = '\0';
934 while (i < wrdexp.we_wordc && total_length < BUFSIZ) {
935 length=strlen(wrdexp.we_wordv[i])+1;
936 if (BUFSIZ-total_length-length <= 0) {
937 error_msg("out of space during expansion");
938 return FALSE;
939 }
940 strcat(command+total_length, wrdexp.we_wordv[i++]);
941 strcat(command+total_length, " ");
942 total_length+=length;
943 }
944 wordfree (&wrdexp);
945
946
947 /* Now do the shell variable substitutions which
948 * wordexp can't do for us, namely $? and $! */
949 src = command;
926 while((dst = strchr(src,'$')) != NULL){ 950 while((dst = strchr(src,'$')) != NULL){
927 if (!(var = getenv(dst + 1))) { 951 if (!(var = getenv(dst + 1))) {
928 switch(*(dst+1)) { 952 switch(*(dst+1)) {
929 case '?': 953 case '?':
930 var = itoa(last_return_code); 954 var = itoa(last_return_code);
931 break; 955 break;
932 case '$':
933 var = itoa(getpid());
934 break;
935 case '#':
936 var = itoa(argc-1);
937 break;
938 case '!': 956 case '!':
939 if (last_bg_pid==-1) 957 if (last_bg_pid==-1)
940 *(var)='\0'; 958 *(var)='\0';
941 else 959 else
942 var = itoa(last_bg_pid); 960 var = itoa(last_bg_pid);
943 break; 961 break;
962#if 0
963 /* Everything else like $$, $#, $[0-9], etcshould all be
964 * expanded by wordexp(), so we can skip that stuff here */
965 case '$':
966 case '#':
944 case '0':case '1':case '2':case '3':case '4': 967 case '0':case '1':case '2':case '3':case '4':
945 case '5':case '6':case '7':case '8':case '9': 968 case '5':case '6':case '7':case '8':case '9':
946 {
947 int index=*(dst + 1)-48;
948 if (index >= argc) {
949 var='\0';
950 } else {
951 var = argv[index];
952 }
953 }
954 break; 969 break;
970#endif
955 } 971 }
956 } 972 }
957 if (var) { 973 if (var) {
958 int offset = dst-src; 974 int subst_len = strlen(var);
959#warning I have a memory leak which needs to be plugged somehow 975 char *next_dst;
960 src = (char*)xmalloc(strlen(src)-strlen(dst)+strlen(var)+1); 976 if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?")) == NULL) {
961 strncpy(src, prog->argv[argc_l -1], offset); 977 next_dst = dst;
962 safe_strncpy(src+offset, var, strlen(var)+1);
963 /* If there are any remaining $ variables in the src string, put them back */
964 if ((dst = strchr(prog->argv[argc_l -1]+offset+1,'$')) != NULL) {
965 offset=strlen(src);
966 safe_strncpy(src+strlen(src), dst, strlen(dst)+1);
967 } 978 }
968 prog->argv[argc_l -1] = src; 979 src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1);
969 } else { 980 /* Move stuff to the end of the string to accommodate filling
970 memset(dst, 0, strlen(src)-strlen(dst)); 981 * the created gap with the new stuff */
982 memmove(dst+subst_len, next_dst+1, subst_len);
983 /* Now copy in the new stuff */
984 strncpy(dst, var, subst_len);
971 } 985 }
986 src = dst;
987 src++;
972 } 988 }
973#endif
974 989
975 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 990
976 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result); 991
977 if (rc == GLOB_NOSPACE) { 992
978 error_msg("out of space during glob operation"); 993#endif
979 return; 994 return TRUE;
980 } else if (rc == GLOB_NOMATCH ||
981 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
982 strcmp(prog->argv[argc_l - 1],
983 prog->glob_result.gl_pathv[i]) == 0)) {
984 /* we need to remove whatever \ quoting is still present */
985 src = dst = prog->argv[argc_l - 1];
986 while (*src) {
987 if (*src == '\\') {
988 src++;
989 *dst++ = process_escape_sequence(&src);
990 } else {
991 *dst++ = *src;
992 src++;
993 }
994 }
995 *dst = '\0';
996 } else if (!rc) {
997 argv_alloced += (prog->glob_result.gl_pathc - i);
998 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
999 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
1000 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
1001 argc_l += (prog->glob_result.gl_pathc - i - 1);
1002 }
1003 }else{
1004 src = dst = prog->argv[argc_l - 1];
1005 while (*src) {
1006 if (*src == '\\') {
1007 src++;
1008 *dst++ = process_escape_sequence(&src);
1009 } else {
1010 *dst++ = *src;
1011 src++;
1012 }
1013 }
1014 *dst = '\0';
1015
1016 prog->glob_result.gl_pathc=0;
1017 if (flags==0)
1018 prog->glob_result.gl_pathv=NULL;
1019 }
1020 *argv_alloced_ptr = argv_alloced;
1021 *argcPtr = argc_l;
1022} 995}
1023 996
1024/* Return cmd->num_progs as 0 if no command is present (e.g. an empty 997/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
@@ -1066,7 +1039,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1066 prog = job->progs; 1039 prog = job->progs;
1067 prog->num_redirects = 0; 1040 prog->num_redirects = 0;
1068 prog->redirects = NULL; 1041 prog->redirects = NULL;
1069 prog->free_glob = 0;
1070 prog->is_stopped = 0; 1042 prog->is_stopped = 0;
1071 prog->family = job; 1043 prog->family = job;
1072 1044
@@ -1106,7 +1078,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1106 sizeof(*prog->argv) * 1078 sizeof(*prog->argv) *
1107 argv_alloced); 1079 argv_alloced);
1108 } 1080 }
1109 expand_argument(prog, &argc_l, &argv_alloced);
1110 prog->argv[argc_l] = buf; 1081 prog->argv[argc_l] = buf;
1111 } 1082 }
1112 } else 1083 } else
@@ -1139,7 +1110,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1139 1110
1140 if (*chptr && *prog->argv[argc_l]) { 1111 if (*chptr && *prog->argv[argc_l]) {
1141 buf++, argc_l++; 1112 buf++, argc_l++;
1142 expand_argument(prog, &argc_l, &argv_alloced);
1143 prog->argv[argc_l] = buf; 1113 prog->argv[argc_l] = buf;
1144 } 1114 }
1145 } 1115 }
@@ -1200,7 +1170,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1200 prog = job->progs + (job->num_progs - 1); 1170 prog = job->progs + (job->num_progs - 1);
1201 prog->num_redirects = 0; 1171 prog->num_redirects = 0;
1202 prog->redirects = NULL; 1172 prog->redirects = NULL;
1203 prog->free_glob = 0;
1204 prog->is_stopped = 0; 1173 prog->is_stopped = 0;
1205 prog->family = job; 1174 prog->family = job;
1206 argc_l = 0; 1175 argc_l = 0;
@@ -1356,7 +1325,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
1356 1325
1357 if (*prog->argv[argc_l]) { 1326 if (*prog->argv[argc_l]) {
1358 argc_l++; 1327 argc_l++;
1359 expand_argument(prog, &argc_l, &argv_alloced);
1360 } 1328 }
1361 if (!argc_l) { 1329 if (!argc_l) {
1362 free_job(job); 1330 free_job(job);
@@ -1624,6 +1592,13 @@ static int busy_loop(FILE * input)
1624 next_command = command; 1592 next_command = command;
1625 } 1593 }
1626 1594
1595 if (expand_arguments(next_command) == FALSE) {
1596 free(command);
1597 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1598 next_command = NULL;
1599 continue;
1600 }
1601
1627 if (!parse_command(&next_command, &newjob, &inbg) && 1602 if (!parse_command(&next_command, &newjob, &inbg) &&
1628 newjob.num_progs) { 1603 newjob.num_progs) {
1629 int pipefds[2] = {-1,-1}; 1604 int pipefds[2] = {-1,-1};
@@ -1723,8 +1698,8 @@ int shell_main(int argc_l, char **argv_l)
1723 job_list.head = NULL; 1698 job_list.head = NULL;
1724 job_list.fg = NULL; 1699 job_list.fg = NULL;
1725#ifdef BB_FEATURE_SH_ENVIRONMENT 1700#ifdef BB_FEATURE_SH_ENVIRONMENT
1726 last_bg_pid=-1; 1701 last_bg_pid=1;
1727 last_return_code=-1; 1702 last_return_code=1;
1728 show_x_trace=FALSE; 1703 show_x_trace=FALSE;
1729#endif 1704#endif
1730 1705
diff --git a/utility.c b/utility.c
index 140480bdd..7fd4cad7d 100644
--- a/utility.c
+++ b/utility.c
@@ -1815,7 +1815,7 @@ const char *make_human_readable_str(unsigned long val, unsigned long hr)
1815} 1815}
1816#endif 1816#endif
1817 1817
1818#if defined(BB_GREP) || defined(BB_HOSTNAME) || defined(BB_SED) || defined(BB_TAR) || defined(BB_WGET) || defined(BB_XARGS) 1818#if defined(BB_GREP) || defined(BB_HOSTNAME) || defined(BB_SED) || defined(BB_TAR) || defined(BB_WGET) || defined(BB_XARGS) || defined(BB_SH)
1819void chomp(char *s) 1819void chomp(char *s)
1820{ 1820{
1821 size_t len = strlen(s); 1821 size_t len = strlen(s);