loongarch64: add new syscall numbers
[musl.git] / src / misc / wordexp.c
blobdb83a69f37d996aa2a9f61bde18a60c06a727505
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"
14 static void reap(pid_t pid)
16 int status;
17 while (waitpid(pid, &status, 0) < 0 && errno == EINTR);
20 static char *getword(FILE *f)
22 char *s = 0;
23 return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
26 static int do_wordexp(const char *s, wordexp_t *we, int flags)
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;
41 if (flags & WRDE_REUSE) wordfree(we);
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;
58 case ')':
59 if (np) {
60 np--;
61 break;
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;
85 if (flags & WRDE_APPEND) {
86 wc = we->we_wordc;
87 wv = we->we_wordv;
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;
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;
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);
116 close(p[1]);
118 f = fdopen(p[0], "r");
119 if (!f) {
120 close(p[0]);
121 kill(pid, SIGKILL);
122 reap(pid);
123 goto nospace;
126 l = wv ? i+1 : 0;
128 free(getword(f));
129 if (feof(f)) {
130 fclose(f);
131 reap(pid);
132 return WRDE_SYNTAX;
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;
142 wv[i++] = w;
143 wv[i] = 0;
145 if (!feof(f)) err = WRDE_NOSPACE;
147 fclose(f);
148 reap(pid);
150 if (!wv) wv = calloc(i+1, sizeof *wv);
152 we->we_wordv = wv;
153 we->we_wordc = i;
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;
160 return err;
162 nospace:
163 if (!(flags & WRDE_APPEND)) {
164 we->we_wordc = 0;
165 we->we_wordv = 0;
167 return WRDE_NOSPACE;
170 int wordexp(const char *restrict s, wordexp_t *restrict we, int flags)
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;
179 void wordfree(wordexp_t *we)
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;