Index: fusl/src/misc/wordexp.c |
diff --git a/fusl/src/misc/wordexp.c b/fusl/src/misc/wordexp.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..db39b5b8a3e3dee78bf6a54c1af3a1e23013c72b |
--- /dev/null |
+++ b/fusl/src/misc/wordexp.c |
@@ -0,0 +1,193 @@ |
+#include <wordexp.h> |
+#include <unistd.h> |
+#include <stdio.h> |
+#include <string.h> |
+#include <limits.h> |
+#include <stdint.h> |
+#include <stdlib.h> |
+#include <sys/wait.h> |
+#include <signal.h> |
+#include <errno.h> |
+#include <fcntl.h> |
+#include "pthread_impl.h" |
+ |
+static void reap(pid_t pid) |
+{ |
+ int status; |
+ for (;;) { |
+ if (waitpid(pid, &status, 0) < 0) { |
+ if (errno != EINTR) return; |
+ } else { |
+ if (WIFEXITED(status)) return; |
+ } |
+ } |
+} |
+ |
+static char *getword(FILE *f) |
+{ |
+ char *s = 0; |
+ return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s; |
+} |
+ |
+static int do_wordexp(const char *s, wordexp_t *we, int flags) |
+{ |
+ size_t i, l; |
+ int sq=0, dq=0; |
+ size_t np=0; |
+ char *w, **tmp; |
+ char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; |
+ int err = 0; |
+ FILE *f; |
+ size_t wc = 0; |
+ char **wv = 0; |
+ int p[2]; |
+ pid_t pid; |
+ sigset_t set; |
+ |
+ if (flags & WRDE_REUSE) wordfree(we); |
+ |
+ if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) { |
+ case '\\': |
+ if (!sq) i++; |
+ break; |
+ case '\'': |
+ if (!dq) sq^=1; |
+ break; |
+ case '"': |
+ if (!sq) dq^=1; |
+ break; |
+ case '(': |
+ if (np) { |
+ np++; |
+ break; |
+ } |
+ case ')': |
+ if (np) { |
+ np--; |
+ break; |
+ } |
+ case '\n': |
+ case '|': |
+ case '&': |
+ case ';': |
+ case '<': |
+ case '>': |
+ case '{': |
+ case '}': |
+ if (!(sq|dq|np)) return WRDE_BADCHAR; |
+ break; |
+ case '$': |
+ if (sq) break; |
+ if (s[i+1]=='(' && s[i+2]=='(') { |
+ i += 2; |
+ np += 2; |
+ break; |
+ } else if (s[i+1] != '(') break; |
+ case '`': |
+ if (sq) break; |
+ return WRDE_CMDSUB; |
+ } |
+ |
+ if (flags & WRDE_APPEND) { |
+ wc = we->we_wordc; |
+ wv = we->we_wordv; |
+ } |
+ |
+ i = wc; |
+ if (flags & WRDE_DOOFFS) { |
+ if (we->we_offs > SIZE_MAX/sizeof(void *)/4) |
+ goto nospace; |
+ i += we->we_offs; |
+ } else { |
+ we->we_offs = 0; |
+ } |
+ |
+ if (pipe2(p, O_CLOEXEC) < 0) goto nospace; |
+ __block_all_sigs(&set); |
+ pid = fork(); |
+ __restore_sigs(&set); |
+ if (pid < 0) { |
+ close(p[0]); |
+ close(p[1]); |
+ goto nospace; |
+ } |
+ if (!pid) { |
+ if (p[1] == 1) fcntl(1, F_SETFD, 0); |
+ else dup2(p[1], 1); |
+ execl("/bin/sh", "sh", "-c", |
+ "eval \"printf %s\\\\\\\\0 x $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); |
+ reap(pid); |
+ goto nospace; |
+ } |
+ |
+ l = wv ? i+1 : 0; |
+ |
+ free(getword(f)); |
+ if (feof(f)) { |
+ fclose(f); |
+ reap(pid); |
+ return WRDE_SYNTAX; |
+ } |
+ |
+ while ((w = getword(f))) { |
+ if (i+1 >= l) { |
+ l += l/2+10; |
+ tmp = realloc(wv, l*sizeof(char *)); |
+ if (!tmp) break; |
+ wv = tmp; |
+ } |
+ wv[i++] = w; |
+ wv[i] = 0; |
+ } |
+ if (!feof(f)) err = WRDE_NOSPACE; |
+ |
+ fclose(f); |
+ reap(pid); |
+ |
+ if (!wv) wv = calloc(i+1, sizeof *wv); |
+ |
+ we->we_wordv = wv; |
+ we->we_wordc = i; |
+ |
+ if (flags & WRDE_DOOFFS) { |
+ if (wv) for (i=we->we_offs; i; i--) |
+ we->we_wordv[i-1] = 0; |
+ we->we_wordc -= we->we_offs; |
+ } |
+ return err; |
+ |
+nospace: |
+ if (!(flags & WRDE_APPEND)) { |
+ we->we_wordc = 0; |
+ we->we_wordv = 0; |
+ } |
+ return WRDE_NOSPACE; |
+} |
+ |
+int wordexp(const char *restrict s, wordexp_t *restrict 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; |
+ if (!we->we_wordv) return; |
+ for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]); |
+ free(we->we_wordv); |
+ we->we_wordv = 0; |
+ we->we_wordc = 0; |
+} |