Log using log_error all errors that are not resulting in an early termination

This commit is contained in:
Andrea Mazzoleni 2026-05-30 17:54:31 +02:00
parent 93d99a566c
commit cf452a091d
6 changed files with 56 additions and 53 deletions

View file

@ -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
============

View file

@ -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 */

View file

@ -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
}

View file

@ -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 */

View file

@ -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;

View file

@ -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);