github.com/afumu/libc@v0.0.6/musl/src/misc/wordexp.c (about) 1 #include <wordexp.h> 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <limits.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <sys/wait.h> 9 #include <signal.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include "pthread_impl.h" 13 14 static void reap(pid_t pid) 15 { 16 int status; 17 while (waitpid(pid, &status, 0) < 0 && errno == EINTR); 18 } 19 20 static char *getword(FILE *f) 21 { 22 char *s = 0; 23 return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s; 24 } 25 26 static int do_wordexp(const char *s, wordexp_t *we, int flags) 27 { 28 size_t i, l; 29 int sq=0, dq=0; 30 size_t np=0; 31 char *w, **tmp; 32 char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null"; 33 int err = 0; 34 FILE *f; 35 size_t wc = 0; 36 char **wv = 0; 37 int p[2]; 38 pid_t pid; 39 sigset_t set; 40 41 if (flags & WRDE_REUSE) wordfree(we); 42 43 if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) { 44 case '\\': 45 if (!sq && !s[++i]) return WRDE_SYNTAX; 46 break; 47 case '\'': 48 if (!dq) sq^=1; 49 break; 50 case '"': 51 if (!sq) dq^=1; 52 break; 53 case '(': 54 if (np) { 55 np++; 56 break; 57 } 58 case ')': 59 if (np) { 60 np--; 61 break; 62 } 63 case '\n': 64 case '|': 65 case '&': 66 case ';': 67 case '<': 68 case '>': 69 case '{': 70 case '}': 71 if (!(sq|dq|np)) return WRDE_BADCHAR; 72 break; 73 case '$': 74 if (sq) break; 75 if (s[i+1]=='(' && s[i+2]=='(') { 76 i += 2; 77 np += 2; 78 break; 79 } else if (s[i+1] != '(') break; 80 case '`': 81 if (sq) break; 82 return WRDE_CMDSUB; 83 } 84 85 if (flags & WRDE_APPEND) { 86 wc = we->we_wordc; 87 wv = we->we_wordv; 88 } 89 90 i = wc; 91 if (flags & WRDE_DOOFFS) { 92 if (we->we_offs > SIZE_MAX/sizeof(void *)/4) 93 goto nospace; 94 i += we->we_offs; 95 } else { 96 we->we_offs = 0; 97 } 98 99 if (pipe2(p, O_CLOEXEC) < 0) goto nospace; 100 __block_all_sigs(&set); 101 pid = fork(); 102 __restore_sigs(&set); 103 if (pid < 0) { 104 close(p[0]); 105 close(p[1]); 106 goto nospace; 107 } 108 if (!pid) { 109 if (p[1] == 1) fcntl(1, F_SETFD, 0); 110 else dup2(p[1], 1); 111 execl("/bin/sh", "sh", "-c", 112 "eval \"printf %s\\\\\\\\0 x $1 $2\"", 113 "sh", s, redir, (char *)0); 114 _exit(1); 115 } 116 close(p[1]); 117 118 f = fdopen(p[0], "r"); 119 if (!f) { 120 close(p[0]); 121 kill(pid, SIGKILL); 122 reap(pid); 123 goto nospace; 124 } 125 126 l = wv ? i+1 : 0; 127 128 free(getword(f)); 129 if (feof(f)) { 130 fclose(f); 131 reap(pid); 132 return WRDE_SYNTAX; 133 } 134 135 while ((w = getword(f))) { 136 if (i+1 >= l) { 137 l += l/2+10; 138 tmp = realloc(wv, l*sizeof(char *)); 139 if (!tmp) break; 140 wv = tmp; 141 } 142 wv[i++] = w; 143 wv[i] = 0; 144 } 145 if (!feof(f)) err = WRDE_NOSPACE; 146 147 fclose(f); 148 reap(pid); 149 150 if (!wv) wv = calloc(i+1, sizeof *wv); 151 152 we->we_wordv = wv; 153 we->we_wordc = i; 154 155 if (flags & WRDE_DOOFFS) { 156 if (wv) for (i=we->we_offs; i; i--) 157 we->we_wordv[i-1] = 0; 158 we->we_wordc -= we->we_offs; 159 } 160 return err; 161 162 nospace: 163 if (!(flags & WRDE_APPEND)) { 164 we->we_wordc = 0; 165 we->we_wordv = 0; 166 } 167 return WRDE_NOSPACE; 168 } 169 170 int wordexp(const char *restrict s, wordexp_t *restrict we, int flags) 171 { 172 int r, cs; 173 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); 174 r = do_wordexp(s, we, flags); 175 pthread_setcancelstate(cs, 0); 176 return r; 177 } 178 179 void wordfree(wordexp_t *we) 180 { 181 size_t i; 182 if (!we->we_wordv) return; 183 for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]); 184 free(we->we_wordv); 185 we->we_wordv = 0; 186 we->we_wordc = 0; 187 }