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