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