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: releng/10.3/lib/libc/tests/gen/wordexp_test.c 291190 2015-11-23 10:53:01Z ngie $");
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
45static void
46chld_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
57ATF_TC_WITHOUT_HEAD(simple_test);
58ATF_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
79ATF_TC_WITHOUT_HEAD(long_output_test);
80ATF_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
96ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
97ATF_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
115ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
116ATF_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
131ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
132ATF_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
150ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
151ATF_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
176ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
177ATF_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
186ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
187ATF_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
211ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
212ATF_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
246ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
247ATF_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
273ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
274ATF_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
298ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
299ATF_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
321ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
322ATF_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
343ATF_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