diff --git a/cmdline/check.c b/cmdline/check.c index ed647d95..6bde6266 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -31,6 +31,27 @@ /****************************************************************************/ /* check */ +static const char* es(int err) +{ + if (err == EIO) + return "error_io"; + else + return "error"; +} + +static void log_fatal_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); + } else if (err == EACCES) { + log_fatal("WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); + } else if (err == ENOSPC) { + log_fatal("WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); + } else { + log_fatal("WARNING! Without a working %s disk, it isn't possible to continue.\n", name); + } +} + /** * A block that failed the hash check, or that was deleted. */ @@ -660,8 +681,8 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s ret = handle_close(&handle[j]); if (ret != 0) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); return -1; /* LCOV_EXCL_STOP */ } @@ -670,8 +691,9 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s ret = rename(path, path_to); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("Error renaming '%s' to '%s'. %s.\n", path, path_to, strerror(errno)); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error renaming '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno)); + log_tag("%s:%u:%s:%s: Rename error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); return -1; /* LCOV_EXCL_STOP */ } @@ -692,23 +714,24 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s /* if the file is closed or different than the one expected, reopen it */ /* a different open file could happen when filtering for bad blocks */ if (handle[j].file != file) { - /* close a potential different file */ + /* keep a pointer at the file we are going to close for error reporting */ + struct snapraid_file* report = handle[j].file; ret = handle_close(&handle[j]); if (ret != 0) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(handle[j].file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); return -1; /* LCOV_EXCL_STOP */ } /* reopen it as readonly, as to set the mtime readonly access it's enough */ /* we know that the file exists because it has the FILE_IS_FIXED tag */ - ret = handle_open(&handle[j], file, state->file_mode, log_error, 0); + ret = handle_open(&handle[j], file, state->file_mode, log_error, log_error); /* output a message for missing files */ if (ret != 0) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Open error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); return -1; /* LCOV_EXCL_STOP */ } @@ -740,9 +763,11 @@ static int file_post(struct snapraid_state* state, int fix, unsigned i, struct s ret = handle_utime(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + /* mark the file as damaged */ file_flag_set(file, FILE_IS_DAMAGED); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); return -1; /* LCOV_EXCL_STOP */ } @@ -782,8 +807,8 @@ close_and_continue: ret = handle_close(&handle[j]); if (ret != 0) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); return -1; /* LCOV_EXCL_STOP */ } @@ -1049,13 +1074,15 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna /* if the file is closed or different than the current one */ if (handle[j].file == 0 || handle[j].file != file) { - /* close the old one, if any */ + /* keep a pointer at the file we are going to close for error reporting */ + struct snapraid_file* report = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(handle[j].file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", i); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1067,12 +1094,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = handle_create(&handle[j], file, state->file_mode); if (ret == -1) { /* LCOV_EXCL_START */ - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the file.\n"); - } else { - log_fatal("DANGER! Without a working data disk, it isn't possible to fix errors on it.\n"); - } + log_tag("%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", i); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1086,10 +1111,12 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } } else { /* open the file only for reading */ - if (!file_flag_has(file, FILE_IS_MISSING)) + if (!file_flag_has(file, FILE_IS_MISSING)) { ret = handle_open(&handle[j], file, state->file_mode, log_error, state->opt.expected_missing ? log_expected : 0); - else + } else { + errno = ENOENT; ret = -1; /* if the file is missing, we cannot open it */ + } if (ret == -1) { /* save the failed block for the check/fix */ failed[failed_count].is_bad = 1; @@ -1102,7 +1129,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna failed[failed_count].handle = &handle[j]; ++failed_count; - log_tag("error:%u:%s:%s: Open error at position %u\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos); + log_tag("%s:%u:%s:%s: Open error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); ++error; /* mark the file as missing, to avoid to retry to open it again */ @@ -1142,8 +1169,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = handle_truncate(&handle[j], file); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected truncate error in a data disk, it isn't possible to fix.\n"); + log_tag("%s:%u:%s:%s: Truncate error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", i); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1174,7 +1203,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna failed[failed_count].handle = &handle[j]; ++failed_count; - log_tag("error:%u:%s:%s: Read error at position %u\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos); + log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); ++error; continue; } @@ -1264,9 +1293,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (parity[l]) { ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, log_error); if (ret == -1) { + log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno)); + buffer_recov[l] = 0; /* no parity to use */ - log_tag("parity_error:%u:%s: Read error\n", i, lev_config_name(l)); ++error; } } else { @@ -1351,16 +1381,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = handle_write(failed[j].handle, failed[j].file_pos, buffer[failed[j].index], state->block_size); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Write error. %s.\n", es(errno), i, failed[j].disk->name, esc_tag(failed[j].file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, failed[j].disk->name); + log_fatal("Stopping at block %u\n", i); + /* mark the file as damaged */ file_flag_set(failed[j].file, FILE_IS_DAMAGED); - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the file.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } - log_fatal("Stopping at block %u\n", i); ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1404,9 +1431,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = parity_write(parity[l], i, buffer[diskmax + l], state->block_size); if (ret == -1) { /* LCOV_EXCL_START */ - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working %s disk, it isn't possible to fix errors on it.\n", lev_name(l)); + log_tag("%s:%u:%s: Write error. %s.\n", es(errno), i, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); log_fatal("Stopping at block %u\n", i); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1442,6 +1470,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (ret == -1) { /* LCOV_EXCL_START */ log_fatal("Stopping at block %u\n", i); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1510,16 +1539,18 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna unsuccessful = 1; log_error("Error stating empty file '%s'. %s.\n", path, strerror(errno)); - log_tag("empty_error:%s:%s: Empty file stat error\n", disk->name, esc_tag(file->sub, esc_buffer)); + log_tag("empty_%s:%s:%s: Empty file stat error\n", es(errno), disk->name, esc_tag(file->sub, esc_buffer)); ++error; } else if (!S_ISREG(st.st_mode)) { unsuccessful = 1; + log_error("Error stating empty file '%s' for not regular file.\n", path); log_tag("empty_error:%s:%s: Empty file error for not regular file\n", disk->name, esc_tag(file->sub, esc_buffer)); ++error; } else if (st.st_size != 0) { unsuccessful = 1; + log_error("Error stating empty file '%s' for not empty file.\n", path); log_tag("empty_error:%s:%s: Empty file error for size '%" PRIu64 "'\n", disk->name, esc_tag(file->sub, esc_buffer), (uint64_t)st.st_size); ++error; } @@ -1531,8 +1562,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = mkancestor(path); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error creating ancestor '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno)); + log_tag("empty_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1543,14 +1577,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600); if (f == -1) { /* LCOV_EXCL_START */ - log_fatal("Error creating empty file '%s'. %s.\n", path, strerror(errno)); - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the file.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } + log_fatal("Error creating '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno)); + log_tag("empty_%s:%u:%s:%s: Create error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1560,11 +1591,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = fmtime(f, file->mtime_sec, file->mtime_nsec); if (ret != 0) { /* LCOV_EXCL_START */ + log_fatal("Error timing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno)); + log_tag("empty_%s:%u:%s:%s: Time error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + log_fatal("Stopping\n"); + close(f); - log_fatal("Error timing file '%s'. %s.\n", file->sub, strerror(errno)); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - log_fatal("Stopping\n"); ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1574,8 +1607,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = close(f); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error closing '%s%s'. %s.\n", disk->dir, file->sub, strerror(errno)); + log_tag("empty_%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1618,11 +1654,12 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna unsuccessful = 1; log_error("Error stating hardlink '%s'. %s.\n", path, strerror(errno)); - log_tag("hardlink_error:%s:%s:%s: Hardlink stat error\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); + log_tag("hardlink_%s:%s:%s:%s: Hardlink stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno)); ++error; } else if (!S_ISREG(st.st_mode)) { unsuccessful = 1; + log_error("Error stating hardlink '%s' for not regular file.\n", path); log_tag("hardlink_error:%s:%s:%s: Hardlink error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; } @@ -1648,11 +1685,12 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } log_error("Error stating hardlink-to '%s'. %s.\n", pathto, strerror(errno)); - log_tag("hardlink_error:%s:%s:%s: Hardlink to stat error\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); + log_tag("hardlink_%s:%s:%s:%s: Hardlink to stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno)); ++error; } else if (!S_ISREG(stto.st_mode)) { unsuccessful = 1; + log_error("Error stating hardlink-to '%s' for not regular file.\n", path); log_tag("hardlink_error:%s:%s:%s: Hardlink-to error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; } else if (!unsuccessful && st.st_ino != stto.st_ino) { @@ -1670,13 +1708,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna unsuccessful = 1; log_error("Error reading symlink '%s'. %s.\n", path, strerror(errno)); - log_tag("symlink_error:%s:%s: Symlink read error\n", disk->name, esc_tag(slink->sub, esc_buffer)); + log_tag("symlink_%s:%s:%s: Symlink read error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); ++error; } else if (ret >= PATH_MAX) { unsuccessful = 1; log_error("Error reading symlink '%s'. Symlink too long.\n", path); - log_tag("symlink_error:%s:%s: Symlink read error\n", disk->name, esc_tag(slink->sub, esc_buffer)); + log_tag("symlink_error:%s:%s: Symlink too long\n", disk->name, esc_tag(slink->sub, esc_buffer)); ++error; } else { linkto[ret] = 0; @@ -1691,12 +1729,17 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } if (fix && unsuccessful && !unrecoverable) { + const char* link = link_flag_has(slink, FILE_IS_HARDLINK) ? "hard" : "sym"; + /* create the ancestor directories */ ret = mkancestor(path); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error creating ancestor '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno)); + log_tag("%slink_%s:%u:%s:%s: Create ancestor error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1706,9 +1749,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = remove(path); if (ret != 0 && errno != ENOENT) { /* LCOV_EXCL_START */ - log_fatal("Error removing '%s'. %s.\n", path, strerror(errno)); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error removing '%s%s'. %s.\n", disk->dir, slink->sub, strerror(errno)); + log_tag("%slink_%s:%u:%s:%s: Remove error. %s.\n", link, es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1720,13 +1765,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (ret != 0) { /* LCOV_EXCL_START */ log_fatal("Error writing hardlink '%s' to '%s'. %s.\n", path, pathto, strerror(errno)); - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the hardlink.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } + log_tag("hardlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1739,13 +1781,10 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (ret != 0) { /* LCOV_EXCL_START */ log_fatal("Error writing symlink '%s' to '%s'. %s.\n", path, slink->linkto, strerror(errno)); - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the symlink.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } + log_tag("symlink_%s:%u:%s:%s: Hardlink error. %s.\n", es(errno), i, disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1784,7 +1823,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna unsuccessful = 1; log_error("Error stating dir '%s'. %s.\n", path, strerror(errno)); - log_tag("dir_error:%s:%s: Dir stat error\n", disk->name, esc_tag(dir->sub, esc_buffer)); + log_tag("dir_%s:%s:%s: Dir stat error. %s.\n", es(errno), disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno)); ++error; } else if (!S_ISDIR(st.st_mode)) { unsuccessful = 1; @@ -1798,8 +1837,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = mkancestor(path); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_fatal("Error creating ancestor '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno)); + log_tag("dir_%s:%u:%s:%s: Create ancestor error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1809,14 +1851,11 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("Error creating dir '%s'. %s.\n", path, strerror(errno)); - if (errno == EACCES) { - log_fatal("WARNING! Please give write permission to the dir.\n"); - } else { - /* we do not use DANGER because it could be ENOSPC which is not always correctly reported */ - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); - } + log_fatal("Error creating directory '%s%s'. %s.\n", disk->dir, dir->sub, strerror(errno)); + log_tag("dir_%s:%u:%s:%s: Create directory error. %s.\n", es(errno), i, disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping\n"); + ++unrecoverable_error; goto bail; /* LCOV_EXCL_STOP */ @@ -1842,8 +1881,9 @@ bail: ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + ++unrecoverable_error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ @@ -1892,7 +1932,9 @@ bail: if (ret != 0) { /* LCOV_EXCL_START */ log_fatal("Error removing '%s'. %s.\n", path, strerror(errno)); - log_fatal("WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + ++unrecoverable_error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ @@ -2028,6 +2070,12 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b /* open for reading, and ignore error */ ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { + log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + if (errno == EIO) { + log_fatal_errno(errno, lev_config_name(l)); + exit(EXIT_FAILURE); + } + /* continue anyway */ parity_ptr[l] = 0; } @@ -2036,7 +2084,8 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to fix any error.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -2044,7 +2093,8 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b ret = parity_chsize(parity_ptr[l], &state->parity[l], 0, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to sync.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -2057,7 +2107,14 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b parity_ptr[l] = &parity[l]; ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { + log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + if (errno == EIO) { + log_fatal_errno(errno, lev_config_name(l)); + exit(EXIT_FAILURE); + } + msg_status("No accessible %s file, only files will be checked.\n", lev_name(l)); + /* continue anyway */ parity_ptr[l] = 0; } @@ -2089,7 +2146,9 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b ret = parity_truncate(parity_ptr[l]); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected truncate error in %s disk.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Truncate error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); + ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ @@ -2099,7 +2158,9 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b ret = parity_close(parity_ptr[l]); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); + ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ diff --git a/cmdline/dry.c b/cmdline/dry.c index d3ddfb09..c22dca91 100644 --- a/cmdline/dry.c +++ b/cmdline/dry.c @@ -28,6 +28,34 @@ /****************************************************************************/ /* dry */ +static const char* es(int err) +{ + if (err == EIO) + return "error_io"; + else + return "error"; +} + +static void log_fatal_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); + } else if (err == EACCES) { + log_fatal("WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); + } else if (err == ENOSPC) { + log_fatal("WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); + } else { + log_fatal("WARNING! Without a working %s disk, it isn't possible to continue.\n", name); + } +} + +static void log_error_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s.\n", name); + } +} + static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task* task) { struct snapraid_io* io = worker->io; @@ -70,57 +98,49 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ - if (errno == EIO) { - log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to dry.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); - log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_IOERROR; - return; - } - - log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to dry.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_ERROR; + + if (errno == EIO) { + task->state = TASK_STATE_IOERROR; + } else { + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } } - ret = handle_open(handle, task->file, state->file_mode, log_error, 0); + ret = handle_open(handle, task->file, state->file_mode, log_error, 0); /* for missing file don't output a message */ if (ret == -1) { - /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); if (errno == EIO) { - log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to dry.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); + /* LCOV_EXCL_START */ + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; + /* LCOV_EXCL_STOP */ } - log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; - /* LCOV_EXCL_STOP */ } task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { - /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); if (errno == EIO) { - log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos); + /* LCOV_EXCL_START */ + log_error_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; return; + /* LCOV_EXCL_STOP */ } - log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; - /* LCOV_EXCL_STOP */ } /* store the path of the opened file */ @@ -142,18 +162,17 @@ static void dry_parity_reader(struct snapraid_worker* worker, struct snapraid_ta /* read the parity */ ret = parity_read(parity_handle, blockcur, buffer, state->block_size, log_error); if (ret == -1) { - /* LCOV_EXCL_START */ + log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); if (errno == EIO) { - log_tag("parity_error:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno)); - log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur); + /* LCOV_EXCL_START */ + log_error_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; return; + /* LCOV_EXCL_STOP */ } - log_tag("parity_error:%u:%s: Read error. %s\n", blockcur, lev_config_name(level), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; - /* LCOV_EXCL_STOP */ } task->state = TASK_STATE_DONE; @@ -203,6 +222,7 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit /* start all the worker threads */ io_start(&io, blockstart, blockmax, 0); + blockcur = blockstart; if (!state_progress_begin(state, blockstart, blockmax, countmax)) goto end; @@ -270,8 +290,7 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Too many input/output read errors in a data disk, it isn't possible to scrub.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, task->path); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", disk->dir); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -324,8 +343,7 @@ static int state_dry_process(struct snapraid_state* state, struct snapraid_parit ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Too many input/output read errors in the %s disk, it isn't possible to scrub.\n", lev_name(levcur)); - log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(levcur)); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_name(levcur)); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -381,9 +399,14 @@ bail: ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Close error. %s\n", blockmax, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected close error in a data disk.\n"); - ++error; + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + + if (errno == EIO) { + ++io_error; + } else { + ++error; + } /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } @@ -402,6 +425,14 @@ bail: if (io_error) log_fatal("DANGER! Unexpected input/output errors!\n"); + log_tag("summary:error_file:%u\n", error); + log_tag("summary:error_io:%u\n", io_error); + if (error + io_error == 0) + log_tag("summary:exit:ok\n"); + else + log_tag("summary:exit:error\n"); + log_flush(); + free(handle); free(waiting_map); io_done(&io); @@ -441,7 +472,8 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to dry.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -465,6 +497,9 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t ret = parity_close(&parity_handle[l]); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); + ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ diff --git a/cmdline/handle.c b/cmdline/handle.c index 780a888a..ab7854ad 100644 --- a/cmdline/handle.c +++ b/cmdline/handle.c @@ -175,6 +175,8 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int if (errno == ENOENT) out_missing("Missing file '%s'.\n", handle->path); + else if (errno == EACCES) + out("Permission denied for file '%s'.\n", handle->path); else out("Error opening file '%s'. %s.\n", handle->path, strerror(errno)); return -1; @@ -250,16 +252,20 @@ int handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned c /* check if we are going to read only not initialized data */ if (offset >= handle->valid_size) { /* if the file is missing, it's at 0 size, or it's rebuilt while reading */ - if (offset == handle->valid_size || handle->valid_size == 0) - out_missing("Reading data from missing file '%s' at offset %" PRIu64 ".\n", handle->path, offset); - else - out("Reading missing data from file '%s' at offset %" PRIu64 ".\n", handle->path, offset); + if (offset == handle->valid_size || handle->valid_size == 0) { + out_missing("Reading missing file '%s' at offset %" PRIu64 ".\n", handle->path, offset); + errno = ENOENT; + } else { + out("Reading over the end from file '%s' at offset %" PRIu64 ".\n", handle->path, offset); + errno = ENXIO; + } return -1; } read_size = file_block_size(handle->file, file_pos, block_size); count = 0; + errno = 0; do { bw_limit(handle->bw, block_size - count); @@ -273,6 +279,8 @@ int handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned c } if (read_ret == 0) { out("Unexpected end of file '%s' at offset %" PRIu64 ". %s.\n", handle->path, offset, strerror(errno)); + if (errno == 0) + errno = ENXIO; return -1; } @@ -310,6 +318,8 @@ int handle_write(struct snapraid_handle* handle, block_off_t file_pos, unsigned if (write_ret != (ssize_t)write_size) { /* conversion is safe because block_size is always small */ /* LCOV_EXCL_START */ log_fatal("Error writing file '%s'. %s.\n", handle->path, strerror(errno)); + if (errno == 0) + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } diff --git a/cmdline/parity.c b/cmdline/parity.c index 22b9a4ae..90433b01 100644 --- a/cmdline/parity.c +++ b/cmdline/parity.c @@ -266,8 +266,10 @@ static int parity_handle_grow(struct snapraid_split_handle* split, data_off_t pr (void)previous_size; /* simulate a failure for testing limits */ - if (split->limit_size != 0 && size > (data_off_t)split->limit_size) + if (split->limit_size != 0 && size > (data_off_t)split->limit_size) { + errno = ENXIO; return -1; + } #if HAVE_FALLOCATE if (!skip_fallocate) { @@ -565,6 +567,7 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* if (size < 0) { /* LCOV_EXCL_START */ + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } @@ -589,6 +592,7 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* if ((run & block_mask) != 0) { /* LCOV_EXCL_START */ log_fatal("Internal inconsistency in split '%s' size with extra '%" PRIu64 "' bytes.\n", split->path, run & block_mask); + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } @@ -608,11 +612,13 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* if (split->st.st_size > run) { /* LCOV_EXCL_START */ log_fatal("Unexpected over resizing parity file '%s' to size %" PRIu64 " resulting in size %" PRIu64 ".\n", split->path, run, (uint64_t)split->st.st_size); + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } else if (is_fixed && split->st.st_size < run) { /* LCOV_EXCL_START */ log_fatal("Failed restoring parity file '%s' to size %" PRIu64 " resulting in size %" PRIu64 ".\n", split->path, run, (uint64_t)split->st.st_size); + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } else { @@ -638,6 +644,7 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* if (size != 0) { /* LCOV_EXCL_START */ log_fatal("Failed to allocate all the required parity space. You miss %" PRIu64 " bytes.\n", size); + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } @@ -872,8 +879,10 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne if (errno == ENOSPC) { log_fatal("Failed to grow parity file '%s' using write due lack of space.\n", split->path); } else { - log_fatal("Error writing file '%s'. %s.\n", split->path, strerror(errno)); + log_fatal("Error writing parity file '%s'. %s.\n", split->path, strerror(errno)); } + if (errno == 0) + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } @@ -910,25 +919,28 @@ int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned /* if read is completely out of the valid range */ if (offset >= split->valid_size) { /* LCOV_EXCL_START */ - out("Missing data reading file '%s' at offset %" PRIu64 " for size %u.\n", split->path, offset, block_size); + out("Reading over the end from parity file '%s' at offset %" PRIu64 " for size %u.\n", split->path, offset, block_size); return -1; /* LCOV_EXCL_STOP */ } count = 0; + errno = 0; do { bw_limit(handle->bw, block_size - count); read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count); if (read_ret < 0) { /* LCOV_EXCL_START */ - out("Error reading file '%s' at offset %" PRIu64 " for size %u. %s.\n", split->path, offset + count, block_size - count, strerror(errno)); + out("Error reading parity file '%s' at offset %" PRIu64 " for size %u. %s.\n", split->path, offset + count, block_size - count, strerror(errno)); return -1; /* LCOV_EXCL_STOP */ } if (read_ret == 0) { /* LCOV_EXCL_START */ - out("Unexpected end of file '%s' at offset %" PRIu64 ". %s.\n", split->path, offset, strerror(errno)); + out("Unexpected end of parity file '%s' at offset %" PRIu64 ". %s.\n", split->path, offset, strerror(errno)); + if (errno == 0) + errno = ENXIO; return -1; /* LCOV_EXCL_STOP */ } diff --git a/cmdline/scrub.c b/cmdline/scrub.c index e0a7168d..9f7e0f18 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -28,6 +28,34 @@ /****************************************************************************/ /* scrub */ +static const char* es(int err) +{ + if (err == EIO) + return "error_io"; + else + return "error"; +} + +static void log_fatal_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); + } else if (err == EACCES) { + log_fatal("WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); + } else if (err == ENOSPC) { + log_fatal("WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); + } else { + log_fatal("WARNING! Without a working %s disk, it isn't possible to continue.\n", name); + } +} + +static void log_error_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s.\n", name); + } +} + /** * Buffer for storing the new hashes. */ @@ -142,39 +170,32 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ - if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); - log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_IOERROR; - return; - } - - log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_ERROR; + + if (errno == EIO) { + task->state = TASK_STATE_IOERROR; + } else { + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } } - ret = handle_open(handle, task->file, state->file_mode, log_error, 0); + ret = handle_open(handle, task->file, state->file_mode, log_error, 0); /* for missing file don't output a message */ if (ret == -1) { + log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); if (errno == EIO) { /* LCOV_EXCL_START */ - log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; /* LCOV_EXCL_STOP */ } - log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } @@ -196,15 +217,15 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { + log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - log_error("DANGER! Unexpected input/output error in a data disk, it isn't possible to scrub.\n"); - log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos); + /* LCOV_EXCL_START */ + log_error_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; return; + /* LCOV_EXCL_STOP */ } - log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } @@ -228,15 +249,15 @@ static void scrub_parity_reader(struct snapraid_worker* worker, struct snapraid_ /* read the parity */ ret = parity_read(parity_handle, blockcur, buffer, state->block_size, log_error); if (ret == -1) { + log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); if (errno == EIO) { - log_tag("parity_error_io:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno)); - log_error("DANGER! Unexpected input/output error in a parity disk, it isn't possible to scrub.\n"); - log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur); + /* LCOV_EXCL_START */ + log_error_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; return; + /* LCOV_EXCL_STOP */ } - log_tag("parity_error:%u:%s: Read error. %s\n", blockcur, lev_config_name(level), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } @@ -445,8 +466,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Too many input/output read error in a data disk, it isn't possible to scrub.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, task->path); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", disk->dir); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -544,8 +564,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Too many input/output read error in the %s disk, it isn't possible to scrub.\n", lev_name(levcur)); - log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(levcur)); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_name(levcur)); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -719,15 +738,12 @@ bail: ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); ++io_error; } else { - log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); ++error; } /* continue, as we are already exiting */ @@ -927,7 +943,8 @@ int state_scrub(struct snapraid_state* state, int plan, int olderthan) ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to scrub.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -945,7 +962,9 @@ int state_scrub(struct snapraid_state* state, int plan, int olderthan) ret = parity_close(&parity_handle[l]); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); + ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ diff --git a/cmdline/sync.c b/cmdline/sync.c index 19f4e7a3..6f391725 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -28,6 +28,42 @@ /****************************************************************************/ /* hash */ +static const char* es(int err) +{ + if (err == EIO) + return "error_io"; + else + return "error"; +} + +static void log_fatal_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); + } else if (err == EACCES) { + log_fatal("WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); + } else if (err == ENOSPC) { + log_fatal("WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); + } else { + log_fatal("WARNING! Without a working %s disk, it isn't possible to continue.\n", name); + } +} + +static void log_error_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal("DANGER! Unexpected input/output error in disk %s.\n", name); + } else if (err == EACCES) { + log_error("WARNING! Grant permission in the disk %s.\n", name); + log_error("Rerun the sync command when finished.\n"); + } else if (err == ENOSPC) { + log_error("WARNING! Ensure there is free space on the disk %s.\n", name); + } else if (err == ENOENT) { + log_error("WARNING! You cannot modify files during a sync.\n"); + log_error("Rerun the sync command when finished.\n"); + } +} + static int state_hash_process(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax, int* skip_sync) { struct snapraid_handle* handle; @@ -138,43 +174,26 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ - if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); - log_fatal("Stopping at block %u\n", i); - ++io_error; - goto bail; - } - - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", i); - ++error; + + if (errno == EIO) { + ++io_error; + } else { + ++error; + } goto bail; /* LCOV_EXCL_STOP */ } } - ret = handle_open(&handle[j], file, state->file_mode, log_error, 0); + ret = handle_open(&handle[j], file, state->file_mode, log_error, log_error); /* output a message for missing files */ if (ret == -1) { - if (errno == EIO) { - /* LCOV_EXCL_START */ - log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); - log_fatal("Stopping at block %u\n", i); - ++io_error; - goto bail; - /* LCOV_EXCL_STOP */ - } - + log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); if (errno == ENOENT) { - log_tag("error:%u:%s:%s: Open ENOENT error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_error("Missing file '%s'.\n", handle[j].path); - log_error("WARNING! You cannot modify data disk during a sync.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(errno, disk->name); + ++error; /* if the file is missing, it means that it was removed during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ @@ -182,21 +201,23 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta } if (errno == EACCES) { - log_tag("error:%u:%s:%s: Open EACCES error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_error("No access at file '%s'.\n", handle[j].path); - log_error("WARNING! Please fix the access permission in the data disk.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(errno, disk->name); + ++error; /* this isn't a serious error, so we skip this block, and continue with others */ continue; } /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Open error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); - log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, file->sub, esc_buffer)); - ++error; + log_fatal_errno(errno, disk->name); + + if (errno == EIO) { + log_fatal("Stopping at block %u\n", i); + ++io_error; + } else { + log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, file->sub, esc_buffer)); + ++error; + } goto bail; /* LCOV_EXCL_STOP */ } @@ -218,9 +239,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta log_tag("error:%u:%s:%s: Unexpected inode change\n", i, disk->name, esc_tag(file->sub, esc_buffer)); log_error("Unexpected inode change from %" PRIu64 " to %" PRIu64 " at file '%s'.\n", file->inode, (uint64_t)handle[j].st.st_ino, handle[j].path); } - log_error("WARNING! You cannot modify files during a sync.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(ENOENT, disk->name); /* same message for ENOENT */ + ++error; + /* if the file is changed, it means that it was modified during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ continue; @@ -229,20 +251,16 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta read_size = handle_read(&handle[j], file_pos, buffer, state->block_size, log_fatal, 0); if (read_size == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); + log_fatal_errno(errno, disk->name); + if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); - log_fatal("DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path); log_fatal("Stopping at block %u\n", i); ++io_error; - goto bail; + } else { + log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, file->sub, esc_buffer)); + ++error; } - - log_tag("error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); - log_fatal("WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be read.\n", handle[j].path); - log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, file->sub, esc_buffer)); - ++error; goto bail; /* LCOV_EXCL_STOP */ } @@ -322,20 +340,15 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ - if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockmax, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); - log_fatal("Stopping at block %u\n", blockmax); - ++io_error; - goto bail; - } - - log_tag("error:%u:%s:%s: Close error. %s\n", blockmax, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockmax); - ++error; + + if (errno == EIO) { + ++io_error; + } else { + ++error; + } goto bail; /* LCOV_EXCL_STOP */ } @@ -379,15 +392,12 @@ bail: ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); ++io_error; } else { - log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); ++error; } /* continue, as we are already exiting */ @@ -528,43 +538,26 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ - if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); - log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_IOERROR; - return; - } - - log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_ERROR; + + if (errno == EIO) { + task->state = TASK_STATE_IOERROR; + } else { + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } } - ret = handle_open(handle, task->file, state->file_mode, log_error, 0); + ret = handle_open(handle, task->file, state->file_mode, log_error, log_error); /* output a message for missing files */ if (ret == -1) { - if (errno == EIO) { - /* LCOV_EXCL_START */ - log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); - log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_IOERROR; - return; - /* LCOV_EXCL_STOP */ - } - + log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); if (errno == ENOENT) { - log_tag("error:%u:%s:%s: Open ENOENT error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_error("Missing file '%s'.\n", handle->path); - log_error("WARNING! You cannot modify data disk during a sync.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(errno, disk->name); + /* if the file is missing, it means that it was removed during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ task->state = TASK_STATE_ERROR_CONTINUE; @@ -572,21 +565,23 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas } if (errno == EACCES) { - log_tag("error:%u:%s:%s: Open EACCES error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_error("No access at file '%s'.\n", handle->path); - log_error("WARNING! Please fix the access permission in the data disk.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(errno, disk->name); + /* this isn't a serious error, so we skip this block, and continue with others */ task->state = TASK_STATE_ERROR_CONTINUE; return; } /* LCOV_EXCL_START */ - log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); - log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, task->file->sub, esc_buffer)); - task->state = TASK_STATE_ERROR; + log_fatal_errno(errno, disk->name); + + if (errno == EIO) { + log_fatal("Stopping at block %u\n", blockcur); + task->state = TASK_STATE_IOERROR; + } else { + log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, task->file->sub, esc_buffer)); + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } @@ -606,8 +601,8 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas } else { log_error("Unexpected inode change from %" PRIu64 " to %" PRIu64 " at file '%s'.\n", task->file->inode, (uint64_t)handle->st.st_ino, handle->path); } - log_error("WARNING! You cannot modify files during a sync.\n"); - log_error("Rerun the sync command when finished.\n"); + log_error_errno(ENOENT, disk->name); /* same message for ENOENT */ + /* if the file is changed, it means that it was modified during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ task->state = TASK_STATE_ERROR_CONTINUE; @@ -617,19 +612,17 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { /* LCOV_EXCL_START */ - if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - log_fatal("DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n"); - log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos); - task->state = TASK_STATE_IOERROR_CONTINUE; - return; - } + log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - log_fatal("WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that file '%s' can be read.\n", handle->path); - log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, task->file->sub, esc_buffer)); - task->state = TASK_STATE_ERROR; + if (errno == EIO) { + log_error_errno(errno, disk->name); + /* continue until the error limit is reached */ + task->state = TASK_STATE_IOERROR_CONTINUE; + } else { + log_fatal_errno(errno, disk->name); + log_fatal("Stopping to allow recovery. Try with 'snapraid check -f /%s'\n", fmt_poll(disk, task->file->sub, esc_buffer)); + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } @@ -654,18 +647,17 @@ static void sync_parity_writer(struct snapraid_worker* worker, struct snapraid_t ret = parity_write(parity_handle, blockcur, buffer, state->block_size); if (ret == -1) { /* LCOV_EXCL_START */ - if (errno == EIO) { - log_tag("parity_error_io:%u:%s: Write EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno)); - log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur); - task->state = TASK_STATE_IOERROR_CONTINUE; - return; - } + log_tag("parity_%s:%u:%s: Write error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); - log_tag("parity_error:%u:%s: Write error. %s\n", blockcur, lev_config_name(level), strerror(errno)); - log_fatal("WARNING! Unexpected write error in the %s disk, it isn't possible to sync.\n", lev_name(level)); - log_fatal("Ensure that disk '%s' has some free space available.\n", lev_config_name(level)); - log_fatal("Stopping at block %u\n", blockcur); - task->state = TASK_STATE_ERROR; + if (errno == EIO) { + log_error_errno(errno, lev_config_name(level)); + /* continue until the error limit is reached */ + task->state = TASK_STATE_IOERROR_CONTINUE; + } else { + log_fatal_errno(errno, lev_config_name(level)); + log_fatal("Stopping at block %u\n", blockcur); + task->state = TASK_STATE_ERROR; + } return; /* LCOV_EXCL_STOP */ } @@ -927,8 +919,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, task->path); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", disk->dir); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -1089,25 +1080,22 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ret = parity_read(&parity_handle[l], blockcur, buffer[diskmax + l], state->block_size, log_error); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(l), strerror(errno)); if (errno == EIO) { - log_tag("parity_error_io:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(l), strerror(errno)); + log_error_errno(errno, lev_config_name(l)); if (io_error >= state->opt.io_error_limit) { - log_fatal("DANGER! Unexpected input/output read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); - log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l)); + log_fatal("DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_config_name(l)); log_fatal("Stopping at block %u\n", blockcur); ++io_error; goto bail; } - log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(l), blockcur); ++io_error; io_error_on_this_block = 1; continue; } - log_tag("parity_error:%u:%s: Read error. %s\n", blockcur, lev_config_name(l), strerror(errno)); - log_fatal("WARNING! Unexpected read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); - log_fatal("Ensure that disk '%s' can be read.\n", lev_config_name(l)); + log_fatal_errno(errno, lev_config_name(l)); log_fatal("Stopping at block %u\n", blockcur); ++error; goto bail; @@ -1275,7 +1263,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ++io_error; if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected input/output write error in a parity disk, it isn't possible to sync.\n"); + log_fatal("DANGER! Too many input/output errors in a parity disk. It isn't possible to continue.\n"); log_fatal("Stopping at block %u\n", blockcur); goto bail; /* LCOV_EXCL_STOP */ @@ -1440,18 +1428,14 @@ bail: ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ + log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); + log_fatal_errno(errno, disk->name); + if (errno == EIO) { - log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("DANGER! Unexpected input/output close error in a data disk.\n"); - log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); ++io_error; } else { - log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); - log_fatal("WARNING! Unexpected close error in a data disk.\n"); - log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); ++error; } - ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } @@ -1521,7 +1505,8 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t ret = parity_create(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to sync.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Create error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -1647,7 +1632,9 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t ret = parity_close(&parity_handle[l]); if (ret == -1) { /* LCOV_EXCL_START */ - log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l)); + log_tag("parity_%s:%u:%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); + log_fatal_errno(errno, lev_config_name(l)); + ++unrecoverable_error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */