xref: /freebsd/lib/libc/tests/gen/wordexp_test.c (revision 42249ef2)
1 /*-
2  * Copyright (c) 2003 Tim J. Robbins
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * Test program for wordexp() and wordfree() as specified by
29  * IEEE Std. 1003.1-2001.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/wait.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <wordexp.h>
42 
43 #include <atf-c.h>
44 
45 static void
46 chld_handler(int x)
47 {
48 	int status, serrno;
49 
50 	(void)x;
51 	serrno = errno;
52 	while (waitpid(-1, &status, WNOHANG) > 0)
53 		;
54 	errno = serrno;
55 }
56 
57 ATF_TC_WITHOUT_HEAD(simple_test);
58 ATF_TC_BODY(simple_test, tc)
59 {
60 	wordexp_t we;
61 	int r;
62 
63 	/* Test that the macros are there. */
64 	(void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
65 	    WRDE_SHOWERR + WRDE_UNDEF);
66 	(void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
67 	    WRDE_SYNTAX);
68 
69 	/* Simple test. */
70 	r = wordexp("hello world", &we, 0);
71 	ATF_REQUIRE(r == 0);
72 	ATF_REQUIRE(we.we_wordc == 2);
73 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
74 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
75 	ATF_REQUIRE(we.we_wordv[2] == NULL);
76 	wordfree(&we);
77 }
78 
79 ATF_TC_WITHOUT_HEAD(long_output_test);
80 ATF_TC_BODY(long_output_test, tc)
81 {
82 	char longdata[6 * 10000 + 1];
83 	wordexp_t we;
84 	int i, r;
85 
86 	/* Long output. */
87 	for (i = 0; i < 10000; i++)
88 		snprintf(longdata + 6 * i, 7, "%05d ", i);
89 	r = wordexp(longdata, &we, 0);
90 	ATF_REQUIRE(r == 0);
91 	ATF_REQUIRE(we.we_wordc == 10000);
92 	ATF_REQUIRE(we.we_wordv[10000] == NULL);
93 	wordfree(&we);
94 }
95 
96 ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
97 ATF_TC_BODY(WRDE_DOOFFS_test, tc)
98 {
99 	wordexp_t we;
100 	int r;
101 
102 	we.we_offs = 3;
103 	r = wordexp("hello world", &we, WRDE_DOOFFS);
104 	ATF_REQUIRE(r == 0);
105 	ATF_REQUIRE(we.we_wordc == 2);
106 	ATF_REQUIRE(we.we_wordv[0] == NULL);
107 	ATF_REQUIRE(we.we_wordv[1] == NULL);
108 	ATF_REQUIRE(we.we_wordv[2] == NULL);
109 	ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0);
110 	ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0);
111 	ATF_REQUIRE(we.we_wordv[5] == NULL);
112 	wordfree(&we);
113 }
114 
115 ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
116 ATF_TC_BODY(WRDE_REUSE_test, tc)
117 {
118 	wordexp_t we;
119 	int r;
120 
121 	r = wordexp("hello world", &we, 0);
122 	r = wordexp("hello world", &we, WRDE_REUSE);
123 	ATF_REQUIRE(r == 0);
124 	ATF_REQUIRE(we.we_wordc == 2);
125 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
126 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
127 	ATF_REQUIRE(we.we_wordv[2] == NULL);
128 	wordfree(&we);
129 }
130 
131 ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
132 ATF_TC_BODY(WRDE_APPEND_test, tc)
133 {
134 	wordexp_t we;
135 	int r;
136 
137 	r = wordexp("this is", &we, 0);
138 	ATF_REQUIRE(r == 0);
139 	r = wordexp("a test", &we, WRDE_APPEND);
140 	ATF_REQUIRE(r == 0);
141 	ATF_REQUIRE(we.we_wordc == 4);
142 	ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0);
143 	ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0);
144 	ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0);
145 	ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0);
146 	ATF_REQUIRE(we.we_wordv[4] == NULL);
147 	wordfree(&we);
148 }
149 
150 ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
151 ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc)
152 {
153 	wordexp_t we;
154 	int r;
155 
156 	we.we_offs = 2;
157 	r = wordexp("this is", &we, WRDE_DOOFFS);
158 	ATF_REQUIRE(r == 0);
159 	r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
160 	ATF_REQUIRE(r == 0);
161 	r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
162 	ATF_REQUIRE(r == 0);
163 	ATF_REQUIRE(we.we_wordc == 6);
164 	ATF_REQUIRE(we.we_wordv[0] == NULL);
165 	ATF_REQUIRE(we.we_wordv[1] == NULL);
166 	ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0);
167 	ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0);
168 	ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0);
169 	ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0);
170 	ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0);
171 	ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0);
172 	ATF_REQUIRE(we.we_wordv[8] == NULL);
173 	wordfree(&we);
174 }
175 
176 ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
177 ATF_TC_BODY(WRDE_UNDEF_test, tc)
178 {
179 	wordexp_t we;
180 	int r;
181 
182 	r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
183 	ATF_REQUIRE(r == WRDE_BADVAL);
184 }
185 
186 ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
187 ATF_TC_BODY(WRDE_NOCMD_test, tc)
188 {
189 	wordexp_t we;
190 	int r;
191 
192 	r = wordexp("`date`", &we, WRDE_NOCMD);
193 	ATF_REQUIRE(r == WRDE_CMDSUB);
194 	r = wordexp("\"`date`\"", &we, WRDE_NOCMD);
195 	ATF_REQUIRE(r == WRDE_CMDSUB);
196 	r = wordexp("$(date)", &we, WRDE_NOCMD);
197 	ATF_REQUIRE(r == WRDE_CMDSUB);
198 	r = wordexp("\"$(date)\"", &we, WRDE_NOCMD);
199 	ATF_REQUIRE(r == WRDE_CMDSUB);
200 	r = wordexp("$((3+5))", &we, WRDE_NOCMD);
201 	ATF_REQUIRE(r == 0);
202 	r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
203 	ATF_REQUIRE(r == 0);
204 	r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE);
205 	ATF_REQUIRE(r == 0);
206 	r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE);
207 	ATF_REQUIRE(r == 0);
208 	wordfree(&we);
209 }
210 
211 ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
212 ATF_TC_BODY(WRDE_BADCHAR_test, tc)
213 {
214 	wordexp_t we;
215 	int r;
216 
217 	r = wordexp("'\n|&;<>(){}'", &we, 0);
218 	ATF_REQUIRE(r == 0);
219 	r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
220 	ATF_REQUIRE(r == 0);
221 	r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
222 	ATF_REQUIRE(r == 0);
223 	wordfree(&we);
224 	r = wordexp("test \n test", &we, 0);
225 	ATF_REQUIRE(r == WRDE_BADCHAR);
226 	r = wordexp("test | test", &we, 0);
227 	ATF_REQUIRE(r == WRDE_BADCHAR);
228 	r = wordexp("test & test", &we, 0);
229 	ATF_REQUIRE(r == WRDE_BADCHAR);
230 	r = wordexp("test ; test", &we, 0);
231 	ATF_REQUIRE(r == WRDE_BADCHAR);
232 	r = wordexp("test > test", &we, 0);
233 	ATF_REQUIRE(r == WRDE_BADCHAR);
234 	r = wordexp("test < test", &we, 0);
235 	ATF_REQUIRE(r == WRDE_BADCHAR);
236 	r = wordexp("test ( test", &we, 0);
237 	ATF_REQUIRE(r == WRDE_BADCHAR);
238 	r = wordexp("test ) test", &we, 0);
239 	ATF_REQUIRE(r == WRDE_BADCHAR);
240 	r = wordexp("test { test", &we, 0);
241 	ATF_REQUIRE(r == WRDE_BADCHAR);
242 	r = wordexp("test } test", &we, 0);
243 	ATF_REQUIRE(r == WRDE_BADCHAR);
244 }
245 
246 ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
247 ATF_TC_BODY(WRDE_SYNTAX_test, tc)
248 {
249 	wordexp_t we;
250 	int r;
251 
252 	r = wordexp("'", &we, 0);
253 	ATF_REQUIRE(r == WRDE_SYNTAX);
254 	r = wordexp("'", &we, WRDE_UNDEF);
255 	ATF_REQUIRE(r == WRDE_SYNTAX);
256 	r = wordexp("'\\'", &we, 0);
257 	ATF_REQUIRE(r == 0);
258 	ATF_REQUIRE(we.we_wordc == 1);
259 	ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0);
260 	ATF_REQUIRE(we.we_wordv[1] == NULL);
261 	wordfree(&we);
262 	/* Two syntax errors that are not detected by the current we_check(). */
263 	r = wordexp("${IFS:+'}", &we, 0);
264 	ATF_REQUIRE(r == WRDE_SYNTAX);
265 	r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
266 	ATF_REQUIRE(r == WRDE_SYNTAX);
267 	r = wordexp("$(case)", &we, 0);
268 	ATF_REQUIRE(r == WRDE_SYNTAX);
269 	r = wordexp("$(case)", &we, WRDE_UNDEF);
270 	ATF_REQUIRE(r == WRDE_SYNTAX);
271 }
272 
273 ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
274 ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
275 {
276 	struct sigaction sa;
277 	wordexp_t we;
278 	int r;
279 
280 	/* With a SIGCHLD handler that reaps all zombies. */
281 	sa.sa_flags = 0;
282 	sigemptyset(&sa.sa_mask);
283 	sa.sa_handler = chld_handler;
284 	r = sigaction(SIGCHLD, &sa, NULL);
285 	ATF_REQUIRE(r == 0);
286 	r = wordexp("hello world", &we, 0);
287 	ATF_REQUIRE(r == 0);
288 	ATF_REQUIRE(we.we_wordc == 2);
289 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
290 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
291 	ATF_REQUIRE(we.we_wordv[2] == NULL);
292 	wordfree(&we);
293 	sa.sa_handler = SIG_DFL;
294 	r = sigaction(SIGCHLD, &sa, NULL);
295 	ATF_REQUIRE(r == 0);
296 }
297 
298 ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
299 ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
300 {
301 	wordexp_t we;
302 	int r;
303 
304 	/*
305 	 * With IFS set to a non-default value (without depending on whether
306 	 * IFS is inherited or not).
307 	 */
308 	r = setenv("IFS", ":", 1);
309 	ATF_REQUIRE(r == 0);
310 	r = wordexp("hello world", &we, 0);
311 	ATF_REQUIRE(r == 0);
312 	ATF_REQUIRE(we.we_wordc == 2);
313 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
314 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
315 	ATF_REQUIRE(we.we_wordv[2] == NULL);
316 	wordfree(&we);
317 	r = unsetenv("IFS");
318 	ATF_REQUIRE(r == 0);
319 }
320 
321 ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
322 ATF_TC_BODY(with_used_non_default_IFS_test, tc)
323 {
324 	wordexp_t we;
325 	int r;
326 
327 	/*
328 	 * With IFS set to a non-default value, and using it.
329 	 */
330 	r = setenv("IFS", ":", 1);
331 	ATF_REQUIRE(r == 0);
332 	r = wordexp("${IFS+hello:world}", &we, 0);
333 	ATF_REQUIRE(r == 0);
334 	ATF_REQUIRE(we.we_wordc == 2);
335 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
336 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
337 	ATF_REQUIRE(we.we_wordv[2] == NULL);
338 	wordfree(&we);
339 	r = unsetenv("IFS");
340 	ATF_REQUIRE(r == 0);
341 }
342 
343 ATF_TP_ADD_TCS(tp)
344 {
345 	ATF_TP_ADD_TC(tp, simple_test);
346 	ATF_TP_ADD_TC(tp, long_output_test);
347 	ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test);
348 	ATF_TP_ADD_TC(tp, WRDE_REUSE_test);
349 	ATF_TP_ADD_TC(tp, WRDE_APPEND_test);
350 	ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test);
351 	ATF_TP_ADD_TC(tp, WRDE_UNDEF_test);
352 	ATF_TP_ADD_TC(tp, WRDE_NOCMD_test);
353 	ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
354 	ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
355 	ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
356 	ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
357 	ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
358 
359 	return (atf_no_error());
360 }
361