wordexp.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 (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. if (flags & WRDE_APPEND) {
  85. wc = we->we_wordc;
  86. wv = we->we_wordv;
  87. }
  88. i = wc;
  89. if (flags & WRDE_DOOFFS) {
  90. if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
  91. goto nospace;
  92. i += we->we_offs;
  93. } else {
  94. we->we_offs = 0;
  95. }
  96. if (pipe2(p, O_CLOEXEC) < 0) goto nospace;
  97. __block_all_sigs(&set);
  98. pid = fork();
  99. __restore_sigs(&set);
  100. if (pid < 0) {
  101. close(p[0]);
  102. close(p[1]);
  103. goto nospace;
  104. }
  105. if (!pid) {
  106. if (p[1] == 1) fcntl(1, F_SETFD, 0);
  107. else dup2(p[1], 1);
  108. execl("/bin/sh", "sh", "-c",
  109. "eval \"printf %s\\\\\\\\0 x $1 $2\"",
  110. "sh", s, redir, (char *)0);
  111. _exit(1);
  112. }
  113. close(p[1]);
  114. f = fdopen(p[0], "r");
  115. if (!f) {
  116. close(p[0]);
  117. kill(pid, SIGKILL);
  118. reap(pid);
  119. goto nospace;
  120. }
  121. l = wv ? i+1 : 0;
  122. free(getword(f));
  123. if (feof(f)) {
  124. fclose(f);
  125. reap(pid);
  126. return WRDE_SYNTAX;
  127. }
  128. while ((w = getword(f))) {
  129. if (i+1 >= l) {
  130. l += l/2+10;
  131. tmp = realloc(wv, l*sizeof(char *));
  132. if (!tmp) break;
  133. wv = tmp;
  134. }
  135. wv[i++] = w;
  136. wv[i] = 0;
  137. }
  138. if (!feof(f)) err = WRDE_NOSPACE;
  139. fclose(f);
  140. reap(pid);
  141. if (!wv) wv = calloc(i+1, sizeof *wv);
  142. we->we_wordv = wv;
  143. we->we_wordc = i;
  144. if (flags & WRDE_DOOFFS) {
  145. if (wv) for (i=we->we_offs; i; i--)
  146. we->we_wordv[i-1] = 0;
  147. we->we_wordc -= we->we_offs;
  148. }
  149. return err;
  150. nospace:
  151. if (!(flags & WRDE_APPEND)) {
  152. we->we_wordc = 0;
  153. we->we_wordv = 0;
  154. }
  155. return WRDE_NOSPACE;
  156. }
  157. int wordexp(const char *restrict s, wordexp_t *restrict we, int flags)
  158. {
  159. int r, cs;
  160. pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
  161. r = do_wordexp(s, we, flags);
  162. pthread_setcancelstate(cs, 0);
  163. return r;
  164. }
  165. void wordfree(wordexp_t *we)
  166. {
  167. size_t i;
  168. if (!we->we_wordv) return;
  169. for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]);
  170. free(we->we_wordv);
  171. we->we_wordv = 0;
  172. we->we_wordc = 0;
  173. }