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
chld_handler(int x)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);
ATF_TC_BODY(simple_test,tc)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);
ATF_TC_BODY(long_output_test,tc)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);
ATF_TC_BODY(WRDE_DOOFFS_test,tc)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);
ATF_TC_BODY(WRDE_REUSE_test,tc)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);
ATF_TC_BODY(WRDE_APPEND_test,tc)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);
ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test,tc)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);
ATF_TC_BODY(WRDE_UNDEF_test,tc)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);
ATF_TC_BODY(WRDE_NOCMD_test,tc)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);
ATF_TC_BODY(WRDE_BADCHAR_test,tc)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);
ATF_TC_BODY(WRDE_SYNTAX_test,tc)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);
ATF_TC_BODY(with_SIGCHILD_handler_test,tc)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);
ATF_TC_BODY(with_unused_non_default_IFS_test,tc)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);
ATF_TC_BODY(with_used_non_default_IFS_test,tc)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
ATF_TP_ADD_TCS(tp)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