Avoid duplicate fatal stderr output in GUI mode

This commit is contained in:
Andrea Mazzoleni 2026-09-17 18:20:27 +02:00
parent d0194c3aff
commit ecb12ee92c
6 changed files with 51 additions and 18 deletions

View file

@ -178,16 +178,18 @@ void log_open(const char* file)
void log_close(const char* file)
{
if (stdlog != stdout && stdlog != stderr && stdlog != 0) {
if (fclose(stdlog) != 0) {
FILE* log = stdlog;
/* fclose() invalidates the stream even on error, so fatal reporting must use stderr. */
stdlog = 0;
if (log != stdout && log != stderr && log != 0) {
if (fclose(log) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing the log file '%s'. %s.\n", file, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
stdlog = 0;
}
/****************************************************************************/
@ -1065,6 +1067,8 @@ int snapraid_main(int argc, char* argv[])
}
}
msg_fatal_stderr = !opt.gui;
os_init(OS_INIT_OPT_AVOID_SLEEP | (opt.force_scan_winfind ? OS_INIT_OPT_WINFIND : 0));
app_init();
raid_init();

View file

@ -293,6 +293,7 @@ void log_error_errno(int err, const char* name)
/* print */
int msg_level = 0;
int msg_fatal_stderr = 1;
FILE* stdlog = 0;
int msg_line_prev = 0; /**< Previous line width on stdout */
int msg_line_curr = 0; /**< Current line width on stdout */
@ -374,34 +375,41 @@ static void msg(FILE* out, const char* format, ...)
void vlog_fatal(int err, const char* format, va_list ap, const char* post)
{
int log_failed = 0;
lock_msg();
if (stdlog) {
if (is_hw(err))
fprintf(stdlog, "msg:fatal_hardware: ");
log_failed = fprintf(stdlog, "msg:fatal_hardware: ") < 0;
else
fprintf(stdlog, "msg:fatal: ");
log_failed = fprintf(stdlog, "msg:fatal: ") < 0;
va_list ap_copy;
va_copy(ap_copy, ap);
vfprintf(stdlog, format, ap_copy);
if (vfprintf(stdlog, format, ap_copy) < 0)
log_failed = 1;
va_end(ap_copy);
if (post)
fprintf(stdlog, "%s", post);
if (post && fprintf(stdlog, "%s", post) < 0)
log_failed = 1;
fflush(stdlog);
if (fflush(stdlog) != 0)
log_failed = 1;
}
va_list ap_copy2;
va_copy(ap_copy2, ap);
vmsg(stderr, format, ap_copy2);
va_end(ap_copy2);
/* A failed tagged write must retain stderr as the only usable fatal diagnostic. */
if (!stdlog || log_failed || msg_fatal_stderr) {
va_list ap_copy2;
va_copy(ap_copy2, ap);
vmsg(stderr, format, ap_copy2);
va_end(ap_copy2);
if (post)
msg(stderr, "%s", post);
if (post)
msg(stderr, "%s", post);
fflush(stderr);
fflush(stderr);
}
unlock_msg();
}

View file

@ -92,7 +92,8 @@ typedef void log_ptr(int err, const char* format, ...) __attribute__((format(att
*
* Messages printed before an early termination.
*
* These messages go in the log file and in stderr unconditionally.
* These messages go in the log file and in stderr, except in GUI mode
* when the tagged log message is emitted successfully.
*/
void vlog_fatal(int err, const char* format, va_list ap, const char* post);
void log_fatal(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
@ -176,6 +177,11 @@ typedef void msg_ptr(const char* format, ...) __attribute__((format(attribute_pr
*/
extern int msg_level;
/**
* Emit fatal messages on stderr also when a log is configured.
*/
extern int msg_fatal_stderr;
/**
* State messages.
*

View file

@ -70,6 +70,11 @@ is escaped to \\\\.
Some tags are output only when the \`\-\-gui\` or \`\-\-gui\-verbose\` option
is used. They provide extra verbose state and runtime progress only
useful for a GUI interface.
In GUI mode, the structured log is intended to be consumed by the GUI.
Fatal errors are therefore not duplicated to standard error when they
are successfully written to the log. If the log is unavailable or
writing it fails, the fatal error is printed to standard error as a
fallback.
.PP
Integer values are marked as \`uint\` when they are unsigned and as \`int\`
when they are signed. However, for practical purposes you can treat

View file

@ -50,6 +50,11 @@ Description
Some tags are output only when the `--gui` or `--gui-verbose` option
is used. They provide extra verbose state and runtime progress only
useful for a GUI interface.
In GUI mode, the structured log is intended to be consumed by the GUI.
Fatal errors are therefore not duplicated to standard error when they
are successfully written to the log. If the log is unavailable or
writing it fails, the fatal error is printed to standard error as a
fallback.
Integer values are marked as `uint` when they are unsigned and as `int`
when they are signed. However, for practical purposes you can treat

View file

@ -54,6 +54,11 @@ The following characters are escaped into sequences:
Some tags are output only when the `--gui` or `--gui-verbose` option
is used. They provide extra verbose state and runtime progress only
useful for a GUI interface.
In GUI mode, the structured log is intended to be consumed by the GUI.
Fatal errors are therefore not duplicated to standard error when they
are successfully written to the log. If the log is unavailable or
writing it fails, the fatal error is printed to standard error as a
fallback.
Integer values are marked as `uint` when they are unsigned and as `int`
when they are signed. However, for practical purposes you can treat