diff --git a/Makefile.am b/Makefile.am index 17aecd5e..fb52b9b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -218,7 +218,8 @@ endif $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) up $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) down $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) test-devices - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) smart -v + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS_VERBOSE) -c $(CONF) smart + $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS_VERBOSE) -c $(CONF) smart --test-fake-device --test-expect-failure if HAVE_SYMLINK $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(PAR1) pool endif diff --git a/cmdline/device.c b/cmdline/device.c index a776ddd6..699510d9 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -52,13 +52,13 @@ /* * Divider for SMART attribute 5 */ -unsigned SMART_5_STEP = 1; +static unsigned SMART_5_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 5 at a given value. */ -double SMART_5_R[SMART_MEASURES] = { +static double SMART_5_R[SMART_MEASURES] = { 0.0034, 0.0738, 0.0883, 0.0960, 0.1016, 0.1062, 0.1106, 0.1142, 0.1189, 0.1259, 0.1307, 0.1337, 0.1368, 0.1400, 0.1419, @@ -116,13 +116,13 @@ double SMART_5_R[SMART_MEASURES] = { /* * Divider for SMART attribute 187 */ -unsigned SMART_187_STEP = 1; +static unsigned SMART_187_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 187 at a given value. */ -double SMART_187_R[SMART_MEASURES] = { +static double SMART_187_R[SMART_MEASURES] = { 0.0048, 0.0957, 0.1157, 0.1306, 0.1415, 0.1501, 0.1695, 0.2444, 0.2714, 0.2925, 0.3113, 0.3284, 0.3515, 0.4054, 0.4331, @@ -180,13 +180,13 @@ double SMART_187_R[SMART_MEASURES] = { /* * Divider for SMART attribute 188 */ -unsigned SMART_188_STEP = 1; +static unsigned SMART_188_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 188 at a given value. */ -double SMART_188_R[SMART_MEASURES] = { +static double SMART_188_R[SMART_MEASURES] = { 0.0028, 0.0312, 0.0493, 0.0625, 0.0712, 0.0773, 0.0818, 0.0891, 0.0950, 0.1006, 0.1054, 0.1093, 0.1129, 0.1193, 0.1241, @@ -244,13 +244,13 @@ double SMART_188_R[SMART_MEASURES] = { /* * Divider for SMART attribute 193 */ -unsigned SMART_193_STEP = 1626; +static unsigned SMART_193_STEP = 1626; /* * Failure rate for 30 days, for a disk * with SMART attribute 193 at a given value. */ -double SMART_193_R[SMART_MEASURES] = { +static double SMART_193_R[SMART_MEASURES] = { 0.0000, 0.0029, 0.0033, 0.0040, 0.0046, 0.0051, 0.0059, 0.0065, 0.0073, 0.0080, 0.0088, 0.0096, 0.0104, 0.0112, 0.0117, @@ -308,13 +308,13 @@ double SMART_193_R[SMART_MEASURES] = { /* * Divider for SMART attribute 197 */ -unsigned SMART_197_STEP = 1; +static unsigned SMART_197_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 197 at a given value. */ -double SMART_197_R[SMART_MEASURES] = { +static double SMART_197_R[SMART_MEASURES] = { 0.0036, 0.2430, 0.3027, 0.3349, 0.3533, 0.3632, 0.3722, 0.3790, 0.4199, 0.6417, 0.6517, 0.6583, 0.6647, 0.6680, 0.6737, @@ -372,13 +372,13 @@ double SMART_197_R[SMART_MEASURES] = { /* * Divider for SMART attribute 198 */ -unsigned SMART_198_STEP = 1; +static unsigned SMART_198_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 198 at a given value. */ -double SMART_198_R[SMART_MEASURES] = { +static double SMART_198_R[SMART_MEASURES] = { 0.0038, 0.3963, 0.4189, 0.4297, 0.4364, 0.4393, 0.4433, 0.4490, 0.4909, 0.7634, 0.7649, 0.7683, 0.7689, 0.7703, 0.7717, @@ -436,13 +436,13 @@ double SMART_198_R[SMART_MEASURES] = { /* * Divider for SMART attribute 199 */ -unsigned SMART_199_STEP = 1; +static unsigned SMART_199_STEP = 1; /* * Failure rate for 30 days, for a disk * with SMART attribute 199 at a given value. */ -double SMART_199_R[SMART_MEASURES] = { +static double SMART_199_R[SMART_MEASURES] = { 0.0037, 0.0449, 0.0680, 0.0872, 0.1023, 0.1153, 0.1272, 0.1375, 0.1462, 0.1564, 0.1641, 0.1722, 0.1790, 0.1846, 0.1915, @@ -512,7 +512,7 @@ static double smart_afr_value(double* tab, unsigned step, uint64_t value) } /** - * Computes the estimated Annual Failure Rare of a set of SMART attributes. + * Computes the estimated Annual Failure Rate of a set of SMART attributes. * * We define the Annual Failure Rate as the average number of * failures you expect in a year from a disk slot: @@ -786,7 +786,7 @@ static void state_smart(unsigned n, tommy_list* low) if (flag & SMARTCTL_FLAG_FAIL) printf(" FAIL"); else if (flag & (SMARTCTL_FLAG_PREFAIL | SMARTCTL_FLAG_PREFAIL_LOGGED)) - printf(" PREFAIL"); + printf(" PREFAIL"); else if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED && devinfo->smart[SMART_ERROR] != 0) printf("%8" PRIu64, devinfo->smart[SMART_ERROR]); @@ -822,7 +822,7 @@ static void state_smart(unsigned n, tommy_list* low) } if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) - printf(" %2.1f", devinfo->smart[SMART_SIZE] / 1E12); + printf(" %4.1f", devinfo->smart[SMART_SIZE] / 1E12); else printf(" -"); @@ -877,7 +877,7 @@ static void state_smart(unsigned n, tommy_list* low) /* prints extra stats only in verbose mode */ if (msg_level < MSG_VERBOSE) - return; + goto bail; /* |<##################################################################72>|####80>| */ printf("\n"); @@ -905,22 +905,84 @@ static void state_smart(unsigned n, tommy_list* low) printf("that you regularly scrub, and in case repair, the array in the specified\n"); printf("time.\n"); +bail: if (make_it_fail) { - /* LCOV_EXCL_START */ printf("\n"); printf("DANGER! SMART is reporting that one or more disks are FAILING!\n"); printf("Please take immediate action!\n"); exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ } } +/** + * Fill with fake data the device list. + */ +static int devtest(tommy_list* low, int operation) +{ + unsigned c; + + if (operation != DEVICE_SMART) + return -1; + + /* add some fake data */ + for (c = 0; c < 16; ++c) { + devinfo_t* entry; + int j; + + entry = calloc_nofail(1, sizeof(devinfo_t)); + + entry->device = c; + + tommy_list_insert_tail(low, &entry->node, entry); + + for (j = 0; j < 256; ++j) { + switch (c) { + case 0 : entry->smart[j] = 0; break; + case 1 : entry->smart[j] = SMART_UNASSIGNED; break; + default : entry->smart[j] = c; break; + } + } + + if (c == 0) { + entry->smart_serial[0] = 0; + entry->file[0] = 0; + entry->name[0] = 0; + entry->smart[SMART_SIZE] = SMART_UNASSIGNED; + entry->smart[SMART_ROTATION_RATE] = 0; + } else { + snprintf(entry->smart_serial, sizeof(entry->smart_serial), "%u", c); + pathcpy(entry->file, sizeof(entry->name), "file"); + pathcpy(entry->name, sizeof(entry->name), "name"); + entry->smart[SMART_SIZE] = c * TERA; + entry->smart[SMART_ROTATION_RATE] = 7200; + } + + entry->smart[SMART_ERROR] = 0; + entry->smart[SMART_FLAGS] = SMART_UNASSIGNED; + + switch (c) { + case 3 : entry->smart[SMART_ERROR] = 1; break; + case 4 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_UNSUPPORTED; break; + case 5 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_COMMAND; break; + case 6 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_OPEN; break; + case 7 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_FAIL; break; + case 8 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_PREFAIL; break; + case 9 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_PREFAIL_LOGGED; break; + case 10 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_ERROR; break; + case 11 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_ERROR_LOGGED; break; + } + } + + return 0; +} + void state_device(struct snapraid_state* state, int operation) { tommy_node* i; unsigned j; tommy_list high; tommy_list low; + int ret; switch (operation) { case DEVICE_UP : msg_progress("Spinup...\n"); break; @@ -958,7 +1020,12 @@ void state_device(struct snapraid_state* state, int operation) tommy_list_insert_tail(&high, &entry->node, entry); } - if (devquery(&high, &low, operation) != 0) { + if (state->opt.fake_device) + ret = devtest(&low, operation); + else + ret = devquery(&high, &low, operation); + + if (ret != 0) { const char* ope = 0; switch (operation) { case DEVICE_UP : ope = "Spinup"; break; diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index cc10e98f..b5e97c6d 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -244,6 +244,7 @@ void config(char* conf, size_t conf_size, const char* argv0) #define OPT_TEST_FORCE_PROGRESS 281 #define OPT_TEST_SKIP_DISK_ACCESS 282 #define OPT_TEST_FORCE_AUTOSAVE_AT 283 +#define OPT_TEST_FAKE_DEVICE 284 #if HAVE_GETOPT_LONG struct option long_options[] = { @@ -355,6 +356,9 @@ struct option long_options[] = { /* Force autosave at the specified block */ { "test-force-autosave-at", 1, 0, OPT_TEST_FORCE_AUTOSAVE_AT }, + /* Fake device data */ + { "test-fake-device", 0, 0, OPT_TEST_FAKE_DEVICE }, + { 0, 0, 0, 0 } }; #endif @@ -686,6 +690,9 @@ int main(int argc, char* argv[]) case OPT_TEST_FORCE_AUTOSAVE_AT : opt.force_autosave_at = atoi(optarg); break; + case OPT_TEST_FAKE_DEVICE : + opt.fake_device = 1; + break; default : /* LCOV_EXCL_START */ msg_error("Unknown option '%c'\n", (char)c); diff --git a/cmdline/state.h b/cmdline/state.h index 7ca07688..e8e82afb 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -46,6 +46,7 @@ const char* lev_config_name(unsigned level); */ #define MEGA (1000 * 1000) #define GIGA (1000 * 1000 * 1000) +#define TERA (1000 * 1000 * 1000 * 1000LL) /** * File modes. @@ -101,6 +102,7 @@ struct snapraid_option { int force_scan_winfind; /**< Force the use of FindFirst/Next in Windows to list directories. */ int force_progress; /**< Force the use of the progress status. */ unsigned force_autosave_at; /**< Force autosave at the specified block. */ + int fake_device; /**< Fake device data. */ }; /**