wordexp.c 3.2 KB

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