1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008, 2009, 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/wait.h> 31 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "atf-c/build.h" 40 #include "atf-c/check.h" 41 #include "atf-c/config.h" 42 #include "atf-c/defs.h" 43 #include "atf-c/dynstr.h" 44 #include "atf-c/error.h" 45 #include "atf-c/fs.h" 46 #include "atf-c/list.h" 47 #include "atf-c/process.h" 48 #include "atf-c/sanity.h" 49 50 /* --------------------------------------------------------------------- 51 * Auxiliary functions. 52 * --------------------------------------------------------------------- */ 53 54 static 55 atf_error_t 56 create_tmpdir(atf_fs_path_t *dir) 57 { 58 atf_error_t err; 59 60 err = atf_fs_path_init_fmt(dir, "%s/check.XXXXXX", 61 atf_config_get("atf_workdir")); 62 if (atf_is_error(err)) 63 goto out; 64 65 err = atf_fs_mkdtemp(dir); 66 if (atf_is_error(err)) { 67 atf_fs_path_fini(dir); 68 goto out; 69 } 70 71 INV(!atf_is_error(err)); 72 out: 73 return err; 74 } 75 76 static 77 void 78 cleanup_tmpdir(const atf_fs_path_t *dir, const atf_fs_path_t *outfile, 79 const atf_fs_path_t *errfile) 80 { 81 { 82 atf_error_t err = atf_fs_unlink(outfile); 83 if (atf_is_error(err)) { 84 INV(atf_error_is(err, "libc") && 85 atf_libc_error_code(err) == ENOENT); 86 atf_error_free(err); 87 } else 88 INV(!atf_is_error(err)); 89 } 90 91 { 92 atf_error_t err = atf_fs_unlink(errfile); 93 if (atf_is_error(err)) { 94 INV(atf_error_is(err, "libc") && 95 atf_libc_error_code(err) == ENOENT); 96 atf_error_free(err); 97 } else 98 INV(!atf_is_error(err)); 99 } 100 101 { 102 atf_error_t err = atf_fs_rmdir(dir); 103 INV(!atf_is_error(err)); 104 } 105 } 106 107 static 108 int 109 const_execvp(const char *file, const char *const *argv) 110 { 111 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 112 return execvp(file, UNCONST(argv)); 113 #undef UNCONST 114 } 115 116 static 117 atf_error_t 118 init_sb(const atf_fs_path_t *path, atf_process_stream_t *sb) 119 { 120 atf_error_t err; 121 122 if (path == NULL) 123 err = atf_process_stream_init_inherit(sb); 124 else 125 err = atf_process_stream_init_redirect_path(sb, path); 126 127 return err; 128 } 129 130 static 131 atf_error_t 132 init_sbs(const atf_fs_path_t *outfile, atf_process_stream_t *outsb, 133 const atf_fs_path_t *errfile, atf_process_stream_t *errsb) 134 { 135 atf_error_t err; 136 137 err = init_sb(outfile, outsb); 138 if (atf_is_error(err)) 139 goto out; 140 141 err = init_sb(errfile, errsb); 142 if (atf_is_error(err)) { 143 atf_process_stream_fini(outsb); 144 goto out; 145 } 146 147 out: 148 return err; 149 } 150 151 struct exec_data { 152 const char *const *m_argv; 153 }; 154 155 static void exec_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN; 156 157 static 158 void 159 exec_child(void *v) 160 { 161 struct exec_data *ea = v; 162 163 const_execvp(ea->m_argv[0], ea->m_argv); 164 fprintf(stderr, "execvp(%s) failed: %s\n", ea->m_argv[0], strerror(errno)); 165 exit(127); 166 } 167 168 static 169 atf_error_t 170 fork_and_wait(const char *const *argv, const atf_fs_path_t *outfile, 171 const atf_fs_path_t *errfile, atf_process_status_t *status) 172 { 173 atf_error_t err; 174 atf_process_child_t child; 175 atf_process_stream_t outsb, errsb; 176 struct exec_data ea = { argv }; 177 178 err = init_sbs(outfile, &outsb, errfile, &errsb); 179 if (atf_is_error(err)) 180 goto out; 181 182 err = atf_process_fork(&child, exec_child, &outsb, &errsb, &ea); 183 if (atf_is_error(err)) 184 goto out_sbs; 185 186 err = atf_process_child_wait(&child, status); 187 188 out_sbs: 189 atf_process_stream_fini(&errsb); 190 atf_process_stream_fini(&outsb); 191 out: 192 return err; 193 } 194 195 static 196 void 197 update_success_from_status(const char *progname, 198 const atf_process_status_t *status, bool *success) 199 { 200 bool s = atf_process_status_exited(status) && 201 atf_process_status_exitstatus(status) == EXIT_SUCCESS; 202 203 if (atf_process_status_exited(status)) { 204 if (atf_process_status_exitstatus(status) == EXIT_SUCCESS) 205 INV(s); 206 else { 207 INV(!s); 208 fprintf(stderr, "%s failed with exit code %d\n", progname, 209 atf_process_status_exitstatus(status)); 210 } 211 } else if (atf_process_status_signaled(status)) { 212 INV(!s); 213 fprintf(stderr, "%s failed due to signal %d%s\n", progname, 214 atf_process_status_termsig(status), 215 atf_process_status_coredump(status) ? " (core dumped)" : ""); 216 } else { 217 INV(!s); 218 fprintf(stderr, "%s failed due to unknown reason\n", progname); 219 } 220 221 *success = s; 222 } 223 224 static 225 atf_error_t 226 array_to_list(const char *const *a, atf_list_t *l) 227 { 228 atf_error_t err; 229 230 err = atf_list_init(l); 231 if (atf_is_error(err)) 232 goto out; 233 234 while (*a != NULL) { 235 char *item = strdup(*a); 236 if (item == NULL) { 237 err = atf_no_memory_error(); 238 goto out; 239 } 240 241 err = atf_list_append(l, item, true); 242 if (atf_is_error(err)) 243 goto out; 244 245 a++; 246 } 247 248 out: 249 return err; 250 } 251 252 static 253 atf_error_t 254 list_to_array(const atf_list_t *l, const char ***ap) 255 { 256 atf_error_t err; 257 const char **a; 258 259 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *)); 260 if (a == NULL) 261 err = atf_no_memory_error(); 262 else { 263 const char **aiter; 264 atf_list_citer_t liter; 265 266 aiter = a; 267 atf_list_for_each_c(liter, l) { 268 *aiter = (const char *)atf_list_citer_data(liter); 269 aiter++; 270 } 271 *aiter = NULL; 272 273 err = atf_no_error(); 274 *ap = a; 275 } 276 277 return err; 278 } 279 280 static 281 void 282 print_list(const atf_list_t *l, const char *pfx) 283 { 284 atf_list_citer_t iter; 285 286 printf("%s", pfx); 287 atf_list_for_each_c(iter, l) 288 printf(" %s", (const char *)atf_list_citer_data(iter)); 289 printf("\n"); 290 } 291 292 static 293 atf_error_t 294 fork_and_wait_list(const atf_list_t *argvl, const atf_fs_path_t *outfile, 295 const atf_fs_path_t *errfile, atf_process_status_t *status) 296 { 297 atf_error_t err; 298 const char **argva; 299 300 err = list_to_array(argvl, &argva); 301 if (atf_is_error(err)) 302 goto out; 303 304 err = fork_and_wait(argva, outfile, errfile, status); 305 306 free(argva); 307 out: 308 return err; 309 } 310 311 static 312 atf_error_t 313 check_build_run(const atf_list_t *argv, bool *success) 314 { 315 atf_error_t err; 316 atf_process_status_t status; 317 318 print_list(argv, ">"); 319 320 err = fork_and_wait_list(argv, NULL, NULL, &status); 321 if (atf_is_error(err)) 322 goto out; 323 324 update_success_from_status((const char *)atf_list_index_c(argv, 0), 325 &status, success); 326 atf_process_status_fini(&status); 327 328 INV(!atf_is_error(err)); 329 out: 330 return err; 331 } 332 333 /* --------------------------------------------------------------------- 334 * The "atf_check_result" type. 335 * --------------------------------------------------------------------- */ 336 337 static 338 atf_error_t 339 atf_check_result_init(atf_check_result_t *r, const char *const *argv, 340 const atf_fs_path_t *dir) 341 { 342 atf_error_t err; 343 const char *workdir; 344 345 workdir = atf_config_get("atf_workdir"); 346 347 err = array_to_list(argv, &r->m_argv); 348 if (atf_is_error(err)) 349 goto out; 350 351 err = atf_fs_path_copy(&r->m_dir, dir); 352 if (atf_is_error(err)) 353 goto err_argv; 354 355 err = atf_fs_path_init_fmt(&r->m_stdout, "%s/stdout", 356 atf_fs_path_cstring(dir)); 357 if (atf_is_error(err)) 358 goto err_dir; 359 360 err = atf_fs_path_init_fmt(&r->m_stderr, "%s/stderr", 361 atf_fs_path_cstring(dir)); 362 if (atf_is_error(err)) 363 goto err_stdout; 364 365 INV(!atf_is_error(err)); 366 goto out; 367 368 err_stdout: 369 atf_fs_path_fini(&r->m_stdout); 370 err_dir: 371 atf_fs_path_fini(&r->m_dir); 372 err_argv: 373 atf_list_fini(&r->m_argv); 374 out: 375 return err; 376 } 377 378 void 379 atf_check_result_fini(atf_check_result_t *r) 380 { 381 atf_process_status_fini(&r->m_status); 382 383 cleanup_tmpdir(&r->m_dir, &r->m_stdout, &r->m_stderr); 384 atf_fs_path_fini(&r->m_stdout); 385 atf_fs_path_fini(&r->m_stderr); 386 atf_fs_path_fini(&r->m_dir); 387 388 atf_list_fini(&r->m_argv); 389 } 390 391 const atf_list_t * 392 atf_check_result_argv(const atf_check_result_t *r) 393 { 394 return &r->m_argv; 395 } 396 397 const atf_fs_path_t * 398 atf_check_result_stdout(const atf_check_result_t *r) 399 { 400 return &r->m_stdout; 401 } 402 403 const atf_fs_path_t * 404 atf_check_result_stderr(const atf_check_result_t *r) 405 { 406 return &r->m_stderr; 407 } 408 409 bool 410 atf_check_result_exited(const atf_check_result_t *r) 411 { 412 return atf_process_status_exited(&r->m_status); 413 } 414 415 int 416 atf_check_result_exitcode(const atf_check_result_t *r) 417 { 418 return atf_process_status_exitstatus(&r->m_status); 419 } 420 421 bool 422 atf_check_result_signaled(const atf_check_result_t *r) 423 { 424 return atf_process_status_signaled(&r->m_status); 425 } 426 427 int 428 atf_check_result_termsig(const atf_check_result_t *r) 429 { 430 return atf_process_status_termsig(&r->m_status); 431 } 432 433 /* --------------------------------------------------------------------- 434 * Free functions. 435 * --------------------------------------------------------------------- */ 436 437 /* XXX: This function shouldn't be in this module. It messes with stdout 438 * and stderr, and it provides a very high-end interface. This belongs, 439 * probably, somewhere related to test cases (such as in the tc module). */ 440 atf_error_t 441 atf_check_build_c_o(const char *sfile, 442 const char *ofile, 443 const char *const optargs[], 444 bool *success) 445 { 446 atf_error_t err; 447 atf_list_t argv; 448 449 err = atf_build_c_o(sfile, ofile, optargs, &argv); 450 if (atf_is_error(err)) 451 goto out; 452 453 err = check_build_run(&argv, success); 454 455 atf_list_fini(&argv); 456 out: 457 return err; 458 } 459 460 atf_error_t 461 atf_check_build_cpp(const char *sfile, 462 const char *ofile, 463 const char *const optargs[], 464 bool *success) 465 { 466 atf_error_t err; 467 atf_list_t argv; 468 469 err = atf_build_cpp(sfile, ofile, optargs, &argv); 470 if (atf_is_error(err)) 471 goto out; 472 473 err = check_build_run(&argv, success); 474 475 atf_list_fini(&argv); 476 out: 477 return err; 478 } 479 480 atf_error_t 481 atf_check_build_cxx_o(const char *sfile, 482 const char *ofile, 483 const char *const optargs[], 484 bool *success) 485 { 486 atf_error_t err; 487 atf_list_t argv; 488 489 err = atf_build_cxx_o(sfile, ofile, optargs, &argv); 490 if (atf_is_error(err)) 491 goto out; 492 493 err = check_build_run(&argv, success); 494 495 atf_list_fini(&argv); 496 out: 497 return err; 498 } 499 500 atf_error_t 501 atf_check_exec_array(const char *const *argv, atf_check_result_t *r) 502 { 503 atf_error_t err; 504 atf_fs_path_t dir; 505 506 err = create_tmpdir(&dir); 507 if (atf_is_error(err)) 508 goto out; 509 510 err = atf_check_result_init(r, argv, &dir); 511 if (atf_is_error(err)) 512 goto err_dir; 513 514 err = fork_and_wait(argv, &r->m_stdout, &r->m_stderr, &r->m_status); 515 if (atf_is_error(err)) 516 goto err_r; 517 518 INV(!atf_is_error(err)); 519 goto out_dir; 520 521 err_r: 522 atf_check_result_fini(r); 523 err_dir: 524 { 525 atf_error_t err2 = atf_fs_rmdir(&dir); 526 INV(!atf_is_error(err2)); 527 } 528 out_dir: 529 atf_fs_path_fini(&dir); 530 out: 531 return err; 532 } 533 534 atf_error_t 535 atf_check_exec_list(const atf_list_t *argv, atf_check_result_t *r) 536 { 537 atf_error_t err; 538 const char **argv2; 539 540 argv2 = NULL; /* Silence GCC warning. */ 541 err = list_to_array(argv, &argv2); 542 if (atf_is_error(err)) 543 goto out; 544 545 err = atf_check_exec_array(argv2, r); 546 547 free(argv2); 548 out: 549 return err; 550 } 551