From 1f17ceca84db2a32763eb7a45dc48af0bba719e7 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 18 Dec 2025 18:16:02 +0100 Subject: [PATCH] Log disk information info also in probe --- cmdline/device.c | 86 ++++++++++++++++++++++++++++------------------ cmdline/mingw.c | 18 +++++----- cmdline/portable.h | 32 ++++++++++------- cmdline/support.c | 35 +++++++++++++++---- cmdline/support.h | 2 +- cmdline/unix.c | 14 ++++---- 6 files changed, 117 insertions(+), 70 deletions(-) diff --git a/cmdline/device.c b/cmdline/device.c index 1aadea94..70d46dfc 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -535,6 +535,41 @@ static double raid_prob_of_one_or_more_failures(double array_failure_rate, doubl return poisson_prob_n_or_more_failures(raid_failure_rate, 1); } +static void state_info_log(devinfo_t* devinfo) +{ + char esc_buffer[ESC_MAX]; + + log_tag("info:%s:%s\n", devinfo->file, devinfo->name); + if (devinfo->serial[0]) + log_tag("attr:%s:%s:serial:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->serial, esc_buffer)); + if (devinfo->vendor[0]) + log_tag("attr:%s:%s:vendor:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->vendor, esc_buffer)); + if (devinfo->model[0]) + log_tag("attr:%s:%s:model:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->model, esc_buffer)); + if (devinfo->info[INFO_SIZE] != SMART_UNASSIGNED) + log_tag("attr:%s:%s:size:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->info[INFO_SIZE]); + if (devinfo->info[INFO_ROTATION_RATE] != SMART_UNASSIGNED) + log_tag("attr:%s:%s:rotationrate:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->info[INFO_ROTATION_RATE]); +} + +static void state_smart_log(devinfo_t* devinfo, double afr) +{ + unsigned j; + + log_tag("smart:%s:%s\n", devinfo->file, devinfo->name); + if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED) + log_tag("attr:%s:%s:error:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ERROR]); + if (devinfo->smart[SMART_FLAGS] != SMART_UNASSIGNED) + log_tag("attr:%s:%s:flags:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_FLAGS], devinfo->smart[SMART_FLAGS]); + + if (afr != 0) + log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_n_or_more_failures(afr, 1)); + + for (j = 0; j < 256; ++j) + if (devinfo->smart[j] != SMART_UNASSIGNED) + log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, j, devinfo->smart[j], devinfo->smart[j]); +} + static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* low) { tommy_node* i; @@ -547,7 +582,6 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo int make_it_fail = 0; uint64_t mask32 = 0xffffffffU; uint64_t mask16 = 0xffffU; - char esc_buffer[ESC_MAX]; /* compute lengths for padding */ device_pad = 0; @@ -561,7 +595,7 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo if (len > device_pad) device_pad = len; - len = strlen(devinfo->smart_serial); + len = strlen(devinfo->serial); if (len > serial_pad) serial_pad = len; @@ -646,12 +680,12 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo /* if error running smartctl, skip AFR estimation */ afr = 0; printf(" n/a"); - } else if (devinfo->smart[SMART_ROTATION_RATE] == 0) { + } else if (devinfo->info[INFO_ROTATION_RATE] == 0) { /* if SSD, skip AFR estimation as data is from not SSD disks */ afr = 0; printf(" SSD"); } else { - afr = smart_afr(devinfo->smart, devinfo->smart_model); + afr = smart_afr(devinfo->smart, devinfo->model); if (afr == 0) { /* this happens only if no data */ @@ -665,14 +699,14 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo } } - if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) - printf(" %4.1f", devinfo->smart[SMART_SIZE] / 1E12); + if (devinfo->info[INFO_SIZE] != SMART_UNASSIGNED) + printf(" %4.1f", devinfo->info[INFO_SIZE] / 1E12); else printf(" -"); printf(" "); - if (*devinfo->smart_serial) - printl(devinfo->smart_serial, serial_pad); + if (*devinfo->serial) + printl(devinfo->serial, serial_pad); else printl("-", serial_pad); @@ -690,26 +724,8 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo printf("\n"); - log_tag("smart:%s:%s\n", devinfo->file, devinfo->name); - if (devinfo->smart_serial[0]) - log_tag("attr:%s:%s:serial:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_serial, esc_buffer)); - if (devinfo->smart_vendor[0]) - log_tag("attr:%s:%s:vendor:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_vendor, esc_buffer)); - if (devinfo->smart_model[0]) - log_tag("attr:%s:%s:model:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_model, esc_buffer)); - if (afr != 0) - log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_n_or_more_failures(afr, 1)); - if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) - log_tag("attr:%s:%s:size:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_SIZE]); - if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED) - log_tag("attr:%s:%s:error:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ERROR]); - if (devinfo->smart[SMART_ROTATION_RATE] != SMART_UNASSIGNED) - log_tag("attr:%s:%s:rotationrate:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ROTATION_RATE]); - if (devinfo->smart[SMART_FLAGS] != SMART_UNASSIGNED) - log_tag("attr:%s:%s:flags:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_FLAGS], devinfo->smart[SMART_FLAGS]); - for (j = 0; j < 256; ++j) - if (devinfo->smart[j] != SMART_UNASSIGNED) - log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, j, devinfo->smart[j], devinfo->smart[j]); + state_info_log(devinfo); + state_smart_log(devinfo, afr); } printf("\n"); @@ -783,6 +799,8 @@ static void state_probe(struct snapraid_state* state, tommy_list* low) len = strlen(devinfo->file); if (len > device_pad) device_pad = len; + + state_info_log(devinfo); } printf("SnapRAID PROBE report:\n"); @@ -860,16 +878,16 @@ int devtest(tommy_list* high, tommy_list* low, int operation) } } - pathprint(entry->smart_serial, sizeof(entry->smart_serial), "FAKE_%s", devinfo->smart_serial); - pathprint(entry->smart_vendor, sizeof(entry->smart_vendor), "FAKE_%s", devinfo->smart_vendor); - pathprint(entry->smart_model, sizeof(entry->smart_model), "FAKE_%s", devinfo->smart_model); + pathprint(entry->serial, sizeof(entry->serial), "FAKE_%s", devinfo->serial); + pathprint(entry->vendor, sizeof(entry->vendor), "FAKE_%s", devinfo->vendor); + pathprint(entry->model, sizeof(entry->model), "FAKE_%s", devinfo->model); pathprint(entry->file, sizeof(entry->name), "FAKE_%s", devinfo->file); pathcpy(entry->name, sizeof(entry->name), devinfo->name); - entry->smart[SMART_SIZE] = count * TERA; - entry->smart[SMART_ROTATION_RATE] = 7200; - entry->smart[SMART_TEMPERATURE_CELSIUS] = 27; + entry->info[INFO_SIZE] = count * TERA; + entry->info[INFO_ROTATION_RATE] = 7200; entry->smart[SMART_ERROR] = 0; entry->smart[SMART_FLAGS] = SMART_UNASSIGNED; + entry->smart[SMART_TEMPERATURE_CELSIUS] = 27; switch (count) { case 3 : entry->smart[SMART_ERROR] = 1; break; diff --git a/cmdline/mingw.c b/cmdline/mingw.c index 85166fca..6eddf561 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2498,7 +2498,7 @@ static int devscan(tommy_list* list) /** * Get SMART attributes. */ -static int devsmart(uint64_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model) +static int devsmart(uint64_t device, const char* name, const char* smartctl, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model) { char conv_buf[CONV_MAX]; WCHAR cmd[MAX_PATH + 128]; @@ -2532,7 +2532,7 @@ retry: /* LCOV_EXCL_STOP */ } - if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) { + if (smartctl_attribute(f, file, name, smart, info, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); log_tag("device:%s:%s:shell\n", file, name); @@ -2567,8 +2567,8 @@ retry: */ if ((ret == 0 || ret == 2) && smart[9] == SMART_UNASSIGNED - && smart[SMART_SIZE] == SMART_UNASSIGNED - && smart[SMART_ROTATION_RATE] == SMART_UNASSIGNED + && info[INFO_SIZE] == SMART_UNASSIGNED + && info[INFO_ROTATION_RATE] == SMART_UNASSIGNED ) { /* retry using the "sat" type */ snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a -d sat %s", exedir, file); @@ -2587,7 +2587,7 @@ retry: /** * Get POWER state */ -static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power) +static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, uint64_t* info, char* serial, char* vendor, char* model) { char conv_buf[CONV_MAX]; WCHAR cmd[MAX_PATH + 128]; @@ -2621,7 +2621,7 @@ retry: /* LCOV_EXCL_STOP */ } - if (smartctl_flush(f, file, name) != 0) { + if (smartctl_attribute(f, file, name, 0, info, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); log_tag("device:%s:%s:shell\n", file, name); @@ -2770,7 +2770,7 @@ static int devdownifup(uint64_t device, const char* name, const char* smartctl, { *power = POWER_UNKNOWN; - if (devprobe(device, name, smartctl, power) != 0) + if (devprobe(device, name, smartctl, power, 0, 0, 0, 0) != 0) return -1; if (*power == POWER_ACTIVE) @@ -2918,7 +2918,7 @@ static void* thread_smart(void* arg) { devinfo_t* devinfo = arg; - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) { + if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */ @@ -2934,7 +2934,7 @@ static void* thread_probe(void* arg) { devinfo_t* devinfo = arg; - if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power) != 0) { + if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */ diff --git a/cmdline/portable.h b/cmdline/portable.h index 374304a8..cc133ddf 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -447,18 +447,25 @@ int randomize(void* ptr, size_t size); #define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190 #define SMART_TEMPERATURE_CELSIUS 194 -/** - * Additional SMART attributes. - */ -#define SMART_ERROR 256 /**< ATA Error count. */ -#define SMART_SIZE 257 /**< Size in bytes. */ -#define SMART_ROTATION_RATE 258 /**< Rotation speed. 0 for SSD. */ -#define SMART_FLAGS 259 /**< Flags returned by smartctl. */ +#define SMART_FLAGS 256 /**< Flags returned by smartctl. */ +#define SMART_ERROR 257 /**< ATA Error count. */ /** * SMART attributes count. */ -#define SMART_COUNT 260 +#define SMART_COUNT 258 + +/** + * Info attributes. + */ +#define INFO_SIZE 0 /**< Size in bytes. */ +#define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */ + +/** + * Info attributes count. + */ +#define INFO_COUNT 2 + #define SMART_IGNORE_MAX 4 /**< Max number of ignored smart attributes */ @@ -506,10 +513,11 @@ struct devinfo_struct { char wfile[PATH_MAX]; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */ #endif struct devinfo_struct* parent; /**< Pointer at the parent if any. */ - uint64_t smart[SMART_COUNT]; /**< SMART raw attributes. */ - char smart_serial[SMART_MAX]; /**< SMART serial number. */ - char smart_vendor[SMART_MAX]; /**< SMART vendor. */ - char smart_model[SMART_MAX]; /**< SMART model. */ + uint64_t smart[SMART_COUNT]; /**< SMART attributes. */ + uint64_t info[INFO_COUNT]; /**< Info attributes. */ + char serial[SMART_MAX]; /**< Serial number. */ + char vendor[SMART_MAX]; /**< Vendor. */ + char model[SMART_MAX]; /**< Model. */ int power; /**< POWER mode. */ #if HAVE_THREAD thread_id_t thread; diff --git a/cmdline/support.c b/cmdline/support.c index f0fc5633..7ea03982 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -1610,15 +1610,36 @@ static int smatch(const char* str, const char* pattern) return 0; } -int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model) +int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model) { unsigned i; int inside; + uint64_t dummy_smart[SMART_COUNT]; + uint64_t dummy_info[INFO_COUNT]; + char dummy_serial[SMART_MAX]; + char dummy_vendor[SMART_MAX]; + char dummy_model[SMART_MAX]; - /* preclear attribute */ + /* dummy attributes */ + if (!smart) + smart = dummy_smart; + if (!info) + info = dummy_info; + if (!serial) + serial = dummy_serial; + if (!vendor) + vendor = dummy_vendor; + if (!model) + model = dummy_model; + + /* preclear attributes */ *serial = 0; + *vendor = 0; + *model = 0; for (i = 0; i < SMART_COUNT; ++i) smart[i] = SMART_UNASSIGNED; + for (i = 0; i < INFO_COUNT; ++i) + info[i] = SMART_UNASSIGNED; /* read the file */ inside = 0; @@ -1645,18 +1666,18 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* sm inside = 0; /* common */ } else if (smatch(s, "Rotation Rate: Solid State") == 0) { - smart[SMART_ROTATION_RATE] = 0; - } else if (sscanf(s, "Rotation Rate: %" SCNu64, &smart[SMART_ROTATION_RATE]) == 1) { + info[INFO_ROTATION_RATE] = 0; + } else if (sscanf(s, "Rotation Rate: %" SCNu64, &info[INFO_ROTATION_RATE]) == 1) { } else if (smatch(s, "User Capacity:") == 0) { char* begin = strchr(s, ':'); char* end = strstr(s, "bytes"); if (begin != 0 && end != 0 && begin < end) { char* p; - smart[SMART_SIZE] = 0; + info[INFO_SIZE] = 0; for (p = begin; p != end; ++p) { if (isdigit(*p)) { - smart[SMART_SIZE] *= 10; - smart[SMART_SIZE] += *p - '0'; + info[INFO_SIZE] *= 10; + info[INFO_SIZE] += *p - '0'; } } } diff --git a/cmdline/support.h b/cmdline/support.h index 2221bf52..cfd7fa22 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -421,7 +421,7 @@ void malloc_fail(size_t size); * Read smartctl attributes from a stream. * Return 0 on success. */ -int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model); +int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model); /** * Flush smartctl output from a stream. diff --git a/cmdline/unix.c b/cmdline/unix.c index 0c0be387..fe0e766d 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -1140,7 +1140,7 @@ static int devscan(tommy_list* list) * Get SMART attributes. */ #if HAVE_LINUX_DEVICE -static int devsmart(dev_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model) +static int devsmart(dev_t device, const char* name, const char* smartctl, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model) { char cmd[PATH_MAX + 64]; char file[PATH_MAX]; @@ -1174,7 +1174,7 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64 /* LCOV_EXCL_STOP */ } - if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) { + if (smartctl_attribute(f, file, name, smart, info, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); log_tag("device:%s:%s:shell\n", file, name); @@ -1212,7 +1212,7 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64 * Get POWER state. */ #if HAVE_LINUX_DEVICE -static int devprobe(dev_t device, const char* name, const char* smartctl, int* power) +static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, uint64_t* info, char* serial, char* vendor, char* model) { char cmd[PATH_MAX + 64]; char file[PATH_MAX]; @@ -1246,7 +1246,7 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, int* p /* LCOV_EXCL_STOP */ } - if (smartctl_flush(f, file, name) != 0) { + if (smartctl_attribute(f, file, name, 0, info, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); log_tag("device:%s:%s:shell\n", file, name); @@ -1376,7 +1376,7 @@ static int devdownifup(dev_t device, const char* name, const char* smartctl, int { *power = POWER_UNKNOWN; - if (devprobe(device, name, smartctl, power) != 0) + if (devprobe(device, name, smartctl, power, 0, 0, 0, 0) != 0) return -1; if (*power == POWER_ACTIVE) @@ -1542,7 +1542,7 @@ static void* thread_smart(void* arg) #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) { + if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */ @@ -1563,7 +1563,7 @@ static void* thread_probe(void* arg) #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power) != 0) { + if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */