diff --git a/cmdline/handle.c b/cmdline/handle.c index 1172e67a..d721f045 100644 --- a/cmdline/handle.c +++ b/cmdline/handle.c @@ -567,7 +567,7 @@ struct snapraid_handle* handle_mapping(struct snapraid_state* state, unsigned* h map = 0; for (k = state->maplist; k != 0; k = k->next) { map = k->data; - if (strcmp(disk->name, map->name) == 0) + if (pathcmp(disk->name, map->name) == 0) break; } if (!map) { diff --git a/cmdline/selftest.c b/cmdline/selftest.c index bbb0764e..8c0a59d4 100644 --- a/cmdline/selftest.c +++ b/cmdline/selftest.c @@ -1930,6 +1930,24 @@ static void test_disk_name(void) assert(disk_name_invalid_reason("r-parity") != 0); assert(disk_name_invalid_reason("z-parity") != 0); +#ifdef _WIN32 + /* case-insensitive parity names rejected on Windows */ + assert(disk_name_invalid_reason("PARITY") != 0); + assert(disk_name_invalid_reason("Parity") != 0); + assert(disk_name_invalid_reason("1-PARITY") != 0); + assert(disk_name_invalid_reason("2-PARITY") != 0); + assert(disk_name_invalid_reason("Q-PARITY") != 0); + assert(disk_name_invalid_reason("Z-PARITY") != 0); +#else + /* case-sensitive on Unix: uppercase variants are distinct from reserved lowercase parity names */ + assert(disk_name_invalid_reason("PARITY") == 0); + assert(disk_name_invalid_reason("Parity") == 0); + assert(disk_name_invalid_reason("1-PARITY") == 0); + assert(disk_name_invalid_reason("2-PARITY") == 0); + assert(disk_name_invalid_reason("Q-PARITY") == 0); + assert(disk_name_invalid_reason("Z-PARITY") == 0); +#endif + /* valid names containing parity as substring */ assert(disk_name_invalid_reason("parity1") == 0); assert(disk_name_invalid_reason("parity_data") == 0); diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 0625692e..1c21f401 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -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; } /****************************************************************************/ diff --git a/cmdline/state.c b/cmdline/state.c index 568a235f..0dadf667 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -117,6 +117,9 @@ static int lev_config_scan(const char* s, unsigned* level, unsigned* mode) const char* disk_name_invalid_reason(const char* name) { unsigned dummy_level; +#ifdef _WIN32 + char lower[DISK_NAME_MAX + 1]; +#endif if (strlen(name) > DISK_NAME_MAX) return "Name is too long (maximum 127 bytes)"; @@ -126,8 +129,16 @@ const char* disk_name_invalid_reason(const char* name) return "Name contains '\\'"; if (strchr(name, ':') != 0) return "Name contains ':'"; + +#ifdef _WIN32 + pathcpy(lower, sizeof(lower), name); + strlwr(lower); + if (lev_config_scan(lower, &dummy_level, 0) == 0) + return "Name is a reserved parity name"; +#else if (lev_config_scan(name, &dummy_level, 0) == 0) return "Name is a reserved parity name"; +#endif return 0; } @@ -1081,7 +1092,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co /* check if the disk name already exists */ for (i = state->disklist; i != 0; i = i->next) { disk = i->data; - if (strcmp(disk->name, buffer) == 0) + if (pathcmp(disk->name, buffer) == 0) break; } if (i) { @@ -1093,7 +1104,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co for (i = state->extralist; i != 0; i = i->next) { struct snapraid_extra* found_extra = i->data; - if (strcmp(found_extra->name, buffer) == 0) + if (pathcmp(found_extra->name, buffer) == 0) break; } if (i) { @@ -1203,7 +1214,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co /* check if the disk name already exists */ for (i = state->extralist; i != 0; i = i->next) { extra = i->data; - if (strcmp(extra->name, buffer) == 0) + if (pathcmp(extra->name, buffer) == 0) break; } if (i) { @@ -1215,7 +1226,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* found_disk = i->data; - if (strcmp(found_disk->name, buffer) == 0) + if (pathcmp(found_disk->name, buffer) == 0) break; } if (i) { @@ -1316,7 +1327,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co struct snapraid_disk* found_disk = 0; for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* disk = i->data; - if (strcmp(disk->name, buffer) == 0) { + if (pathcmp(disk->name, buffer) == 0) { found_disk = disk; break; } @@ -1324,7 +1335,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co struct snapraid_extra* found_extra = 0; for (i = state->extralist; i != 0; i = i->next) { struct snapraid_extra* extra = i->data; - if (strcmp(extra->name, buffer) == 0) { + if (pathcmp(extra->name, buffer) == 0) { found_extra = extra; break; } @@ -1385,7 +1396,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co struct snapraid_disk* found_disk = 0; for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* disk = i->data; - if (strcmp(disk->name, buffer) == 0) { + if (pathcmp(disk->name, buffer) == 0) { found_disk = disk; break; } @@ -1393,7 +1404,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co struct snapraid_extra* found_extra = 0; for (i = state->extralist; i != 0; i = i->next) { struct snapraid_extra* extra = i->data; - if (strcmp(extra->name, buffer) == 0) { + if (pathcmp(extra->name, buffer) == 0) { found_extra = extra; break; } @@ -1705,7 +1716,7 @@ static struct snapraid_disk* find_disk_by_name(struct snapraid_state* state, con for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* disk = i->data; - if (strcmp(disk->name, name) == 0) + if (pathcmp(disk->name, name) == 0) return disk; } @@ -1804,7 +1815,7 @@ static void state_map(struct snapraid_state* state) /* check if the disk is already mapped */ for (j = state->maplist; j != 0; j = j->next) { map = j->data; - if (strcmp(disk->name, map->name) == 0) { + if (pathcmp(disk->name, map->name) == 0) { /* mapping found */ break; } @@ -2096,7 +2107,7 @@ static void state_content_check(struct snapraid_state* state, const char* path) tommy_node* j; for (j = i->next; j != 0; j = j->next) { struct snapraid_map* other = j->data; - if (strcmp(map->name, other->name) == 0) { + if (pathcmp(map->name, other->name) == 0) { /* LCOV_EXCL_START */ log_fatal(ECONTENT, "Conflicting 'map' disk specification in '%s'\n", path); exit(EXIT_FAILURE); diff --git a/cmdline/support.c b/cmdline/support.c index 62188239..bc7fe19d 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -375,27 +375,31 @@ 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; } - /* GUI consumers read tagged fatal messages from the log and must not receive a duplicate raw copy. */ - if (!stdlog || msg_fatal_stderr) { + /* 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); diff --git a/cmdline/support.h b/cmdline/support.h index dbc551a2..98af27cd 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -93,7 +93,7 @@ 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, except in GUI mode - * when a log is configured, where only the tagged log message is emitted. + * 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)));