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