Log full SMART attributes

This commit is contained in:
Andrea Mazzoleni 2026-02-16 15:43:25 +01:00
parent 5e98164b64
commit 696ee97754
9 changed files with 95 additions and 26 deletions

View file

@ -408,7 +408,7 @@ static double smart_afr_value(double* tab, unsigned step, uint64_t value)
* we use the maximum rate reported, and we do not sum them,
* because the attributes are not independent.
*/
static double smart_afr(struct smart_struct* smart, const char* model)
static double smart_afr(struct smart_attr* smart, const char* model)
{
double afr = 0;
uint64_t mask32 = 0xffffffffU;
@ -556,10 +556,31 @@ static void state_smart_log(devinfo_t* devinfo, double afr)
if (afr != 0)
log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_at_least_one_failure(afr));
for (j = 0; j < 256; ++j)
if (devinfo->smart[j].raw != SMART_UNASSIGNED) {
log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%s\n", devinfo->file, devinfo->name, j, devinfo->smart[j].raw, devinfo->smart[j].raw, devinfo->smart[j].norm, devinfo->smart[j].worst, devinfo->smart[j].thresh, devinfo->smart[j].name);
for (j = 0; j < 256; ++j) {
struct smart_attr* attr = &devinfo->smart[j];
if (attr->raw != SMART_UNASSIGNED) {
const char* type = "";;
const char* updated = "";
const char* when_failed = "";
if (attr->flags & SMART_ATTR_TYPE_PREFAIL)
type = "prefail";
else if (attr->flags & SMART_ATTR_TYPE_OLDAGE)
type = "oldage";
if (attr->flags & SMART_ATTR_UPDATE_ALWAYS)
updated = "always";
else if (attr->flags & SMART_ATTR_UPDATE_OFFLINE)
updated = "offline";
if (attr->flags & SMART_ATTR_WHEN_FAILED_NOW)
when_failed = "now";
else if (attr->flags & SMART_ATTR_WHEN_FAILED_PAST)
when_failed = "past";
else if (attr->flags & SMART_ATTR_WHEN_FAILED_NEVER)
when_failed = "never";
log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%s:%s:%s:%s\n", devinfo->file, devinfo->name, j, attr->raw, attr->raw, attr->norm, attr->worst, attr->thresh, attr->name, type, updated, when_failed);
}
}
int temp = smart_temp(devinfo);
if (temp >= 0)

View file

@ -2506,7 +2506,7 @@ static int devscan(tommy_list* list)
/**
* Get SMART attributes.
*/
static int devsmart(uint64_t device, const char* name, const char* smartctl, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* inter)
static int devsmart(uint64_t device, const char* name, const char* smartctl, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* inter)
{
char conv_buf[CONV_MAX];
WCHAR cmd[MAX_PATH + 128];
@ -2738,7 +2738,7 @@ static void devattr(uint64_t device, const char* name, const char* wfile, uint64
/**
* Get POWER state
*/
static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interf)
static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf)
{
char conv_buf[CONV_MAX];
WCHAR cmd[MAX_PATH + 128];

View file

@ -502,6 +502,25 @@ int randomize(void* ptr, size_t size);
*/
#define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL
/**
* SMART Attribute flags
*/
#define SMART_ATTR_TYPE_PREFAIL 1
#define SMART_ATTR_TYPE_OLDAGE 2
#define SMART_ATTR_UPDATE_ALWAYS 4
#define SMART_ATTR_UPDATE_OFFLINE 8
#define SMART_ATTR_WHEN_FAILED_NOW 16
#define SMART_ATTR_WHEN_FAILED_PAST 32
#define SMART_ATTR_WHEN_FAILED_NEVER 64
struct smart_attr {
char name[128]; /**< SMART attribute name. */
uint64_t raw; /**< SMART attributes raw. */
uint64_t norm; /**< SMART attributes normalized. */
uint64_t worst; /**< SMART attributes worst. */
uint64_t thresh; /**< SMART attributes threshold. */
int flags; /**< SMART_ATTR_* flags */
};
/**
* Power mode
@ -510,14 +529,6 @@ int randomize(void* ptr, size_t size);
#define POWER_ACTIVE 1
#define POWER_UNKNOWN -1
struct smart_struct {
char name[128]; /**< SMART attribute name. */
uint64_t raw; /**< SMART attributes raw. */
uint64_t norm; /**< SMART attributes normalized. */
uint64_t worst; /**< SMART attributes worst. */
uint64_t thresh; /**< SMART attributes threshold. */
};
/**
* Device info entry.
*/
@ -533,7 +544,7 @@ struct devinfo_struct {
#endif
struct devinfo_struct* parent; /**< Pointer at the parent if any. */
struct devinfo_struct* split; /**< Pointer at first split if any. */
struct smart_struct smart[SMART_COUNT]; /**< All smart values. */
struct smart_attr smart[SMART_COUNT]; /**< All smart values. */
uint64_t info[INFO_COUNT]; /**< Info attributes. */
uint64_t access_stat; /**< Access stat info. */
char serial[SMART_MAX]; /**< Serial number. */

View file

@ -1702,11 +1702,11 @@ static int smatch(const char* str, const char* pattern)
return 0;
}
int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* inter)
int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* inter)
{
unsigned i;
int inside;
struct smart_struct dummy_smart[SMART_COUNT];
struct smart_attr dummy_smart[SMART_COUNT];
uint64_t dummy_info[INFO_COUNT];
char dummy_serial[SMART_MAX];
char dummy_family[SMART_MAX];
@ -1732,7 +1732,7 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart
*family = 0;
*model = 0;
*inter = 0;
memset(smart, 0, sizeof(struct smart_struct) * SMART_COUNT);
memset(smart, 0, sizeof(struct smart_attr) * SMART_COUNT);
for (i = 0; i < SMART_COUNT; ++i)
smart[i].raw = SMART_UNASSIGNED;
for (i = 0; i < INFO_COUNT; ++i)
@ -1851,11 +1851,16 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart
inside = 1;
} else if (inside) {
char id_name[128] = { 0 };
char type[64] = { 0 };
char updated[64] = { 0 };
char when_failed[64] = { 0 };
uint64_t min, max;
int minmax;
if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %*s %*s %*s %" SCNu64 " (Min/Max %" SCNu64 "/%" SCNu64 ")", &id, id_name, &norm, &worst, &thresh, &raw, &min, &max) == 8) {
int flags;
if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %63s %63s %63s %" SCNu64 " (Min/Max %" SCNu64 "/%" SCNu64 ")", &id, id_name, &norm, &worst, &thresh, type, updated, when_failed, &raw, &min, &max) == 11) {
minmax = 1;
} else if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %*s %*s %*s %" SCNu64, &id, id_name, &norm, &worst, &thresh, &raw) == 6) {
} else if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %63s %63s %63s %" SCNu64, &id, id_name, &norm, &worst, &thresh, type, updated, when_failed, &raw) == 9) {
minmax = 0;
} else {
log_fatal(EEXTERNAL, "Invalid smartctl line '%s'.\n", s);
@ -1869,6 +1874,22 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart
/* LCOV_EXCL_STOP */
}
flags = 0;
if (strcmp(type, "Pre-fail") == 0)
flags |= SMART_ATTR_TYPE_PREFAIL;
else if (strcmp(type, "Old_age") == 0)
flags |= SMART_ATTR_TYPE_OLDAGE;
if (strcmp(updated, "Always") == 0)
flags |= SMART_ATTR_UPDATE_ALWAYS;
else if (strcmp(updated, "Offline") == 0)
flags |= SMART_ATTR_UPDATE_OFFLINE;
if (strcmp(when_failed, "FAILING_NOW") == 0)
flags |= SMART_ATTR_WHEN_FAILED_NOW;
else if (strcmp(when_failed, "In_the_past") == 0)
flags |= SMART_ATTR_WHEN_FAILED_PAST;
else if (strcmp(when_failed, "-") == 0)
flags |= SMART_ATTR_WHEN_FAILED_NEVER;
/* revert the min/max decoding done by smartctl */
if (minmax
&& raw <= 0xFFFFUL
@ -1882,6 +1903,7 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart
smart[id].norm = norm;
smart[id].worst = worst;
smart[id].thresh = thresh;
smart[id].flags = flags;
pathcpy(smart[id].name, sizeof(smart[id].name), id_name);
/*

View file

@ -453,7 +453,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, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interf);
int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf);
/**
* Flush smartctl output from a stream.

View file

@ -1479,7 +1479,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, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interface)
static int devsmart(dev_t device, const char* name, const char* smartctl, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interface)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];
@ -1717,7 +1717,7 @@ static void devattr(dev_t device, uint64_t* info, char* serial, char* family, ch
* Get POWER state.
*/
#if HAVE_LINUX_DEVICE
static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interface)
static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interface)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];

View file

@ -1794,7 +1794,7 @@ The raw flags value (uint, hexadecimal).
.PD
.RE
.TP
.B attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>
.B attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>:<type>:<updated>:<when_failed>
Logs the raw value of any assigned SMART attribute.
.RS 4
.PD 0
@ -1819,6 +1819,15 @@ The threshold value (uint).
.HP 4
.I <name>
Name of the attribute.
.HP 4
.I <type>
Type of the attribute: \`prefail\` or \`oldage\`.
.HP 4
.I <updated>
Update method of the attribute: \`always\` or \`offline\`.
.HP 4
.I <when_failed>
If and when the attribute failed: \`never\` or \`past\` or \`now\`.
.PD
.RE
.TP

View file

@ -1121,7 +1121,7 @@ Command Smart And Probe Tags
<flags_decimal> - The raw flags value (uint, decimal).
<flags_hex> - The raw flags value (uint, hexadecimal).
=attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>
=attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>:<type>:<updated>:<when_failed>
Logs the raw value of any assigned SMART attribute.
<id> - The SMART attribute ID (uint).
@ -1131,6 +1131,9 @@ Command Smart And Probe Tags
<worst> - The worst value (uint).
<thresh> - The threshold value (uint).
<name> - Name of the attribute.
<type> - Type of the attribute: `prefail` or `oldage`.
<updated> - Update method of the attribute: `always` or `offline`.
<when_failed> - If and when the attribute failed: `never` or `past` or `now`.
=attr:<device_file>:<disk_name>[/<split_index>]:power:active
Logs that the device was confirmed to be in an active power

View file

@ -1167,7 +1167,7 @@ Tags logging specific disk identification and attribute values.
<flags_decimal> - The raw flags value (uint, decimal).
<flags_hex> - The raw flags value (uint, hexadecimal).
attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>
attr:<device_file>:<disk_name>[/<split_index>]:<id>:<raw_decimal>:<raw_hex>:<norm>:<worst>:<thresh>:<name>:<type>:<updated>:<when_failed>
Logs the raw value of any assigned SMART attribute.
<id> - The SMART attribute ID (uint).
@ -1177,6 +1177,9 @@ Tags logging specific disk identification and attribute values.
<worst> - The worst value (uint).
<thresh> - The threshold value (uint).
<name> - Name of the attribute.
<type> - Type of the attribute: `prefail` or `oldage`.
<updated> - Update method of the attribute: `always` or `offline`.
<when_failed> - If and when the attribute failed: `never` or `past` or `now`.
attr:<device_file>:<disk_name>[/<split_index>]:power:active
Logs that the device was confirmed to be in an active power