diff --git a/runner/executor.c b/runner/executor.c index ab613a8afecc6248345673b3d0c3d6231d045cd4..9c8bf90f0ddd71471880af94d187be35c8846785 100644 --- a/runner/executor.c +++ b/runner/executor.c @@ -577,15 +577,47 @@ bool open_output_files(int dirfd, int *fds, bool write) return true; } +/** + * open_output_files_rdonly: + * @dirfd: fd of output directory with err.txt, dmesg.txt and other files + * @fds: array for fd's of opened output files + * + * Tries to open output files in read-only mode and saves file descriptors + * in fds array. + * + * Returns: true if all files opened, false otherwise + */ +bool open_output_files_rdonly(int dirfd, int *fds) +{ + bool ret = true; + + for (int i = 0; i < _F_LAST; i++) + if ((fds[i] = open_for_reading(dirfd, filenames[i])) < 0) { + fds[i] = -errno; + ret = false; /* Remember failure */ + } + + return ret; +} + void close_outputs(int *fds) { int i; for (i = 0; i < _F_LAST; i++) { - close(fds[i]); + if (fds[i] >= 0) + close(fds[i]); } } +const char *get_out_filename(int fid) +{ + if (fid >= 0 && fid < _F_LAST) + return filenames[fid]; + + return "output-filename-index-error"; +} + /* Returns the number of bytes written to disk, or a negative number on error */ static long dump_dmesg(int kmsgfd, int outfd, ssize_t size) { diff --git a/runner/executor.h b/runner/executor.h index ab6a0c1767d11b65369611d0fcdd73bc390c152b..3b1cabcf559ce79645d681c22229b2356530aa27 100644 --- a/runner/executor.h +++ b/runner/executor.h @@ -26,7 +26,9 @@ enum { }; bool open_output_files(int dirfd, int *fds, bool write); +bool open_output_files_rdonly(int dirfd, int *fds); void close_outputs(int *fds); +const char *get_out_filename(int fid); /* * Initialize execute_state object to a state where it's ready to diff --git a/runner/resultgen.c b/runner/resultgen.c index 0d3a569cf3262efb195e7247db21e2462ed18040..c96aa67414f8c97b5ffe7a40ad32cb0f8f367a94 100644 --- a/runner/resultgen.c +++ b/runner/resultgen.c @@ -2176,12 +2176,42 @@ static bool parse_test_directory(int dirfd, { int fds[_F_LAST]; struct subtest_list subtests = {}; - bool status = true; int commsparsed; - if (!open_output_files(dirfd, fds, false)) { - fprintf(stderr, "Error opening output files\n"); - return false; + if (!open_output_files_rdonly(dirfd, fds)) { + struct stat statbuf; + size_t fsizes[_F_LAST]; /* checks for both comm and out/err empty */ + int fst_err; + + for (int i = 0; i < _F_LAST; ++i) { + fsizes[i] = 0; + if (fds[i] > 0) { + fst_err = fstat(fds[i], &statbuf); + if (!fst_err) + fsizes[i] = statbuf.st_size; + else + fprintf(stderr, "results: %s: stats failed: %s\n", + get_out_filename(i), strerror(fst_err)); + } else { + fprintf(stderr, "results: %s: open failed: %s\n", + get_out_filename(i), strerror(-fds[i])); + } + } + + /* out/err/dmesg.txt should exist, otherwise there was crash */ + if (fds[_F_OUT] < 0 || fds[_F_ERR] < 0 || fds[_F_DMESG] < 0) { + fprintf(stderr, "results: missing output file(s)\n"); + close_outputs(fds); + + return false; + } + + if (!fsizes[_F_SOCKET] && !fsizes[_F_OUT] && !fsizes[_F_ERR]) { + if (!fsizes[_F_DMESG]) + fprintf(stderr, "results: empty output files\n"); + else + fprintf(stderr, "results: comms/err/out empty, using only dmesg\n"); + } } /* @@ -2191,8 +2221,6 @@ static bool parse_test_directory(int dirfd, commsparsed = fill_from_comms(fds[_F_SOCKET], entry, &subtests, results); if (commsparsed == COMMSPARSE_ERROR) { fprintf(stderr, "Error parsing output files (comms)\n"); - status = false; - goto parse_output_end; } if (commsparsed == COMMSPARSE_EMPTY) { @@ -2200,20 +2228,17 @@ static bool parse_test_directory(int dirfd, * fill_from_journal fills the subtests struct and * adds timeout results where applicable. */ - fill_from_journal(fds[_F_JOURNAL], entry, &subtests, results); + if (fds[_F_JOURNAL] > 0) + fill_from_journal(fds[_F_JOURNAL], entry, &subtests, results); if (!fill_from_output(fds[_F_OUT], entry->binary, "out", &subtests, results->tests) || !fill_from_output(fds[_F_ERR], entry->binary, "err", &subtests, results->tests)) { fprintf(stderr, "Error parsing output files (out.txt, err.txt)\n"); - status = false; - goto parse_output_end; } } if (!fill_from_dmesg(fds[_F_DMESG], settings, entry->binary, &subtests, results->tests)) { fprintf(stderr, "Error parsing output files (dmesg.txt)\n"); - status = false; - goto parse_output_end; } override_results(entry->binary, &subtests, results->tests); @@ -2221,11 +2246,10 @@ static bool parse_test_directory(int dirfd, add_to_totals(entry->binary, &subtests, results); - parse_output_end: close_outputs(fds); free_subtests(&subtests); - return status; + return true; } static void try_add_notrun_results(const struct job_list_entry *entry, @@ -2359,14 +2383,21 @@ struct json_object *generate_results_json(int dirfd) char name[16]; snprintf(name, 16, "%zd", i); + fprintf(stderr, "results: parsing output: %s/ for test: %s\n", + name, job_list.entries[i].binary); if ((testdirfd = openat(dirfd, name, O_DIRECTORY | O_RDONLY)) < 0) { + if (settings.log_level >= LOG_LEVEL_NORMAL) + fprintf(stderr, "results: no output, setting notrun\n"); + try_add_notrun_results(&job_list.entries[i], &settings, &results); continue; } if (!parse_test_directory(testdirfd, &job_list.entries[i], &settings, &results)) { - close(testdirfd); - return NULL; + if (settings.log_level >= LOG_LEVEL_NORMAL) + fprintf(stderr, "results: no useful output, setting notrun\n"); + + try_add_notrun_results(&job_list.entries[i], &settings, &results); } close(testdirfd); }