diff --git a/HISTORY b/HISTORY index 4ed1d418..ed9e1466 100644 --- a/HISTORY +++ b/HISTORY @@ -5,6 +5,9 @@ SnapRAID HISTORY ============ * Fix stack overflow in deep directory trees on platforms with a small stack like Alpine. + * Do not log "fatal" error messages unless execution is stopped early. + This ensures SnapRAID Daemon correctly identifies the alert level of + each message (e.g., treating non-terminating issues as warnings). 14.5 2026/05 ============ diff --git a/cmdline/dry.c b/cmdline/dry.c index 566db530..1ce1c5a2 100644 --- a/cmdline/dry.c +++ b/cmdline/dry.c @@ -97,7 +97,7 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub), task->file_pos, strerror(errno)); if (is_hw(errno)) { /* LCOV_EXCL_START */ - log_error_errno(errno, disk->name); + log_fatal_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; return; /* LCOV_EXCL_STOP */ @@ -129,7 +129,7 @@ static void dry_parity_reader(struct snapraid_worker* worker, struct snapraid_ta log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); if (is_hw(errno)) { /* LCOV_EXCL_START */ - log_error_errno(errno, lev_config_name(level)); + log_fatal_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; return; /* LCOV_EXCL_STOP */ diff --git a/cmdline/scan.c b/cmdline/scan.c index 8b80e1f4..3ff4aac0 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -567,9 +567,9 @@ static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struc * http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx */ log_tag("%s:%u:%s:%s: Uncached time change error.\n", es(ESOFT), 0, disk->name, esc_tag(sub)); - log_fatal(ESOFT, "WARNING! Detected uncached time change from %" PRIu64 ".%09u to %" PRIu64 ".%09u for file '%s'\n", + log_error(ESOFT, "WARNING! Detected uncached time change from %" PRIu64 ".%09u to %" PRIu64 ".%09u for file '%s'\n", (uint64_t)st->st_mtime, (uint32_t)st->st_mtimensec, (uint64_t)synced_st.st_mtime, (uint32_t)synced_st.st_mtimensec, sub); - log_fatal(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); + log_error(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); #endif st->st_mtime = synced_st.st_mtime; st->st_mtimensec = synced_st.st_mtimensec; @@ -578,9 +578,9 @@ static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struc if (st->st_size != synced_st.st_size) { #ifndef _WIN32 log_tag("%s:%u:%s:%s: Uncached size change error.\n", es(ESOFT), 0, disk->name, esc_tag(sub)); - log_fatal(ESOFT, "WARNING! Detected uncached size change from %" PRIu64 " to %" PRIu64 " for file '%s'\n", + log_error(ESOFT, "WARNING! Detected uncached size change from %" PRIu64 " to %" PRIu64 " for file '%s'\n", (uint64_t)st->st_size, (uint64_t)synced_st.st_size, sub); - log_fatal(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); + log_error(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); #endif st->st_size = synced_st.st_size; } @@ -588,9 +588,9 @@ static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struc if (st->st_nlink != synced_st.st_nlink) { #ifndef _WIN32 log_tag("%s:%u:%s:%s: Uncached nlink change error.\n", es(ESOFT), 0, disk->name, esc_tag(sub)); - log_fatal(ESOFT, "WARNING! Detected uncached nlink change from %u to %u for file '%s'\n", + log_error(ESOFT, "WARNING! Detected uncached nlink change from %u to %u for file '%s'\n", (uint32_t)st->st_nlink, (uint32_t)synced_st.st_nlink, sub); - log_fatal(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); + log_error(ESOFT, "It's better if you run SnapRAID without other processes running.\n"); #endif st->st_nlink = synced_st.st_nlink; } @@ -1006,9 +1006,9 @@ static void scan_file(struct snapraid_scan* scan, int is_diff, const char* sub, if (is_original_file_size_different_than_zero && st->st_size == 0) { if (!state->opt.force_zero) { /* LCOV_EXCL_START */ - log_fatal(ESOFT, "The file '%s%s' has unexpected zero size!\n", disk->dir, sub); - log_fatal(ESOFT, "It's possible that after a kernel crash this file was lost,\n"); - log_fatal(ESOFT, "and you can use 'snapraid fix -f /%s' to recover it.\n", fmt_poll(disk, sub)); + log_error(ESOFT, "The file '%s%s' has unexpected zero size!\n", disk->dir, sub); + log_error(ESOFT, "It's possible that after a kernel crash this file was lost,\n"); + log_error(ESOFT, "and you can use 'snapraid fix -f /%s' to recover it.\n", fmt_poll(disk, sub)); if (!is_diff) { log_fatal(ESOFT, "If this an expected condition you can '%s' anyway using 'snapraid --force-zero %s'\n", state->command, state->command); exit(EXIT_FAILURE); @@ -1510,7 +1510,7 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa /* LCOV_EXCL_STOP */ } if (ret == 0) - log_fatal(ESOFT, "WARNING! Empty symbolic link '%s'.\n", path_next); + log_error(ESOFT, "WARNING! Empty symbolic link '%s'.\n", path_next); /* readlink doesn't put the final 0 */ tmp[ret] = 0; @@ -1535,7 +1535,7 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa */ if ((uint64_t)st->st_dev != disk->device) { log_tag("%s:%u:%s:%s: Ignoring mount point.\n", es(ESOFT), 0, disk->name, esc_tag(path_next)); - log_fatal(ESOFT, "WARNING! Ignoring mount point '%s' because it appears to be in a different device\n", path_next); + log_error(ESOFT, "WARNING! Ignoring mount point '%s' because it appears to be in a different device\n", path_next); } else #endif { @@ -1562,7 +1562,7 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa st = DSTAT(path_next, dd, &st_buf); log_tag("%s:%u:%s:%s: Ignoring special file.\n", es(ESOFT), 0, disk->name, esc_tag(path_next)); - log_fatal(ESOFT, "WARNING! Ignoring special '%s' file '%s'\n", stat_desc(st), path_next); + log_error(ESOFT, "WARNING! Ignoring special '%s' file '%s'\n", stat_desc(st), path_next); } else { msg_verbose("Excluding special file '%s' for rule '%s'\n", path_next, filter_type(reason, tmp, PATH_MAX)); } @@ -1815,7 +1815,7 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) /* if verbose, print the list of duplicates real offsets */ /* other cases are for offsets not supported, so we don't need to report them file by file */ if (phy_last >= FILEPHY_REAL_OFFSET) { - log_fatal(ESOFT, "WARNING! Files '%s%s' and '%s%s' share the same physical offset %" PRId64 ".\n", disk->dir, phy_file_last->sub, disk->dir, file->sub, phy_last); + log_error(ESOFT, "WARNING! Files '%s%s' and '%s%s' share the same physical offset %" PRId64 ".\n", disk->dir, phy_file_last->sub, disk->dir, file->sub, phy_last); } ++phy_dup; } @@ -1885,9 +1885,9 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) ) { if (!done) { done = 1; - log_fatal(ESOFT, "WARNING! All the files previously present in disk '%s' at dir '%s'", disk->name, disk->dir); + log_error(ESOFT, "WARNING! All the files previously present in disk '%s' at dir '%s'", disk->name, disk->dir); } else { - log_fatal(ESOFT, ", disk '%s' at dir '%s'", disk->name, disk->dir); + log_error(ESOFT, ", disk '%s' at dir '%s'", disk->name, disk->dir); } /* detect the special condition of all files missing */ @@ -1902,12 +1902,12 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) if (done) { log_fatal(ESOFT, "\nare now missing or have been rewritten!\n"); if (all_rewritten) { - log_fatal(ESOFT, "This could occur when restoring a disk from a backup\n"); - log_fatal(ESOFT, "program that is not setting correctly the timestamps.\n"); + log_error(ESOFT, "This could occur when restoring a disk from a backup\n"); + log_error(ESOFT, "program that is not setting correctly the timestamps.\n"); } if (all_missing) { - log_fatal(ESOFT, "This could occur when some disks are not mounted\n"); - log_fatal(ESOFT, "in the expected directory.\n"); + log_error(ESOFT, "This could occur when some disks are not mounted\n"); + log_error(ESOFT, "in the expected directory.\n"); } if (!is_diff) { log_fatal(ESOFT, "If you want to '%s' anyway, use 'snapraid --force-empty %s'.\n", state->command, state->command); @@ -1925,14 +1925,14 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) if (disk->has_unreliable_physical) { if (!done) { done = 1; - log_fatal(ESOFT, "WARNING! Physical offsets not supported for disk '%s'", disk->name); + log_error(ESOFT, "WARNING! Physical offsets not supported for disk '%s'", disk->name); } else { - log_fatal(ESOFT, ", '%s'", disk->name); + log_error(ESOFT, ", '%s'", disk->name); } } } if (done) { - log_fatal(ESOFT, ". The order of files won't be optimal.\n"); + log_error(ESOFT, ". The order of files won't be optimal.\n"); } } @@ -1944,14 +1944,14 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) if (disk->has_volatile_inodes) { if (!done) { done = 1; - log_fatal(ESOFT, "WARNING! Inodes are not persistent for disks: '%s'", disk->name); + log_error(ESOFT, "WARNING! Inodes are not persistent for disks: '%s'", disk->name); } else { - log_fatal(ESOFT, ", '%s'", disk->name); + log_error(ESOFT, ", '%s'", disk->name); } } } if (done) { - log_fatal(ESOFT, ". Inodes are not used to detect move operations.\n"); + log_error(ESOFT, ". Inodes are not used to detect move operations.\n"); } /* check for disks with changed UUID */ @@ -1966,14 +1966,14 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) if (disk->has_different_uuid && !disk->had_empty_uuid) { if (!done) { done = 1; - log_fatal(ESOFT, "WARNING! UUID is changed for disks: '%s'", disk->name); + log_error(ESOFT, "WARNING! UUID is changed for disks: '%s'", disk->name); } else { - log_fatal(ESOFT, ", '%s'", disk->name); + log_error(ESOFT, ", '%s'", disk->name); } } } if (done) { - log_fatal(ESOFT, ". Inodes are not used to detect move operations.\n"); + log_error(ESOFT, ". Inodes are not used to detect move operations.\n"); } /* check for disks with unsupported UUID */ @@ -1984,17 +1984,17 @@ static int state_diffscan(struct snapraid_state* state, int is_diff) if (disk->has_unsupported_uuid) { if (!done) { done = 1; - log_fatal(ESOFT, "WARNING! UUID is unsupported for disks: '%s'", disk->name); + log_error(ESOFT, "WARNING! UUID is unsupported for disks: '%s'", disk->name); } else { - log_fatal(ESOFT, ", '%s'", disk->name); + log_error(ESOFT, ", '%s'", disk->name); } } } if (done) { - log_fatal(ESOFT, ". Not using inodes to detect move operations.\n"); + log_error(ESOFT, ". Not using inodes to detect move operations.\n"); #if defined(_linux) && !HAVE_BLKID - log_fatal(ESOFT, "The 'blkid' library is not linked in SnapRAID!\n"); - log_fatal(ESOFT, "Try rebuilding it after installing the libblkid-dev or libblkid-devel package.\n"); + log_error(ESOFT, "The 'blkid' library is not linked in SnapRAID!\n"); + log_error(ESOFT, "Try rebuilding it after installing the libblkid-dev or libblkid-devel package.\n"); #endif } diff --git a/cmdline/scrub.c b/cmdline/scrub.c index 04ae6e4c..9a65d4ce 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -184,7 +184,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub), task->file_pos, strerror(errno)); if (is_hw(errno)) { /* LCOV_EXCL_START */ - log_error_errno(errno, disk->name); + log_fatal_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; return; /* LCOV_EXCL_STOP */ @@ -216,7 +216,7 @@ static void scrub_parity_reader(struct snapraid_worker* worker, struct snapraid_ log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); if (is_hw(errno)) { /* LCOV_EXCL_START */ - log_error_errno(errno, lev_config_name(level)); + log_fatal_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; return; /* LCOV_EXCL_STOP */ diff --git a/cmdline/state.c b/cmdline/state.c index 3c4a4ced..0699878a 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -445,7 +445,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t for (j = i->next; j != 0; j = j->next) { struct snapraid_content* other = j->data; if (content->device == other->device) { - log_fatal(ESOFT, "WARNING! Content files on the same disk: '%s' and '%s'.\n", content->content, other->content); + log_error(ESOFT, "WARNING! Content files on the same disk: '%s' and '%s'.\n", content->content, other->content); break; } } @@ -471,11 +471,11 @@ static void state_config_check(struct snapraid_state* state, const char* path, t #endif if (state->raid_mode == RAID_MODE_CAUCHY && !state->opt.no_warnings) { if (state->level == 3) { - log_fatal(ESOFT, "WARNING! Your CPU doesn't have a fast implementation for triple parity.\n"); - log_fatal(ESOFT, "WARNING! It's recommended to switch to 'z-parity' instead than '3-parity'.\n"); + log_error(ESOFT, "WARNING! Your CPU doesn't have a fast implementation for triple parity.\n"); + log_error(ESOFT, "WARNING! It's recommended to switch to 'z-parity' instead than '3-parity'.\n"); } else if (state->level > 3) { - log_fatal(ESOFT, "WARNING! Your CPU doesn't have a fast implementation beyond triple parity.\n"); - log_fatal(ESOFT, "WARNING! It's recommended to reduce the parity levels to triple parity.\n"); + log_error(ESOFT, "WARNING! Your CPU doesn't have a fast implementation beyond triple parity.\n"); + log_error(ESOFT, "WARNING! It's recommended to reduce the parity levels to triple parity.\n"); } } @@ -1682,7 +1682,7 @@ static void state_map(struct snapraid_state* state) if (map->uuid[0] != 0) { /* count the number of uuid change */ ++uuid_mismatch; - log_fatal(ESOFT, "UUID change for disk '%s' from '%s' to '%s'\n", disk->name, map->uuid, disk->uuid); + log_error(ESOFT, "UUID change for disk '%s' from '%s' to '%s'\n", disk->name, map->uuid, disk->uuid); } else { /* no message here, because having a disk without */ /* UUID is the normal state of an empty disk */ @@ -1718,7 +1718,7 @@ static void state_map(struct snapraid_state* state) if (state->parity[l].split_map[s].uuid[0] != 0) { /* count the number of uuid change */ ++uuid_mismatch; - log_fatal(ESOFT, "UUID change for parity '%s/%u' from '%s' to '%s'\n", lev_config_name(l), s, state->parity[l].split_map[s].uuid, uuid); + log_error(ESOFT, "UUID change for parity '%s/%u' from '%s' to '%s'\n", lev_config_name(l), s, state->parity[l].split_map[s].uuid, uuid); } /* update the uuid */ @@ -2948,7 +2948,7 @@ static void state_read_content(struct snapraid_state* state, const char* path, S /* search by UUID if renamed */ disk = find_disk_by_uuid(state, uuid); if (disk) { - log_fatal(EUSER, "WARNING! Renaming disk '%s' to '%s'\n", buffer, disk->name); + log_error(EUSER, "WARNING! Renaming disk '%s' to '%s'\n", buffer, disk->name); /* write the new state with the new name */ state->need_write = 1; @@ -3169,7 +3169,7 @@ static void state_read_content(struct snapraid_state* state, const char* path, S } /* otherwise we can drop it */ - log_fatal(EUSER, "WARNING! Dropping from '%s' unused split '%u'\n", lev_config_name(v_level), s); + log_error(EUSER, "WARNING! Dropping from '%s' unused split '%u'\n", lev_config_name(v_level), s); } else { char parity_name[64]; @@ -4271,7 +4271,7 @@ void state_read(struct snapraid_state* state) /* otherwise continue */ if (node->next) { - log_fatal(errno, "WARNING! Content file '%s' not found, attempting with another copy...\n", path); + log_error(errno, "WARNING! Content file '%s' not found, attempting with another copy...\n", path); /* ensure to rewrite all the content files */ state->need_write = 1; @@ -4284,7 +4284,7 @@ void state_read(struct snapraid_state* state) /* if not found, assume empty */ if (!f) { - log_fatal(EUSER, "No content file found. Assuming empty.\n"); + log_error(EUSER, "No content file found. Assuming empty.\n"); /* create the initial mapping */ state_map(state); @@ -4328,8 +4328,8 @@ void state_read(struct snapraid_state* state) } else { /* if the size is different */ if (other_st.st_size != st.st_size) { - log_fatal(ECONTENT, "WARNING! Content files '%s' and '%s' have a different size!\n", path, other_path); - log_fatal(ECONTENT, "Likely one of the two is broken!\n"); + log_error(ECONTENT, "WARNING! Content files '%s' and '%s' have a different size!\n", path, other_path); + log_error(ECONTENT, "Likely one of the two is broken!\n"); /* ensure to rewrite all the content files */ state->need_write = 1; diff --git a/cmdline/sync.c b/cmdline/sync.c index 1b47d071..a2d4610e 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -569,7 +569,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub), task->file_pos, strerror(errno)); if (is_hw(errno)) { - log_error_errno(errno, disk->name); + log_fatal_errno(errno, disk->name); /* continue until the error limit is reached */ task->state = TASK_STATE_IOERROR_CONTINUE; } else { @@ -604,7 +604,7 @@ static void sync_parity_writer(struct snapraid_worker* worker, struct snapraid_t log_tag("parity_%s:%u:%s: Write error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); if (is_hw(errno)) { - log_error_errno(errno, lev_config_name(level)); + log_fatal_errno(errno, lev_config_name(level)); /* continue until the error limit is reached */ task->state = TASK_STATE_IOERROR_CONTINUE; } else { @@ -1039,7 +1039,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* LCOV_EXCL_START */ log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(l), strerror(errno)); if (is_hw(errno)) { - log_error_errno(errno, lev_config_name(l)); + log_fatal_errno(errno, lev_config_name(l)); if (io_error >= state->opt.io_error_limit) { log_fatal(errno, "DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_config_name(l)); log_fatal(errno, "Stopping at block %u\n", blockcur);