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