xref: /minix3/minix/tests/test84.c (revision 1facb0487c831b9ead49737c23d6f936b553009b)
1 /*
2  * Based off tests/lib/libc/gen/posix_spawn/t_spawn.c
3  */
4 
5 /* $NetBSD: t_spawn.c,v 1.1 2012/02/13 21:03:08 martin Exp $ */
6 
7 /*-
8  * Copyright (c) 2012 The NetBSD Foundation, Inc.
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to The NetBSD Foundation
12  * by Charles Zhang <charles@NetBSD.org> and
13  * Martin Husemann <martin@NetBSD.org>.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <spawn.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <errno.h>
44 #include <sys/wait.h>
45 
46 #include "common.h"
47 
48 /* reroute stdout to /dev/null while returning another fd for the old stdout */
49 /* this is just for aesthetics: we don't want to see the output of 'ls' */
50 static int
sink_stdout(void)51 sink_stdout(void)
52 {
53 	int fd, fd2;
54 
55 	if ((fd = fcntl(1, F_DUPFD, 3)) == -1 || close(1) == -1) {
56 		e(0);
57 		quit();
58 	}
59 
60 	if ((fd2 = open("/dev/null", O_WRONLY)) != 1) {
61 		if (fd2 == -1 || dup2(fd2, 1) != 1) {
62 			dup2(fd, 1);
63 			e(0);
64 			quit();
65 		}
66 	}
67 
68 	return fd;
69 }
70 
71 /* restore stdout */
72 static void
restore_stdout(int fd)73 restore_stdout(int fd)
74 {
75 
76 	dup2(fd, 1);
77 	close(fd);
78 }
79 
80 /* tests a simple posix_spawn executing /bin/ls */
81 static void
test_posix_spawn_ls(void)82 test_posix_spawn_ls(void)
83 {
84 	char * const args[] = { "ls", "-la", NULL };
85 	int err;
86 
87 	err = posix_spawn(NULL, "/bin/ls", NULL, NULL, args, NULL);
88 	if (err != 0)
89 		e(1);
90 }
91 
92 /* tests a simple posix_spawnp executing ls via $PATH */
93 static void
test_posix_spawnp_ls(void)94 test_posix_spawnp_ls(void)
95 {
96 	char * const args[] = { "ls", "-la", NULL };
97 	int err;
98 
99 	err = posix_spawnp(NULL, "ls", NULL, NULL, args, NULL);
100 	if(err != 0)
101 		e(2);
102 }
103 
104 /* posix_spawn a non existant binary */
105 static void
test_posix_spawn_missing(void)106 test_posix_spawn_missing(void)
107 {
108 	char * const args[] = { "t84_h_nonexist", NULL };
109 	int err;
110 
111 	err = posix_spawn(NULL, "../t84_h_nonexist", NULL, NULL, args, NULL);
112 	if (err != ENOENT)
113 		e(4);
114 }
115 
116 /* posix_spawn a script with non existing interpreter */
117 static void
test_posix_spawn_nonexec(void)118 test_posix_spawn_nonexec(void)
119 {
120 	char * const args[] = { "t84_h_nonexec", NULL };
121 	int err;
122 
123 	err = posix_spawn(NULL, "../t84_h_nonexec", NULL, NULL, args, NULL);
124 	if (err != ENOENT)
125 		e(5);
126 }
127 
128 /* posix_spawn a child and get it's return code */
129 static void
test_posix_spawn_child(void)130 test_posix_spawn_child(void)
131 {
132 	char * const args0[] = { "t84_h_spawn", "0", NULL };
133 	char * const args1[] = { "t84_h_spawn", "1", NULL };
134 	char * const args7[] = { "t84_h_spawn", "7", NULL };
135 	int err, status;
136 	pid_t pid;
137 
138 	err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args0, NULL);
139 	if (err != 0 || pid < 1)
140 		e(1);
141 	waitpid(pid, &status, 0);
142 	if (! (WIFEXITED(status) && WEXITSTATUS(status) == 0))
143 		e(2);
144 
145 	err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args1, NULL);
146 	if (err != 0 || pid < 1)
147 		e(3);
148 	waitpid(pid, &status, 0);
149 	if (! (WIFEXITED(status) && WEXITSTATUS(status) == 1))
150 		e(4);
151 
152 	err = posix_spawn(&pid, "../t84_h_spawn", NULL, NULL, args7, NULL);
153 	if (err != 0 || pid < 1)
154 		e(5);
155 	waitpid(pid, &status, 0);
156 	if (! (WIFEXITED(status) && WEXITSTATUS(status) == 7))
157 		e(6);
158 }
159 
160 /* test spawn attributes */
161 static void
test_posix_spawnattr(void)162 test_posix_spawnattr(void)
163 {
164 	int pid, status, err, pfd[2];
165 	char helper_arg[128];
166 	char * const args[] = { "t84_h_spawnattr", helper_arg, NULL };
167 	sigset_t sig;
168 	posix_spawnattr_t attr;
169 
170 	/*
171 	 * create a pipe to controll the child
172 	 */
173 	err = pipe(pfd);
174 	if (err != 0)
175 		e(1);
176 	sprintf(helper_arg, "%d", pfd[0]);
177 
178 	posix_spawnattr_init(&attr);
179 
180 	sigemptyset(&sig);
181 	sigaddset(&sig, SIGUSR1);
182 
183 	posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDULER |
184 		POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETPGROUP |
185 		POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
186 		POSIX_SPAWN_SETSIGDEF);
187 	posix_spawnattr_setpgroup(&attr, 0);
188 #if 0
189 	posix_spawnattr_setschedparam(&attr, &sp);
190 	posix_spawnattr_setschedpolicy(&attr, scheduler);
191 #endif
192 	posix_spawnattr_setsigmask(&attr, &sig);
193 	posix_spawnattr_setsigdefault(&attr, &sig);
194 
195 	err = posix_spawn(&pid, "../t84_h_spawnattr", NULL, &attr, args, NULL);
196 	if (err != 0)
197 		e(2);
198 
199 	/* ready, let child go */
200 	write(pfd[1], "q", 1);
201 	close(pfd[0]);
202 	close(pfd[1]);
203 
204 	/* wait and check result from child */
205 	waitpid(pid, &status, 0);
206 	if (! (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS))
207 		e(3);
208 
209 	posix_spawnattr_destroy(&attr);
210 }
211 
212 /* tests a simple posix_spawn executing /bin/ls with file actions */
213 static void
test_posix_spawn_file_actions(void)214 test_posix_spawn_file_actions(void)
215 {
216 	char * const args[] = { "ls", "-la", NULL };
217 	int err;
218 	posix_spawn_file_actions_t file_actions;
219 
220 	/*
221 	 * Just do a bunch of random operations which should leave console
222 	 * output intact.
223 	 */
224 	posix_spawn_file_actions_init(&file_actions);
225 	posix_spawn_file_actions_adddup2(&file_actions, 1, 3);
226 	posix_spawn_file_actions_adddup2(&file_actions, 1, 4);
227 	posix_spawn_file_actions_adddup2(&file_actions, 1, 6);
228 	posix_spawn_file_actions_adddup2(&file_actions, 1, 5);
229 	posix_spawn_file_actions_addclose(&file_actions, 3);
230 	posix_spawn_file_actions_addclose(&file_actions, 4);
231 	posix_spawn_file_actions_addclose(&file_actions, 6);
232 	posix_spawn_file_actions_addclose(&file_actions, 5);
233 
234 	posix_spawn_file_actions_addclose(&file_actions, 0);
235 	posix_spawn_file_actions_addclose(&file_actions, 2);
236 	posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null",
237 	    O_RDONLY, 0);
238 	posix_spawn_file_actions_adddup2(&file_actions, 1, 2);
239 	posix_spawn_file_actions_addclose(&file_actions, 1);
240 	posix_spawn_file_actions_adddup2(&file_actions, 2, 1);
241 
242 	err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args, NULL);
243 	posix_spawn_file_actions_destroy(&file_actions);
244 
245 	if (err != 0)
246 		e(1);
247 }
248 
249 /* tests failures with file actions */
250 static void
test_posix_spawn_file_actions_failures(void)251 test_posix_spawn_file_actions_failures(void)
252 {
253 	char * const args[] = { "ls", "-la", NULL };
254 	int err, i;
255 	posix_spawn_file_actions_t file_actions;
256 
257 	/* Test bogus open */
258 	posix_spawn_file_actions_init(&file_actions);
259 	posix_spawn_file_actions_addclose(&file_actions, 0);
260 	posix_spawn_file_actions_addopen(&file_actions, 0, "t84_h_nonexist",
261 	    O_RDONLY, 0);
262 
263 	err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args, NULL);
264 	posix_spawn_file_actions_destroy(&file_actions);
265 
266 	if (err == 0)
267 		e(1);
268 
269 	/* Test bogus dup2 */
270 	for (i = 3; i < 10; i++) {
271 		posix_spawn_file_actions_init(&file_actions);
272 		posix_spawn_file_actions_adddup2(&file_actions, i, i+1);
273 
274 		err = posix_spawn(NULL, "/bin/ls", &file_actions, NULL, args,
275 		    NULL);
276 		posix_spawn_file_actions_destroy(&file_actions);
277 
278 		if (err == 0)
279 			e(i-2);
280 	}
281 
282 	/*
283 	 * Test bogus exec with dup2 (to mess with the pipe error reporting in
284 	 * posix_spawn.c)
285 	 */
286 	posix_spawn_file_actions_init(&file_actions);
287 	posix_spawn_file_actions_adddup2(&file_actions, 1, 3);
288 	posix_spawn_file_actions_adddup2(&file_actions, 1, 4);
289 	posix_spawn_file_actions_adddup2(&file_actions, 1, 6);
290 	posix_spawn_file_actions_adddup2(&file_actions, 1, 5);
291 	posix_spawn_file_actions_adddup2(&file_actions, 1, 7);
292 
293 	err = posix_spawn(NULL, "t84_h_nonexist", &file_actions, NULL, args,
294 	    NULL);
295 	posix_spawn_file_actions_destroy(&file_actions);
296 
297 	if (err == 0)
298 		e(9);
299 }
300 
301 int
main(void)302 main(void)
303 {
304 	int fd;
305 
306 	start(84);
307 
308 	subtest = 1;
309 	fd = sink_stdout();
310 	test_posix_spawn_ls();
311 	test_posix_spawnp_ls();
312 	restore_stdout(fd);
313 
314 	test_posix_spawn_missing();
315 	test_posix_spawn_nonexec();
316 
317 	subtest = 2;
318 	test_posix_spawn_child();
319 
320 	subtest = 3;
321 	test_posix_spawnattr();
322 	subtest = 4;
323 	fd = sink_stdout();
324 	test_posix_spawn_file_actions();
325 	restore_stdout(fd);
326 	subtest = 5;
327 	test_posix_spawn_file_actions_failures();
328 
329 	/* TODO: Write/port more tests */
330 
331 	quit();
332 
333 	/* Not reached */
334 	return -1;
335 }
336