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 |