protect syslog against cancellation
[musl] / src / misc / wordexp.c
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
9 static char *getword(FILE *f)
10 {
11         char *s = 0;
12         return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
13 }
14
15 int wordexp(const char *s, wordexp_t *we, int flags)
16 {
17         size_t i, l, len;
18         int sq=0, dq=0;
19         size_t np=0;
20         char *cmd, *w, **tmp;
21         char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null";
22         int err = 0, status;
23         FILE *f;
24         size_t wc = 0;
25         char **wv = 0;
26
27         if (flags & WRDE_REUSE) wordfree(we);
28
29         if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) {
30         case '\\':
31                 if (!sq) i++;
32                 break;
33         case '\'':
34                 if (!dq) sq^=1;
35                 break;
36         case '"':
37                 if (!sq) dq^=1;
38                 break;
39         case '(':
40                 if (np) {
41                         np++;
42                         break;
43                 }
44         case ')':
45                 if (np) {
46                         np--;
47                         break;
48                 }
49         case '\n':
50         case '|':
51         case '&':
52         case ';':
53         case '<':
54         case '>':
55         case '{':
56         case '}':
57                 if (!(sq|dq|np)) return WRDE_BADCHAR;
58                 break;
59         case '$':
60                 if (s[i+1]=='(' && s[i+2]=='(') {
61                         i += 2;
62                         np += 2;
63                         break;
64                 } else if (s[i+1] != '(') break;
65         case '`':
66                 if (sq) break;
67                 return WRDE_CMDSUB;
68         }
69
70         if (flags & WRDE_APPEND) {
71                 wc = we->we_wordc;
72                 wv = we->we_wordv;
73         }
74
75         i = wc;
76         if (flags & WRDE_DOOFFS) {
77                 if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
78                         return WRDE_NOSPACE;
79                 i += we->we_offs;
80         }
81
82         len = 50 + strlen(s);
83         cmd = malloc(len);
84         if (!cmd) return WRDE_NOSPACE;
85         snprintf(cmd, len, "printf %%s\\\\0 %s %s", s, redir);
86         f = popen(cmd, "r");
87         free(cmd);
88         if (!f) return WRDE_NOSPACE;
89
90         l = wv ? i+1 : 0;
91
92         while ((w = getword(f))) {
93                 if (i+1 >= l) {
94                         l += l/2+10;
95                         tmp = realloc(wv, l*sizeof(char *));
96                         if (!tmp) break;
97                         wv = tmp;
98                 }
99                 wv[i++] = w;
100                 wv[i] = 0;
101         }
102         if (!feof(f)) err = WRDE_NOSPACE;
103
104         status = pclose(f);
105         if (WEXITSTATUS(status)) {
106                 if (!(flags & WRDE_APPEND)) {
107                         free(wv);
108                         return WRDE_SYNTAX;
109                 } else if (wv==we->we_wordv) {
110                         return WRDE_SYNTAX;
111                 }
112         }
113
114         we->we_wordv = wv;
115         we->we_wordc = i - we->we_offs;
116         return err;
117 }
118
119 void wordfree(wordexp_t *we)
120 {
121         size_t i;
122         if (!we->we_wordv) return;
123         for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]);
124         free(we->we_wordv);
125         we->we_wordv = 0;
126         we->we_wordc = 0;
127 }