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