OLD | NEW |
(Empty) | |
| 1 #include <wordexp.h> |
| 2 #include <unistd.h> |
| 3 #include <stdio.h> |
| 4 #include <string.h> |
| 5 #include <limits.h> |
| 6 #include <stdint.h> |
| 7 #include <stdlib.h> |
| 8 #include <sys/wait.h> |
| 9 #include <signal.h> |
| 10 #include <errno.h> |
| 11 #include <fcntl.h> |
| 12 #include "pthread_impl.h" |
| 13 |
| 14 static void reap(pid_t pid) |
| 15 { |
| 16 int status; |
| 17 for (;;) { |
| 18 if (waitpid(pid, &status, 0) < 0) { |
| 19 if (errno != EINTR) return; |
| 20 } else { |
| 21 if (WIFEXITED(status)) return; |
| 22 } |
| 23 } |
| 24 } |
| 25 |
| 26 static char *getword(FILE *f) |
| 27 { |
| 28 char *s = 0; |
| 29 return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s; |
| 30 } |
| 31 |
| 32 static int do_wordexp(const char *s, wordexp_t *we, int flags) |
| 33 { |
| 34 size_t i, l; |
| 35 int sq=0, dq=0; |
| 36 size_t np=0; |
| 37 char *w, **tmp; |
| 38 char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; |
| 39 int err = 0; |
| 40 FILE *f; |
| 41 size_t wc = 0; |
| 42 char **wv = 0; |
| 43 int p[2]; |
| 44 pid_t pid; |
| 45 sigset_t set; |
| 46 |
| 47 if (flags & WRDE_REUSE) wordfree(we); |
| 48 |
| 49 if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) { |
| 50 case '\\': |
| 51 if (!sq) i++; |
| 52 break; |
| 53 case '\'': |
| 54 if (!dq) sq^=1; |
| 55 break; |
| 56 case '"': |
| 57 if (!sq) dq^=1; |
| 58 break; |
| 59 case '(': |
| 60 if (np) { |
| 61 np++; |
| 62 break; |
| 63 } |
| 64 case ')': |
| 65 if (np) { |
| 66 np--; |
| 67 break; |
| 68 } |
| 69 case '\n': |
| 70 case '|': |
| 71 case '&': |
| 72 case ';': |
| 73 case '<': |
| 74 case '>': |
| 75 case '{': |
| 76 case '}': |
| 77 if (!(sq|dq|np)) return WRDE_BADCHAR; |
| 78 break; |
| 79 case '$': |
| 80 if (sq) break; |
| 81 if (s[i+1]=='(' && s[i+2]=='(') { |
| 82 i += 2; |
| 83 np += 2; |
| 84 break; |
| 85 } else if (s[i+1] != '(') break; |
| 86 case '`': |
| 87 if (sq) break; |
| 88 return WRDE_CMDSUB; |
| 89 } |
| 90 |
| 91 if (flags & WRDE_APPEND) { |
| 92 wc = we->we_wordc; |
| 93 wv = we->we_wordv; |
| 94 } |
| 95 |
| 96 i = wc; |
| 97 if (flags & WRDE_DOOFFS) { |
| 98 if (we->we_offs > SIZE_MAX/sizeof(void *)/4) |
| 99 goto nospace; |
| 100 i += we->we_offs; |
| 101 } else { |
| 102 we->we_offs = 0; |
| 103 } |
| 104 |
| 105 if (pipe2(p, O_CLOEXEC) < 0) goto nospace; |
| 106 __block_all_sigs(&set); |
| 107 pid = fork(); |
| 108 __restore_sigs(&set); |
| 109 if (pid < 0) { |
| 110 close(p[0]); |
| 111 close(p[1]); |
| 112 goto nospace; |
| 113 } |
| 114 if (!pid) { |
| 115 if (p[1] == 1) fcntl(1, F_SETFD, 0); |
| 116 else dup2(p[1], 1); |
| 117 execl("/bin/sh", "sh", "-c", |
| 118 "eval \"printf %s\\\\\\\\0 x $1 $2\"", |
| 119 "sh", s, redir, (char *)0); |
| 120 _exit(1); |
| 121 } |
| 122 close(p[1]); |
| 123 |
| 124 f = fdopen(p[0], "r"); |
| 125 if (!f) { |
| 126 close(p[0]); |
| 127 kill(pid, SIGKILL); |
| 128 reap(pid); |
| 129 goto nospace; |
| 130 } |
| 131 |
| 132 l = wv ? i+1 : 0; |
| 133 |
| 134 free(getword(f)); |
| 135 if (feof(f)) { |
| 136 fclose(f); |
| 137 reap(pid); |
| 138 return WRDE_SYNTAX; |
| 139 } |
| 140 |
| 141 while ((w = getword(f))) { |
| 142 if (i+1 >= l) { |
| 143 l += l/2+10; |
| 144 tmp = realloc(wv, l*sizeof(char *)); |
| 145 if (!tmp) break; |
| 146 wv = tmp; |
| 147 } |
| 148 wv[i++] = w; |
| 149 wv[i] = 0; |
| 150 } |
| 151 if (!feof(f)) err = WRDE_NOSPACE; |
| 152 |
| 153 fclose(f); |
| 154 reap(pid); |
| 155 |
| 156 if (!wv) wv = calloc(i+1, sizeof *wv); |
| 157 |
| 158 we->we_wordv = wv; |
| 159 we->we_wordc = i; |
| 160 |
| 161 if (flags & WRDE_DOOFFS) { |
| 162 if (wv) for (i=we->we_offs; i; i--) |
| 163 we->we_wordv[i-1] = 0; |
| 164 we->we_wordc -= we->we_offs; |
| 165 } |
| 166 return err; |
| 167 |
| 168 nospace: |
| 169 if (!(flags & WRDE_APPEND)) { |
| 170 we->we_wordc = 0; |
| 171 we->we_wordv = 0; |
| 172 } |
| 173 return WRDE_NOSPACE; |
| 174 } |
| 175 |
| 176 int wordexp(const char *restrict s, wordexp_t *restrict we, int flags) |
| 177 { |
| 178 int r, cs; |
| 179 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
| 180 r = do_wordexp(s, we, flags); |
| 181 pthread_setcancelstate(cs, 0); |
| 182 return r; |
| 183 } |
| 184 |
| 185 void wordfree(wordexp_t *we) |
| 186 { |
| 187 size_t i; |
| 188 if (!we->we_wordv) return; |
| 189 for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]); |
| 190 free(we->we_wordv); |
| 191 we->we_wordv = 0; |
| 192 we->we_wordc = 0; |
| 193 } |
OLD | NEW |