#include "tui.h"
#include "log.h"
#include "failtest.h"
+#include "ctdb-test.h"
#include "talloc.h"
#include "dlinklist.h"
#include <stdlib.h>
bool should_i_fail(const char *func)
{
pid_t child;
- int status;
+ int status, pfd[2];
struct fail_decision *dec;
+ size_t log_size;
+ char *log;
if (failpath)
return do_failpath(func);
DLIST_ADD_END(decisions, dec, struct fail_decision);
+ if (pipe(pfd) != 0)
+ err(1, "pipe failed for failtest!");
+
fflush(stdout);
child = fork();
if (child == -1)
/* The child actually fails. The script will screw up at this
* point, but should not crash. */
if (child == 0) {
+ /* Log to parent (including stderr if things go really bad). */
+ close(pfd[0]);
+ dup2(pfd[1], STDOUT_FILENO);
+ dup2(pfd[1], STDERR_FILENO);
dec->failed = true;
if (!failtest_no_report || !strstr(func, failtest_no_report))
fails++;
}
dec->failed = false;
+
+ close(pfd[1]);
+ log = grab_fd(pfd[0], &log_size);
+
while (waitpid(child, &status, 0) < 0) {
if (errno != EINTR)
err(1, "failtest waitpid failed for child %i",
/* If child succeeded, or mere script failure, continue. */
if (WIFEXITED(status) && (WEXITSTATUS(status) == EXIT_SUCCESS
- || WEXITSTATUS(status) == EXIT_SCRIPTFAIL))
+ || WEXITSTATUS(status) == EXIT_SCRIPTFAIL)) {
+ talloc_free(log);
return false;
-
- /* Report unless child already reported it. */
- if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SILENT) {
- /* Reproduce child's path */
- dec->failed = true;
- log_line(LOG_ALWAYS, "Child %s %i on failure path: %s",
- WIFEXITED(status) ? "exited" : "signalled",
- WIFEXITED(status) ? WEXITSTATUS(status)
- : WTERMSIG(status), failpath_string());
}
- exit(EXIT_SILENT);
+
+ /* Reproduce child's path */
+ dec->failed = true;
+
+ log_line(LOG_ALWAYS, "Child %s %i on failure path: %s",
+ WIFEXITED(status) ? "exited" : "signalled",
+ WIFEXITED(status) ? WEXITSTATUS(status)
+ : WTERMSIG(status), failpath_string());
+ log_line(LOG_ALWAYS, "Child output:\n%s", log);
+ exit(EXIT_FAILURE);
}
void dump_failinfo(void)
#include "expect.h"
#include <string.h>
#include <talloc.h>
+#include <err.h>
static struct {
enum log_type type;
{ LOG_VERBOSE, "verbose" },
};
-static FILE *logstream;
static int typemask = ~LOG_VERBOSE;
bool log_line(enum log_type type, const char *format, ...)
line = talloc_vasprintf(NULL, format, ap);
va_end(ap);
- if (!type || (type & typemask))
- fprintf(logstream ?: stderr, "%s\n", line);
+ if (!type || (type & typemask)) {
+ printf("%s\n", line);
+ fflush(stdout);
+ }
ret = expect_log_hook(line);
talloc_free(line);
/* write to the end of buffer */
if (vsnprintf(buf + len, bufsize - len - 1, format, ap)
- > bufsize - len - 1)
- log_line(LOG_ALWAYS, "log_line_partial buffer is full!");
+ > bufsize - len - 1) {
+ errx(1, "log_line_partial buffer is full!");
+ }
ptr = buf;
static void log_init(void)
{
- logstream = stdout;
if (tui_quiet)
typemask = 0;
tui_register_command("log", log_admin, log_admin_help);