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> 33int wordexp(const char *restrict words __unused, wordexp_t *restrict pwordexp __unused, int flags __unused) { 34 return WRDE_NOSPACE; 35} 36 37void 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 */ 71typedef 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 */ 88static const char command_substitution_str[] = "command substitution"; 89static const char syntax_error_str[] = "syntax error"; 90static const char unbound_variable_str[] = " unbound variable"; 91#endif /* __APPLE__ */ 92 93static int we_askshell(const char *, wordexp_t *, int); 94static 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 */ 103int 104#ifdef __APPLE__ 105wordexp(const char * __restrict words, wordexp_t * __restrict we0, int flags) 106#else /* !__APPLE__ */ 107wordexp(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 176static size_t 177we_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 */ 200static int 201we_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) { 295spawnerrexit: 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; 437cleanup: 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 */ 489static int 490we_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 */ 575void 576wordfree(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 */ 601