wordexp.c revision 287872
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 "namespace.h" 28#include <sys/cdefs.h> 29#include <sys/types.h> 30#include <sys/wait.h> 31#include <errno.h> 32#include <fcntl.h> 33#include <paths.h> 34#include <signal.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <unistd.h> 39#include <wordexp.h> 40#include "un-namespace.h" 41#include "libc_private.h" 42 43__FBSDID("$FreeBSD: releng/10.2/lib/libc/gen/wordexp.c 287872 2015-09-16 20:59:41Z delphij $"); 44 45static int we_askshell(const char *, wordexp_t *, int); 46static int we_check(const char *, int); 47 48/* 49 * wordexp -- 50 * Perform shell word expansion on `words' and place the resulting list 51 * of words in `we'. See wordexp(3). 52 * 53 * Specified by IEEE Std. 1003.1-2001. 54 */ 55int 56wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) 57{ 58 int error; 59 60 if (flags & WRDE_REUSE) 61 wordfree(we); 62 if ((flags & WRDE_APPEND) == 0) { 63 we->we_wordc = 0; 64 we->we_wordv = NULL; 65 we->we_strings = NULL; 66 we->we_nbytes = 0; 67 } 68 if ((error = we_check(words, flags)) != 0) { 69 wordfree(we); 70 return (error); 71 } 72 if ((error = we_askshell(words, we, flags)) != 0) { 73 wordfree(we); 74 return (error); 75 } 76 return (0); 77} 78 79static size_t 80we_read_fully(int fd, char *buffer, size_t len) 81{ 82 size_t done; 83 ssize_t nread; 84 85 done = 0; 86 do { 87 nread = _read(fd, buffer + done, len - done); 88 if (nread == -1 && errno == EINTR) 89 continue; 90 if (nread <= 0) 91 break; 92 done += nread; 93 } while (done != len); 94 return done; 95} 96 97/* 98 * we_askshell -- 99 * Use the `wordexp' /bin/sh builtin function to do most of the work 100 * in expanding the word string. This function is complicated by 101 * memory management. 102 */ 103static int 104we_askshell(const char *words, wordexp_t *we, int flags) 105{ 106 int pdes[2]; /* Pipe to child */ 107 char bbuf[9]; /* Buffer for byte count */ 108 char wbuf[9]; /* Buffer for word count */ 109 long nwords, nbytes; /* Number of words, bytes from child */ 110 long i; /* Handy integer */ 111 size_t sofs; /* Offset into we->we_strings */ 112 size_t vofs; /* Offset into we->we_wordv */ 113 pid_t pid; /* Process ID of child */ 114 pid_t wpid; /* waitpid return value */ 115 int status; /* Child exit status */ 116 int error; /* Our return value */ 117 int serrno; /* errno to return */ 118 char *np, *p; /* Handy pointers */ 119 char *nstrings; /* Temporary for realloc() */ 120 char **nwv; /* Temporary for realloc() */ 121 sigset_t newsigblock, oldsigblock; 122 const char *ifs; 123 124 serrno = errno; 125 ifs = getenv("IFS"); 126 127 if (pipe2(pdes, O_CLOEXEC) < 0) 128 return (WRDE_NOSPACE); /* XXX */ 129 (void)sigemptyset(&newsigblock); 130 (void)sigaddset(&newsigblock, SIGCHLD); 131 (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); 132 if ((pid = fork()) < 0) { 133 serrno = errno; 134 _close(pdes[0]); 135 _close(pdes[1]); 136 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 137 errno = serrno; 138 return (WRDE_NOSPACE); /* XXX */ 139 } 140 else if (pid == 0) { 141 /* 142 * We are the child; just get /bin/sh to run the wordexp 143 * builtin on `words'. 144 */ 145 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 146 if ((pdes[1] != STDOUT_FILENO ? 147 _dup2(pdes[1], STDOUT_FILENO) : 148 _fcntl(pdes[1], F_SETFD, 0)) < 0) 149 _exit(1); 150 execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u", 151 "-c", "IFS=$1;eval \"$2\";eval \"wordexp $3\"", "", 152 ifs != NULL ? ifs : " \t\n", 153 flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", words, 154 (char *)NULL); 155 _exit(1); 156 } 157 158 /* 159 * We are the parent; read the output of the shell wordexp function, 160 * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal 161 * byte count (not including terminating null bytes), followed by 162 * the expanded words separated by nulls. 163 */ 164 _close(pdes[1]); 165 if (we_read_fully(pdes[0], wbuf, 8) != 8 || 166 we_read_fully(pdes[0], bbuf, 8) != 8) { 167 error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; 168 serrno = errno; 169 goto cleanup; 170 } 171 wbuf[8] = bbuf[8] = '\0'; 172 nwords = strtol(wbuf, NULL, 16); 173 nbytes = strtol(bbuf, NULL, 16) + nwords; 174 175 /* 176 * Allocate or reallocate (when flags & WRDE_APPEND) the word vector 177 * and string storage buffers for the expanded words we're about to 178 * read from the child. 179 */ 180 sofs = we->we_nbytes; 181 vofs = we->we_wordc; 182 if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND)) 183 vofs += we->we_offs; 184 we->we_wordc += nwords; 185 we->we_nbytes += nbytes; 186 if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 + 187 (flags & WRDE_DOOFFS ? we->we_offs : 0)) * 188 sizeof(char *))) == NULL) { 189 error = WRDE_NOSPACE; 190 goto cleanup; 191 } 192 we->we_wordv = nwv; 193 if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) { 194 error = WRDE_NOSPACE; 195 goto cleanup; 196 } 197 for (i = 0; i < vofs; i++) 198 if (we->we_wordv[i] != NULL) 199 we->we_wordv[i] += nstrings - we->we_strings; 200 we->we_strings = nstrings; 201 202 if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { 203 error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; 204 serrno = errno; 205 goto cleanup; 206 } 207 208 error = 0; 209cleanup: 210 _close(pdes[0]); 211 do 212 wpid = _waitpid(pid, &status, 0); 213 while (wpid < 0 && errno == EINTR); 214 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 215 if (error != 0) { 216 errno = serrno; 217 return (error); 218 } 219 if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) 220 return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX); 221 222 /* 223 * Break the null-terminated expanded word strings out into 224 * the vector. 225 */ 226 if (vofs == 0 && flags & WRDE_DOOFFS) 227 while (vofs < we->we_offs) 228 we->we_wordv[vofs++] = NULL; 229 p = we->we_strings + sofs; 230 while (nwords-- != 0) { 231 we->we_wordv[vofs++] = p; 232 if ((np = memchr(p, '\0', nbytes)) == NULL) 233 return (WRDE_NOSPACE); /* XXX */ 234 nbytes -= np - p + 1; 235 p = np + 1; 236 } 237 we->we_wordv[vofs] = NULL; 238 239 return (0); 240} 241 242/* 243 * we_check -- 244 * Check that the string contains none of the following unquoted 245 * special characters: <newline> |&;<>(){} 246 * or command substitutions when WRDE_NOCMD is set in flags. 247 */ 248static int 249we_check(const char *words, int flags) 250{ 251 char c; 252 int dquote, level, quote, squote; 253 254 quote = squote = dquote = 0; 255 while ((c = *words++) != '\0') { 256 switch (c) { 257 case '\\': 258 if (squote == 0) 259 quote ^= 1; 260 continue; 261 case '\'': 262 if (quote + dquote == 0) 263 squote ^= 1; 264 break; 265 case '"': 266 if (quote + squote == 0) 267 dquote ^= 1; 268 break; 269 case '`': 270 if (quote + squote == 0 && flags & WRDE_NOCMD) 271 return (WRDE_CMDSUB); 272 while ((c = *words++) != '\0' && c != '`') 273 if (c == '\\' && (c = *words++) == '\0') 274 break; 275 if (c == '\0') 276 return (WRDE_SYNTAX); 277 break; 278 case '|': case '&': case ';': case '<': case '>': 279 case '{': case '}': case '(': case ')': case '\n': 280 if (quote + squote + dquote == 0) 281 return (WRDE_BADCHAR); 282 break; 283 case '$': 284 if ((c = *words++) == '\0') 285 break; 286 else if (quote + squote == 0 && c == '(') { 287 if (flags & WRDE_NOCMD && *words != '(') 288 return (WRDE_CMDSUB); 289 level = 1; 290 while ((c = *words++) != '\0') { 291 if (c == '\\') { 292 if ((c = *words++) == '\0') 293 break; 294 } else if (c == '(') 295 level++; 296 else if (c == ')' && --level == 0) 297 break; 298 } 299 if (c == '\0' || level != 0) 300 return (WRDE_SYNTAX); 301 } else if (quote + squote == 0 && c == '{') { 302 level = 1; 303 while ((c = *words++) != '\0') { 304 if (c == '\\') { 305 if ((c = *words++) == '\0') 306 break; 307 } else if (c == '{') 308 level++; 309 else if (c == '}' && --level == 0) 310 break; 311 } 312 if (c == '\0' || level != 0) 313 return (WRDE_SYNTAX); 314 } else 315 --words; 316 break; 317 default: 318 break; 319 } 320 quote = 0; 321 } 322 if (quote + squote + dquote != 0) 323 return (WRDE_SYNTAX); 324 325 return (0); 326} 327 328/* 329 * wordfree -- 330 * Free the result of wordexp(). See wordexp(3). 331 * 332 * Specified by IEEE Std. 1003.1-2001. 333 */ 334void 335wordfree(wordexp_t *we) 336{ 337 338 if (we == NULL) 339 return; 340 free(we->we_wordv); 341 free(we->we_strings); 342 we->we_wordv = NULL; 343 we->we_strings = NULL; 344 we->we_nbytes = 0; 345 we->we_wordc = 0; 346} 347