#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <wordexp.h>
#include <signal.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <getopt.h>
+
+//#undef __GLIBC__
+//#undef __UCLIBC__
+
+#if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__)
+#include <wordexp.h>
+#define expand_t wordexp_t
+#undef BB_FEATURE_SH_BACKTICKS
+#else
+#include <glob.h>
+#define expand_t glob_t
+#endif
#include "busybox.h"
#include "cmdedit.h"
+
static const int MAX_LINE = 256; /* size of input buffer for cwd data */
static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
static int expand_arguments(char *command)
{
#ifdef BB_FEATURE_SH_ENVIRONMENT
- wordexp_t wrdexp;
+ expand_t expand_result;
char *src, *dst, *var;
int i=0, length, total_length=0, retval;
+ const char *out_of_space = "out of space during expansion";
#endif
/* get rid of the terminating \n */
#ifdef BB_FEATURE_SH_ENVIRONMENT
+
+#if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__)
/* This first part uses wordexp() which is a wonderful C lib
* function which expands nearly everything. */
-
- retval = wordexp (command, &wrdexp, 0);
-
+ retval = wordexp (command, &expand_result, 0);
if (retval == WRDE_NOSPACE) {
/* Mem may have been allocated... */
- wordfree (&wrdexp);
- error_msg("out of space during expansion");
+ wordfree (&expand_result);
+ error_msg(out_of_space);
return FALSE;
}
if (retval < 0) {
/* Convert from char** (one word per string) to a simple char*,
* but don't overflow command which is BUFSIZ in length */
*command = '\0';
- while (i < wrdexp.we_wordc && total_length < BUFSIZ) {
- length=strlen(wrdexp.we_wordv[i])+1;
+ while (i < expand_result.we_wordc && total_length < BUFSIZ) {
+ length=strlen(expand_result.we_wordv[i])+1;
if (BUFSIZ-total_length-length <= 0) {
- error_msg("out of space during expansion");
+ error_msg(out_of_space);
return FALSE;
}
- strcat(command+total_length, wrdexp.we_wordv[i++]);
+ strcat(command+total_length, expand_result.we_wordv[i++]);
strcat(command+total_length, " ");
total_length+=length;
}
- wordfree (&wrdexp);
-
+ wordfree (&expand_result);
+#else
+
+ /* Ok. They don't have a recent glibc and they don't have uClibc. Chances
+ * are about 100% they don't have wordexp(). So instead the best we can do
+ * is use glob and then fixup environment variables and such ourselves.
+ * This is better then nothing, but certainly not perfect */
+
+ /* It turns out that glob is very stupid. We have to feed it one word at a
+ * time since it can't cope with a full string. Here we convert command
+ * (char*) into cmd (char**, one word per string) */
+ {
+
+ int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE;
+ char * tmpcmd;
+ /* We need a clean copy, so strsep can mess up the copy while
+ * we write stuff into the original (in a minute) */
+ char * cmd = strdup(command);
+ *command = '\0';
+ for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) {
+ if (*tmpcmd == '\0')
+ break;
+ retval = glob(tmpcmd, flags, NULL, &expand_result);
+ if (retval == GLOB_NOSPACE) {
+ /* Mem may have been allocated... */
+ globfree (&expand_result);
+ error_msg(out_of_space);
+ return FALSE;
+ } else if (retval != 0) {
+ /* Some other error. GLOB_NOMATCH shouldn't
+ * happen because of the GLOB_NOCHECK flag in
+ * the glob call. */
+ error_msg("syntax error");
+ return FALSE;
+ } else {
+ /* Convert from char** (one word per string) to a simple char*,
+ * but don't overflow command which is BUFSIZ in length */
+ for (i=0; i < expand_result.gl_pathc; i++) {
+ length=strlen(expand_result.gl_pathv[i])+1;
+ if (BUFSIZ-total_length-length <= 0) {
+ error_msg(out_of_space);
+ return FALSE;
+ }
+ strcat(command+total_length, expand_result.gl_pathv[i]);
+ strcat(command+total_length, " ");
+ total_length+=length;
+ }
+ globfree (&expand_result);
+ }
+ }
+ free(cmd);
+ trim(command);
+ }
+#endif
+
/* Now do the shell variable substitutions which
* wordexp can't do for us, namely $? and $! */
src = command;
while((dst = strchr(src,'$')) != NULL){
- if (!(var = getenv(dst + 1))) {
- switch(*(dst+1)) {
- case '?':
- var = itoa(last_return_code);
- break;
- case '!':
- if (last_bg_pid==-1)
- *(var)='\0';
- else
- var = itoa(last_bg_pid);
- break;
-#if 0
- /* Everything else like $$, $#, $[0-9], etcshould all be
- * expanded by wordexp(), so we can skip that stuff here */
- case '$':
- case '#':
- case '0':case '1':case '2':case '3':case '4':
- case '5':case '6':case '7':case '8':case '9':
- break;
-#endif
- }
+ var = NULL;
+ switch(*(dst+1)) {
+ case '?':
+ var = itoa(last_return_code);
+ break;
+ case '!':
+ if (last_bg_pid==-1)
+ *(var)='\0';
+ else
+ var = itoa(last_bg_pid);
+ break;
+ /* Everything else like $$, $#, $[0-9], etc should all be
+ * expanded by wordexp(), so we can in theory skip that stuff
+ * here, but just to be on the safe side (i.e. since uClibc
+ * wordexp doesn't do this stuff yet), lets leave it in for
+ * now. */
+ case '$':
+ var = itoa(getpid());
+ break;
+ case '#':
+ var = itoa(argc-1);
+ break;
+ case '0':case '1':case '2':case '3':case '4':
+ case '5':case '6':case '7':case '8':case '9':
+ {
+ int index=*(dst + 1)-48;
+ if (index >= argc) {
+ var='\0';
+ } else {
+ var = argv[index];
+ }
+ }
+ break;
+
}
if (var) {
+ /* a single character construction was found, and
+ * already handled in the case statement */
+ src=dst+2;
+ } else {
+ /* Looks like an environment variable */
+ char delim_hold;
+ int num_skip_chars=1;
+ int dstlen = strlen(dst);
+ /* Is this a ${foo} type variable? */
+ if (dstlen >=2 && *(dst+1) == '{') {
+ src=strchr(dst+1, '}');
+ num_skip_chars=2;
+ } else {
+ src=strpbrk(dst+1, " \t~`!$^&*()=|\\[];\"'<>?./");
+ }
+ if (src == NULL) {
+ src = dst+dstlen;
+ }
+ delim_hold=*src;
+ *src='\0'; /* temporary */
+ var = getenv(dst + num_skip_chars);
+ *src=delim_hold;
+ if (num_skip_chars==2) {
+ src++;
+ }
+ }
+ if (var == NULL) {
+ /* Seems we got an un-expandable variable. So delete it. */
+ var = "";
+ }
+ {
int subst_len = strlen(var);
- char *next_dst;
- if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?")) == NULL) {
- next_dst = dst;
+ int trail_len = strlen(src);
+ if (dst+subst_len+trail_len >= command+BUFSIZ) {
+ error_msg(out_of_space);
+ return FALSE;
}
- src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1);
- /* Move stuff to the end of the string to accommodate filling
- * the created gap with the new stuff */
- memmove(dst+subst_len, next_dst+1, subst_len);
+ /* Move stuff to the end of the string to accommodate
+ * filling the created gap with the new stuff */
+ memmove(dst+subst_len, src, trail_len);
+ *(dst+subst_len+trail_len)='\0';
/* Now copy in the new stuff */
- strncpy(dst, var, subst_len);
+ memcpy(dst, var, subst_len);
+ src = dst+subst_len;
}
- src = dst;
- src++;
}
-
-
-
#endif
return TRUE;
}
#ifdef BB_FEATURE_SH_ENVIRONMENT
last_return_code=WEXITSTATUS(status);
-#endif
debug_printf("'%s' exited -- return code %d\n",
job_list.fg->text, last_return_code);
+#endif
if (!job_list.fg->running_progs) {
/* child exited */
remove_job(&job_list, job_list.fg);