xref: /freebsd/lib/libc/tests/gen/wordexp_test.c (revision 315ee00f)
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 #include <sys/wait.h>
34 #include <errno.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <wordexp.h>
40 
41 #include <atf-c.h>
42 
43 static void
44 chld_handler(int x)
45 {
46 	int status, serrno;
47 
48 	(void)x;
49 	serrno = errno;
50 	while (waitpid(-1, &status, WNOHANG) > 0)
51 		;
52 	errno = serrno;
53 }
54 
55 ATF_TC_WITHOUT_HEAD(simple_test);
56 ATF_TC_BODY(simple_test, tc)
57 {
58 	wordexp_t we;
59 	int r;
60 
61 	/* Test that the macros are there. */
62 	(void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
63 	    WRDE_SHOWERR + WRDE_UNDEF);
64 	(void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
65 	    WRDE_SYNTAX);
66 
67 	/* Simple test. */
68 	r = wordexp("hello world", &we, 0);
69 	ATF_REQUIRE(r == 0);
70 	ATF_REQUIRE(we.we_wordc == 2);
71 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
72 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
73 	ATF_REQUIRE(we.we_wordv[2] == NULL);
74 	wordfree(&we);
75 }
76 
77 ATF_TC_WITHOUT_HEAD(long_output_test);
78 ATF_TC_BODY(long_output_test, tc)
79 {
80 	char longdata[6 * 10000 + 1];
81 	wordexp_t we;
82 	int i, r;
83 
84 	/* Long output. */
85 	for (i = 0; i < 10000; i++)
86 		snprintf(longdata + 6 * i, 7, "%05d ", i);
87 	r = wordexp(longdata, &we, 0);
88 	ATF_REQUIRE(r == 0);
89 	ATF_REQUIRE(we.we_wordc == 10000);
90 	ATF_REQUIRE(we.we_wordv[10000] == NULL);
91 	wordfree(&we);
92 }
93 
94 ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
95 ATF_TC_BODY(WRDE_DOOFFS_test, tc)
96 {
97 	wordexp_t we;
98 	int r;
99 
100 	we.we_offs = 3;
101 	r = wordexp("hello world", &we, WRDE_DOOFFS);
102 	ATF_REQUIRE(r == 0);
103 	ATF_REQUIRE(we.we_wordc == 2);
104 	ATF_REQUIRE(we.we_wordv[0] == NULL);
105 	ATF_REQUIRE(we.we_wordv[1] == NULL);
106 	ATF_REQUIRE(we.we_wordv[2] == NULL);
107 	ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0);
108 	ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0);
109 	ATF_REQUIRE(we.we_wordv[5] == NULL);
110 	wordfree(&we);
111 }
112 
113 ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
114 ATF_TC_BODY(WRDE_REUSE_test, tc)
115 {
116 	wordexp_t we;
117 	int r;
118 
119 	r = wordexp("hello world", &we, 0);
120 	r = wordexp("hello world", &we, WRDE_REUSE);
121 	ATF_REQUIRE(r == 0);
122 	ATF_REQUIRE(we.we_wordc == 2);
123 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
124 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
125 	ATF_REQUIRE(we.we_wordv[2] == NULL);
126 	wordfree(&we);
127 }
128 
129 ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
130 ATF_TC_BODY(WRDE_APPEND_test, tc)
131 {
132 	wordexp_t we;
133 	int r;
134 
135 	r = wordexp("this is", &we, 0);
136 	ATF_REQUIRE(r == 0);
137 	r = wordexp("a test", &we, WRDE_APPEND);
138 	ATF_REQUIRE(r == 0);
139 	ATF_REQUIRE(we.we_wordc == 4);
140 	ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0);
141 	ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0);
142 	ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0);
143 	ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0);
144 	ATF_REQUIRE(we.we_wordv[4] == NULL);
145 	wordfree(&we);
146 }
147 
148 ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
149 ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc)
150 {
151 	wordexp_t we;
152 	int r;
153 
154 	we.we_offs = 2;
155 	r = wordexp("this is", &we, WRDE_DOOFFS);
156 	ATF_REQUIRE(r == 0);
157 	r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
158 	ATF_REQUIRE(r == 0);
159 	r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
160 	ATF_REQUIRE(r == 0);
161 	ATF_REQUIRE(we.we_wordc == 6);
162 	ATF_REQUIRE(we.we_wordv[0] == NULL);
163 	ATF_REQUIRE(we.we_wordv[1] == NULL);
164 	ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0);
165 	ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0);
166 	ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0);
167 	ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0);
168 	ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0);
169 	ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0);
170 	ATF_REQUIRE(we.we_wordv[8] == NULL);
171 	wordfree(&we);
172 }
173 
174 ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
175 ATF_TC_BODY(WRDE_UNDEF_test, tc)
176 {
177 	wordexp_t we;
178 	int r;
179 
180 	r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
181 	ATF_REQUIRE(r == WRDE_BADVAL);
182 }
183 
184 ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
185 ATF_TC_BODY(WRDE_NOCMD_test, tc)
186 {
187 	wordexp_t we;
188 	int r;
189 
190 	r = wordexp("`date`", &we, WRDE_NOCMD);
191 	ATF_REQUIRE(r == WRDE_CMDSUB);
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("$((3+5))", &we, WRDE_NOCMD);
199 	ATF_REQUIRE(r == 0);
200 	r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
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 	wordfree(&we);
207 }
208 
209 ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
210 ATF_TC_BODY(WRDE_BADCHAR_test, tc)
211 {
212 	wordexp_t we;
213 	int r;
214 
215 	r = wordexp("'\n|&;<>(){}'", &we, 0);
216 	ATF_REQUIRE(r == 0);
217 	r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
218 	ATF_REQUIRE(r == 0);
219 	r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
220 	ATF_REQUIRE(r == 0);
221 	wordfree(&we);
222 	r = wordexp("test \n test", &we, 0);
223 	ATF_REQUIRE(r == WRDE_BADCHAR);
224 	r = wordexp("test | 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 }
243 
244 ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
245 ATF_TC_BODY(WRDE_SYNTAX_test, tc)
246 {
247 	wordexp_t we;
248 	int r;
249 
250 	r = wordexp("'", &we, 0);
251 	ATF_REQUIRE(r == WRDE_SYNTAX);
252 	r = wordexp("'", &we, WRDE_UNDEF);
253 	ATF_REQUIRE(r == WRDE_SYNTAX);
254 	r = wordexp("'\\'", &we, 0);
255 	ATF_REQUIRE(r == 0);
256 	ATF_REQUIRE(we.we_wordc == 1);
257 	ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0);
258 	ATF_REQUIRE(we.we_wordv[1] == NULL);
259 	wordfree(&we);
260 	/* Two syntax errors that are not detected by the current we_check(). */
261 	r = wordexp("${IFS:+'}", &we, 0);
262 	ATF_REQUIRE(r == WRDE_SYNTAX);
263 	r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
264 	ATF_REQUIRE(r == WRDE_SYNTAX);
265 	r = wordexp("$(case)", &we, 0);
266 	ATF_REQUIRE(r == WRDE_SYNTAX);
267 	r = wordexp("$(case)", &we, WRDE_UNDEF);
268 	ATF_REQUIRE(r == WRDE_SYNTAX);
269 }
270 
271 ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
272 ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
273 {
274 	struct sigaction sa;
275 	wordexp_t we;
276 	int r;
277 
278 	/* With a SIGCHLD handler that reaps all zombies. */
279 	sa.sa_flags = 0;
280 	sigemptyset(&sa.sa_mask);
281 	sa.sa_handler = chld_handler;
282 	r = sigaction(SIGCHLD, &sa, NULL);
283 	ATF_REQUIRE(r == 0);
284 	r = wordexp("hello world", &we, 0);
285 	ATF_REQUIRE(r == 0);
286 	ATF_REQUIRE(we.we_wordc == 2);
287 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
288 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
289 	ATF_REQUIRE(we.we_wordv[2] == NULL);
290 	wordfree(&we);
291 	sa.sa_handler = SIG_DFL;
292 	r = sigaction(SIGCHLD, &sa, NULL);
293 	ATF_REQUIRE(r == 0);
294 }
295 
296 ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
297 ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
298 {
299 	wordexp_t we;
300 	int r;
301 
302 	/*
303 	 * With IFS set to a non-default value (without depending on whether
304 	 * IFS is inherited or not).
305 	 */
306 	r = setenv("IFS", ":", 1);
307 	ATF_REQUIRE(r == 0);
308 	r = wordexp("hello world", &we, 0);
309 	ATF_REQUIRE(r == 0);
310 	ATF_REQUIRE(we.we_wordc == 2);
311 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
312 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
313 	ATF_REQUIRE(we.we_wordv[2] == NULL);
314 	wordfree(&we);
315 	r = unsetenv("IFS");
316 	ATF_REQUIRE(r == 0);
317 }
318 
319 ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
320 ATF_TC_BODY(with_used_non_default_IFS_test, tc)
321 {
322 	wordexp_t we;
323 	int r;
324 
325 	/*
326 	 * With IFS set to a non-default value, and using it.
327 	 */
328 	r = setenv("IFS", ":", 1);
329 	ATF_REQUIRE(r == 0);
330 	r = wordexp("${IFS+hello:world}", &we, 0);
331 	ATF_REQUIRE(r == 0);
332 	ATF_REQUIRE(we.we_wordc == 2);
333 	ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
334 	ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
335 	ATF_REQUIRE(we.we_wordv[2] == NULL);
336 	wordfree(&we);
337 	r = unsetenv("IFS");
338 	ATF_REQUIRE(r == 0);
339 }
340 
341 ATF_TP_ADD_TCS(tp)
342 {
343 	ATF_TP_ADD_TC(tp, simple_test);
344 	ATF_TP_ADD_TC(tp, long_output_test);
345 	ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test);
346 	ATF_TP_ADD_TC(tp, WRDE_REUSE_test);
347 	ATF_TP_ADD_TC(tp, WRDE_APPEND_test);
348 	ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test);
349 	ATF_TP_ADD_TC(tp, WRDE_UNDEF_test);
350 	ATF_TP_ADD_TC(tp, WRDE_NOCMD_test);
351 	ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
352 	ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
353 	ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
354 	ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
355 	ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
356 
357 	return (atf_no_error());
358 }
359