]> git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/wordexp.c
1bcf6599baf4e38c6fb0fad868f070a4b55411b7
[apple/libc.git] / gen / FreeBSD / wordexp.c
1 /*-
2 * Copyright (c) 2002 Tim J. Robbins.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <TargetConditionals.h>
28
29 #if TARGET_OS_IPHONE
30 /* <rdar://problem/13875458> */
31
32 #if defined(__OPEN_SOURCE__) || !__LP64__
33 #include <wordexp.h>
34 int wordexp(const char *restrict words __unused, wordexp_t *restrict pwordexp __unused, int flags __unused) {
35 return WRDE_NOSPACE;
36 }
37
38 void wordfree(wordexp_t *pwordexp __unused) {
39 }
40 #else
41 struct __not_an_empty_c_file;
42 #endif
43
44 #else
45
46 #include "namespace.h"
47 #include <sys/cdefs.h>
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <paths.h>
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <wordexp.h>
59 #include "un-namespace.h"
60 #ifdef __APPLE__
61 // For _NSGetEnviron() -- which gives us a pointer to environ
62 #include <crt_externs.h>
63 #include <spawn.h>
64 #endif /* __APPLE__ */
65
66 __FBSDID("$FreeBSD$");
67
68 #ifdef __APPLE__
69 /*
70 * To maintain backwards compatibility with wordexp_t, we can't put
71 * we_strings and we_nbytes in wordexp_t. So we create a new structure,
72 * we_int_t, that has wi_strings and wi_nbytes, as well as the we_wordv
73 * storage.
74 */
75 typedef struct {
76 char *wi_strings;
77 size_t wi_nbytes;
78 char *wi_wordv[0];
79 } we_int_t;
80 /*
81 * Normally, we_wordv will point to wi_wordv, so we need macros to convert
82 * back and forth between wi_wordv and the we_int_t structure.
83 */
84 #define WE_INT_T(x) ((we_int_t *)((char *)(x) - sizeof(we_int_t)))
85 #define WE_STRINGS(we) (WE_INT_T((we)->we_wordv)->wi_strings)
86 #define WE_WORDV(x) ((x)->wi_wordv)
87
88 /*
89 * bash will return success, yet print a command substitution/syntax error
90 * to stderr. So we need to capture stderr, and see if it contains this error.
91 */
92 static const char command_substitution_str[] = "command substitution";
93 static const char syntax_error_str[] = "syntax error";
94 static const char unbound_variable_str[] = " unbound variable";
95 #endif /* __APPLE__ */
96
97 static int we_askshell(const char *, wordexp_t *, int);
98 static int we_check(const char *, int);
99
100 /*
101 * wordexp --
102 * Perform shell word expansion on `words' and place the resulting list
103 * of words in `we'. See wordexp(3).
104 *
105 * Specified by IEEE Std. 1003.1-2001.
106 */
107 int
108 #ifdef __APPLE__
109 wordexp(const char * __restrict words, wordexp_t * __restrict we0, int flags)
110 #else /* !__APPLE__ */
111 wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
112 #endif /* !__APPLE__ */
113 {
114 int error;
115 #ifdef __APPLE__
116 wordexp_t temp;
117 wordexp_t *we = &temp;
118
119 if ((error = we_check(words, flags)) != 0) return (error);
120 we->we_offs = we0->we_offs;
121 if (flags & WRDE_APPEND) {
122 size_t i;
123 size_t vofs = we0->we_wordc + (flags & WRDE_DOOFFS ? we0->we_offs : 0);
124 we_int_t *wi0 = WE_INT_T(we0->we_wordv);
125 we_int_t *wi = malloc((vofs + 1) * sizeof(char *) + sizeof(we_int_t));
126
127 if (!wi) return (WRDE_NOSPACE);
128 memcpy(wi, wi0, (vofs + 1) * sizeof(char *) + sizeof(we_int_t));
129 wi->wi_strings = malloc(wi->wi_nbytes);
130 if (!wi->wi_strings) {
131 free(wi);
132 return (WRDE_NOSPACE);
133 }
134 memcpy(wi->wi_strings, wi0->wi_strings, wi->wi_nbytes);
135 for (i = 0; i < vofs; i++)
136 if (wi->wi_wordv[i] != NULL)
137 wi->wi_wordv[i] += wi->wi_strings - wi0->wi_strings;
138 we->we_wordc = we0->we_wordc;
139 we->we_wordv = WE_WORDV(wi);
140 } else {
141 we->we_wordc = 0;
142 we->we_wordv = NULL;
143 }
144 #else /* !__APPLE__ */
145 if (flags & WRDE_REUSE)
146 wordfree(we);
147 if ((flags & WRDE_APPEND) == 0) {
148 we->we_wordc = 0;
149 we->we_wordv = NULL;
150 we->we_strings = NULL;
151 we->we_nbytes = 0;
152 }
153 if ((error = we_check(words, flags)) != 0) {
154 wordfree(we);
155 return (error);
156 }
157 #endif /* !__APPLE__ */
158 if ((error = we_askshell(words, we, flags)) != 0) {
159 #ifdef __APPLE__
160 if (error == WRDE_NOSPACE) {
161 if (flags & WRDE_REUSE)
162 wordfree(we0);
163 *we0 = *we;
164 } else {
165 wordfree(we);
166 }
167 #else /* !__APPLE__ */
168 wordfree(we);
169 #endif /* !__APPLE__ */
170 return (error);
171 }
172 #ifdef __APPLE__
173 if (flags & WRDE_REUSE)
174 wordfree(we0);
175 *we0 = *we;
176 #endif /* __APPLE__ */
177 return (0);
178 }
179
180 static size_t
181 we_read_fully(int fd, char *buffer, size_t len)
182 {
183 size_t done;
184 ssize_t nread;
185
186 done = 0;
187 do {
188 nread = _read(fd, buffer + done, len - done);
189 if (nread == -1 && errno == EINTR)
190 continue;
191 if (nread <= 0)
192 break;
193 done += nread;
194 } while (done != len);
195 return done;
196 }
197
198 /*
199 * we_askshell --
200 * Use the `wordexp' /bin/sh builtin function to do most of the work
201 * in expanding the word string. This function is complicated by
202 * memory management.
203 */
204 static int
205 we_askshell(const char *words, wordexp_t *we, int flags)
206 {
207 int pdes[2]; /* Pipe to child */
208 char bbuf[9]; /* Buffer for byte count */
209 char wbuf[9]; /* Buffer for word count */
210 long nwords, nbytes; /* Number of words, bytes from child */
211 long i; /* Handy integer */
212 size_t sofs; /* Offset into we->we_strings */
213 size_t vofs; /* Offset into we->we_wordv */
214 pid_t pid; /* Process ID of child */
215 pid_t wpid; /* waitpid return value */
216 int status; /* Child exit status */
217 int error; /* Our return value */
218 int serrno; /* errno to return */
219 char *np, *p; /* Handy pointers */
220 char *nstrings; /* Temporary for realloc() */
221 #ifdef __APPLE__
222 int perr[2]; /* Pipe to child error */
223 we_int_t *nwv; /* Temporary for realloc() */
224 int spawnerr = 0;
225 posix_spawn_file_actions_t file_actions;
226 posix_spawnattr_t attr;
227 #else /* !__APPLE__ */
228 char **nwv; /* Temporary for realloc() */
229 #endif /* !__APPLE__ */
230 sigset_t newsigblock, oldsigblock;
231
232 serrno = errno;
233
234 #ifdef __APPLE__
235 if (pipe(pdes) < 0)
236 #else /* !__APPLE__ */
237 if (pipe2(pdes, O_CLOEXEC) < 0)
238 #endif /* !__APPLE__ */
239 return (WRDE_NOSPACE); /* XXX */
240 #ifdef __APPLE__
241 if (pipe(perr) < 0) {
242 close(pdes[0]);
243 close(pdes[1]);
244 return (WRDE_NOSPACE); /* XXX */
245 }
246 #endif /* __APPLE__ */
247 (void)sigemptyset(&newsigblock);
248 (void)sigaddset(&newsigblock, SIGCHLD);
249 (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
250 #ifdef __APPLE__
251 if ((spawnerr = posix_spawnattr_init(&attr)) != 0) goto spawnerrexit;
252 do {
253 sigset_t spawnsig;
254 if ((spawnerr = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT)) != 0) break;
255 (void)sigfillset(&spawnsig);
256 if ((spawnerr = posix_spawnattr_setsigdefault(&attr, &spawnsig)) != 0) break;
257 (void)sigemptyset(&spawnsig);
258 if ((spawnerr = posix_spawnattr_setsigmask(&attr, &spawnsig)) != 0) break;
259 if ((spawnerr = posix_spawn_file_actions_init(&file_actions)) != 0) break;
260 do {
261 char *argv[7] = {"sh"};
262 const char cmd[] = "[ $# -gt 0 ] && export IFS=\"$1\";/usr/lib/system/wordexp-helper ";
263 int a = 1;
264 char *buf;
265 int buflen;
266 char *IFS;
267 if (pdes[1] == STDOUT_FILENO) {
268 if ((spawnerr = posix_spawn_file_actions_addinherit_np(&file_actions, STDOUT_FILENO)) != 0) break;
269 } else {
270 if ((spawnerr = posix_spawn_file_actions_adddup2(&file_actions, pdes[1], STDOUT_FILENO)) != 0) break;
271 }
272 if (perr[1] == STDERR_FILENO) {
273 if ((spawnerr = posix_spawn_file_actions_addinherit_np(&file_actions, STDERR_FILENO)) != 0) break;
274 } else {
275 if ((spawnerr = posix_spawn_file_actions_adddup2(&file_actions, perr[1], STDERR_FILENO)) != 0) break;
276 }
277 if (flags & WRDE_UNDEF) argv[a++] = "-u";
278 argv[a++] = "-c";
279 buflen = (sizeof(cmd) - 1) + strlen(words) + 1;
280 if ((buf = malloc(buflen)) == NULL) {
281 spawnerr = errno;
282 break;
283 }
284 strcpy(buf, cmd);
285 strcat(buf, words);
286 argv[a++] = buf;
287 if ((IFS = getenv("IFS")) != NULL) {
288 argv[a++] = "--";
289 argv[a++] = IFS;
290 }
291 argv[a] = NULL;
292 spawnerr = posix_spawn(&pid, _PATH_BSHELL, &file_actions, &attr, argv, *_NSGetEnviron());
293 free(buf);
294 } while(0);
295 posix_spawn_file_actions_destroy(&file_actions);
296 } while(0);
297 posix_spawnattr_destroy(&attr);
298 if (spawnerr) {
299 spawnerrexit:
300 close(pdes[0]);
301 close(pdes[1]);
302 close(perr[0]);
303 close(perr[1]);
304 errno = spawnerr;
305 return (WRDE_NOSPACE); /* XXX */
306 }
307 #else /* !__APPLE__ */
308 if ((pid = fork()) < 0) {
309 serrno = errno;
310 _close(pdes[0]);
311 _close(pdes[1]);
312 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
313 errno = serrno;
314 return (WRDE_NOSPACE); /* XXX */
315 }
316 else if (pid == 0) {
317 /*
318 * We are the child; just get /bin/sh to run the wordexp
319 * builtin on `words'.
320 */
321 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
322 if ((pdes[1] != STDOUT_FILENO ?
323 _dup2(pdes[1], STDOUT_FILENO) :
324 _fcntl(pdes[1], F_SETFD, 0)) < 0)
325 _exit(1);
326 execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
327 "-c", "eval \"$1\";eval \"wordexp $2\"", "",
328 flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", words,
329 (char *)NULL);
330 _exit(1);
331 }
332 #endif /* !__APPLE__ */
333
334 /*
335 * We are the parent; read the output of the shell wordexp function,
336 * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal
337 * byte count (not including terminating null bytes), followed by
338 * the expanded words separated by nulls.
339 */
340 _close(pdes[1]);
341 #ifdef __APPLE__
342 close(perr[1]);
343 #endif /* __APPLE__ */
344 if (we_read_fully(pdes[0], wbuf, 8) != 8 ||
345 we_read_fully(pdes[0], bbuf, 8) != 8) {
346 error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX;
347 serrno = errno;
348 goto cleanup;
349 }
350 wbuf[8] = bbuf[8] = '\0';
351 nwords = strtol(wbuf, NULL, 16);
352 nbytes = strtol(bbuf, NULL, 16) + nwords;
353
354 /*
355 * Allocate or reallocate (when flags & WRDE_APPEND) the word vector
356 * and string storage buffers for the expanded words we're about to
357 * read from the child.
358 */
359 #ifndef __APPLE__
360 sofs = we->we_nbytes;
361 #endif /* !__APPLE__ */
362 vofs = we->we_wordc;
363 if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
364 vofs += we->we_offs;
365 we->we_wordc += nwords;
366 #ifndef __APPLE__
367 we->we_nbytes += nbytes;
368 #endif /* !__APPLE__ */
369 #ifdef __APPLE__
370 if ((nwv = realloc(we->we_wordv ? WE_INT_T(we->we_wordv) : NULL, (we->we_wordc + 1 +
371 (flags & WRDE_DOOFFS ? we->we_offs : 0)) *
372 sizeof(char *) + sizeof(we_int_t))) == NULL)
373 #else /* !__APPLE__ */
374 if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 +
375 (flags & WRDE_DOOFFS ? we->we_offs : 0)) *
376 sizeof(char *))) == NULL)
377 #endif /* !__APPLE__ */
378 {
379 error = WRDE_NOSPACE;
380 goto cleanup;
381 }
382 #ifdef __APPLE__
383 if (!we->we_wordv) {
384 nwv->wi_strings = NULL;
385 nwv->wi_nbytes = 0;
386 }
387 sofs = nwv->wi_nbytes;
388 nwv->wi_nbytes += nbytes;
389 we->we_wordv = WE_WORDV(nwv);
390 #else /* !__APPLE__ */
391 we->we_wordv = nwv;
392 #endif /* !__APPLE__ */
393 #ifdef __APPLE__
394 if ((nstrings = realloc(nwv->wi_strings, nwv->wi_nbytes)) == NULL)
395 #else /* !__APPLE__ */
396 if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL)
397 #endif /* !__APPLE__ */
398 {
399 error = WRDE_NOSPACE;
400 goto cleanup;
401 }
402 for (i = 0; i < vofs; i++)
403 if (we->we_wordv[i] != NULL)
404 #ifdef __APPLE__
405 we->we_wordv[i] += nstrings - nwv->wi_strings;
406 #else /* !__APPLE__ */
407 we->we_wordv[i] += nstrings - we->we_strings;
408 #endif /* !__APPLE__ */
409 #ifdef __APPLE__
410 nwv->wi_strings = nstrings;
411 #else /* !__APPLE__ */
412 we->we_strings = nstrings;
413 #endif /* !__APPLE__ */
414
415 #ifdef __APPLE__
416 if (we_read_fully(pdes[0], nwv->wi_strings + sofs, nbytes) != nbytes)
417 #else /* !__APPLE__ */
418 if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes)
419 #endif /* !__APPLE__ */
420 {
421 error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX;
422 serrno = errno;
423 goto cleanup;
424 }
425 #ifdef __APPLE__
426 char err_buf[1024];
427 ssize_t err_sz = read(perr[0], err_buf, sizeof(err_buf) - 1);
428 if (err_sz > 0) {
429 err_buf[err_sz] = '\0';
430 if (flags & WRDE_SHOWERR) {
431 fputs(err_buf, stderr);
432 }
433 } else if (err_sz < 0) {
434 serrno = errno;
435 error = WRDE_NOSPACE;
436 goto cleanup;
437 }
438 #endif /* __APPLE__ */
439
440 error = 0;
441 cleanup:
442 _close(pdes[0]);
443 #ifdef __APPLE__
444 close(perr[0]);
445 #endif /* __APPLE__ */
446 do
447 wpid = _waitpid(pid, &status, 0);
448 while (wpid < 0 && errno == EINTR);
449 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
450 if (error != 0) {
451 errno = serrno;
452 return (error);
453 }
454 if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
455 return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
456 #ifdef __APPLE__
457 const char *cs = strstr(err_buf, command_substitution_str);
458 if (cs && strstr(cs + (sizeof(command_substitution_str) - 1), syntax_error_str)) {
459 return (strstr(err_buf, unbound_variable_str) ? WRDE_BADVAL : WRDE_SYNTAX);
460 }
461 #endif /* __APPLE__ */
462
463 /*
464 * Break the null-terminated expanded word strings out into
465 * the vector.
466 */
467 if (vofs == 0 && flags & WRDE_DOOFFS)
468 while (vofs < we->we_offs)
469 we->we_wordv[vofs++] = NULL;
470 #ifdef __APPLE__
471 p = nwv->wi_strings + sofs;
472 #else /* !__APPLE__ */
473 p = we->we_strings + sofs;
474 #endif /* !__APPLE__ */
475 while (nwords-- != 0) {
476 we->we_wordv[vofs++] = p;
477 if ((np = memchr(p, '\0', nbytes)) == NULL)
478 return (WRDE_NOSPACE); /* XXX */
479 nbytes -= np - p + 1;
480 p = np + 1;
481 }
482 we->we_wordv[vofs] = NULL;
483
484 return (0);
485 }
486
487 /*
488 * we_check --
489 * Check that the string contains none of the following unquoted
490 * special characters: <newline> |&;<>(){}
491 * or command substitutions when WRDE_NOCMD is set in flags.
492 */
493 static int
494 we_check(const char *words, int flags)
495 {
496 char c;
497 int dquote, level, quote, squote;
498
499 quote = squote = dquote = 0;
500 while ((c = *words++) != '\0') {
501 switch (c) {
502 case '\\':
503 if (squote == 0)
504 quote ^= 1;
505 continue;
506 case '\'':
507 if (quote + dquote == 0)
508 squote ^= 1;
509 break;
510 case '"':
511 if (quote + squote == 0)
512 dquote ^= 1;
513 break;
514 case '`':
515 if (quote + squote == 0 && flags & WRDE_NOCMD)
516 return (WRDE_CMDSUB);
517 while ((c = *words++) != '\0' && c != '`')
518 if (c == '\\' && (c = *words++) == '\0')
519 break;
520 if (c == '\0')
521 return (WRDE_SYNTAX);
522 break;
523 case '|': case '&': case ';': case '<': case '>':
524 case '{': case '}': case '(': case ')': case '\n':
525 if (quote + squote + dquote == 0)
526 return (WRDE_BADCHAR);
527 break;
528 case '$':
529 if ((c = *words++) == '\0')
530 break;
531 else if (quote + squote == 0 && c == '(') {
532 if (flags & WRDE_NOCMD && *words != '(')
533 return (WRDE_CMDSUB);
534 level = 1;
535 while ((c = *words++) != '\0') {
536 if (c == '\\') {
537 if ((c = *words++) == '\0')
538 break;
539 } else if (c == '(')
540 level++;
541 else if (c == ')' && --level == 0)
542 break;
543 }
544 if (c == '\0' || level != 0)
545 return (WRDE_SYNTAX);
546 } else if (quote + squote == 0 && c == '{') {
547 level = 1;
548 while ((c = *words++) != '\0') {
549 if (c == '\\') {
550 if ((c = *words++) == '\0')
551 break;
552 } else if (c == '{')
553 level++;
554 else if (c == '}' && --level == 0)
555 break;
556 }
557 if (c == '\0' || level != 0)
558 return (WRDE_SYNTAX);
559 } else
560 --words;
561 break;
562 default:
563 break;
564 }
565 quote = 0;
566 }
567 if (quote + squote + dquote != 0)
568 return (WRDE_SYNTAX);
569
570 return (0);
571 }
572
573 /*
574 * wordfree --
575 * Free the result of wordexp(). See wordexp(3).
576 *
577 * Specified by IEEE Std. 1003.1-2001.
578 */
579 void
580 wordfree(wordexp_t *we)
581 {
582
583 if (we == NULL)
584 return;
585 #ifdef __APPLE__
586 if (we->we_wordv) {
587 free(WE_STRINGS(we));
588 free(WE_INT_T(we->we_wordv));
589 }
590 #else /* !__APPLE__ */
591 free(we->we_wordv);
592 #endif /* !__APPLE__ */
593 #ifndef __APPLE__
594 free(we->we_strings);
595 #endif /* !__APPLE__ */
596 we->we_wordv = NULL;
597 #ifndef __APPLE__
598 we->we_strings = NULL;
599 we->we_nbytes = 0;
600 #endif /* !__APPLE__ */
601 we->we_wordc = 0;
602 }
603
604 #endif /* TARGET_OS_IPHONE */