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 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 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 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 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 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 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 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 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 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 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 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