wordexp must set the we_offs entries of we_wordv to null pointers
[musl] / src / misc / wordexp.c
index b0d6846..15adddb 100644 (file)
@@ -5,6 +5,9 @@
 #include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <pthread.h>
 
 static char *getword(FILE *f)
 {
@@ -12,17 +15,19 @@ static char *getword(FILE *f)
        return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
 }
 
-int wordexp(const char *s, wordexp_t *we, int flags)
+static int do_wordexp(const char *s, wordexp_t *we, int flags)
 {
-       size_t i, l, len;
+       size_t i, l;
        int sq=0, dq=0;
        size_t np=0;
-       char *cmd, *w, **tmp;
+       char *w, **tmp;
        char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null";
        int err = 0, status;
        FILE *f;
        size_t wc = 0;
        char **wv = 0;
+       int p[2];
+       pid_t pid;
 
        if (flags & WRDE_REUSE) wordfree(we);
 
@@ -77,16 +82,35 @@ int wordexp(const char *s, wordexp_t *we, int flags)
                if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
                        return WRDE_NOSPACE;
                i += we->we_offs;
+       } else {
+               we->we_offs = 0;
        }
 
-       len = 50 + strlen(s);
-       cmd = malloc(len);
-       if (!cmd) return WRDE_NOSPACE;
-       snprintf(cmd, len, "printf %%s\\\\0 %s %s", s, redir);
-printf("{%s}\n", cmd);
-       f = popen(cmd, "r");
-       free(cmd);
-       if (!f) return WRDE_NOSPACE;
+       if (pipe(p) < 0) return WRDE_NOSPACE;
+       pid = fork();
+       if (pid < 0) {
+               close(p[0]);
+               close(p[1]);
+               return WRDE_NOSPACE;
+       }
+       if (!pid) {
+               dup2(p[1], 1);
+               close(p[0]);
+               close(p[1]);
+               execl("/bin/sh", "sh", "-c",
+                       "eval \"printf %s\\\\\\\\0 $1 $2\"",
+                       "sh", s, redir, (char *)0);
+               _exit(1);
+       }
+       close(p[1]);
+       
+       f = fdopen(p[0], "r");
+       if (!f) {
+               close(p[0]);
+               kill(pid, SIGKILL);
+               waitpid(pid, &status, 0);
+               return WRDE_NOSPACE;
+       }
 
        l = wv ? i+1 : 0;
 
@@ -102,7 +126,8 @@ printf("{%s}\n", cmd);
        }
        if (!feof(f)) err = WRDE_NOSPACE;
 
-       status = pclose(f);
+       fclose(f);
+       waitpid(pid, &status, 0);
        if (WEXITSTATUS(status)) {
                if (!(flags & WRDE_APPEND)) {
                        free(wv);
@@ -113,10 +138,24 @@ printf("{%s}\n", cmd);
        }
 
        we->we_wordv = wv;
-       we->we_wordc = i - we->we_offs;
+       we->we_wordc = i;
+
+       for (i=we->we_offs; i; i--)
+               we->we_wordv[i-1] = 0;
+
+       if (flags & WRDE_DOOFFS) we->we_wordc -= we->we_offs;
        return err;
 }
 
+int wordexp(const char *s, wordexp_t *we, int flags)
+{
+       int r, cs;
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+       r = do_wordexp(s, we, flags);
+       pthread_setcancelstate(cs, 0);
+       return r;
+}
+
 void wordfree(wordexp_t *we)
 {
        size_t i;