diff --git a/Makefile.am b/Makefile.am index 1ec1d3f5a..1274de006 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,8 +44,8 @@ if !WITH_NVME DISTCHECK_CONFIGURE_FLAGS += --without-nvme endif -if !WITH_SMART -DISTCHECK_CONFIGURE_FLAGS += --without-smart +if !WITH_SMARTMONTOOLS +DISTCHECK_CONFIGURE_FLAGS += --without-smartmontools endif if !WITH_SWAP @@ -72,7 +72,7 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess config.sub \ configure depcomp install-sh ltmain.sh missing py-compile compile ar-lib \ m4/*.m4 -LIBDIRS = src/utils/.libs:src/plugins/.libs:src/plugins/fs/.libs:src/plugins/nvme/.libs:src/lib/.libs +LIBDIRS = src/utils/.libs:src/plugins/.libs:src/plugins/fs/.libs:src/plugins/nvme/.libs:src/plugins/smart/.libs:src/lib/.libs GIDIR = src/lib if WITH_PYTHON3 diff --git a/configure.ac b/configure.ac index 8c6dddacc..209bef6b3 100644 --- a/configure.ac +++ b/configure.ac @@ -22,6 +22,7 @@ AC_CONFIG_FILES([Makefile src/Makefile \ src/plugins/Makefile \ src/plugins/fs/Makefile \ src/plugins/nvme/Makefile \ + src/plugins/smart/Makefile \ src/utils/Makefile \ src/utils/blockdev-utils.pc \ src/lib/Makefile \ @@ -153,16 +154,21 @@ AS_IF([test "x$with_nvme" != "xno"], [AC_DEFINE([WITH_BD_NVME], [], [Define if nvme is supported]) AC_SUBST([WITH_NVME], [1])], []) -AC_ARG_WITH([smart], - AS_HELP_STRING([--with-smart], [support smart @<:@default=yes@:>@]), +AC_ARG_WITH([smartmontools], + AS_HELP_STRING([--with-smartmontools], [support ATA/SCSI S.M.A.R.T. via smartmontools @<:@default=yes@:>@]), [], - [with_smart=yes]) + [with_smartmontools=yes]) + +AC_SUBST([WITH_SMARTMONTOOLS], [0]) +AM_CONDITIONAL(WITH_SMARTMONTOOLS, test "x$with_smartmontools" != "xno") +AS_IF([test "x$with_smartmontools" != "xno"], + [AC_DEFINE([WITH_BD_SMART], [], [Define if smart is supported]) + AC_SUBST([WITH_SMART], [1]) + AC_SUBST([WITH_SMARTMONTOOLS], [1])], + []) AC_SUBST([WITH_SMART], [0]) -AM_CONDITIONAL(WITH_SMART, test "x$with_smart" != "xno") -AS_IF([test "x$with_smart" != "xno"], - [AC_DEFINE([WITH_BD_SMART], [], [Define if smart is supported]) AC_SUBST([WITH_SMART], [1])], - []) +AM_CONDITIONAL(WITH_SMART, test "x$with_smartmontools" != "xno") LIBBLOCKDEV_PLUGIN([BTRFS], [btrfs]) LIBBLOCKDEV_PLUGIN([CRYPTO], [crypto]) @@ -177,7 +183,7 @@ LIBBLOCKDEV_PLUGIN([PART], [part]) LIBBLOCKDEV_PLUGIN([FS], [fs]) LIBBLOCKDEV_PLUGIN([NVDIMM], [nvdimm]) LIBBLOCKDEV_PLUGIN([NVME], [nvme]) -LIBBLOCKDEV_PLUGIN([SMART], [smart]) +LIBBLOCKDEV_PLUGIN([SMART], [smartmontools]) dnl these packages/modules are always needed LIBBLOCKDEV_PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.42.2]) @@ -318,7 +324,7 @@ echo " NVMe plugin: ${with_nvme} Part plugin: ${with_part} S390 plugin: ${s390_info} - S.M.A.R.T. plugin: ${with_smart} + Smartmontools plugin: ${with_smartmontools} Swap plugin: ${with_swap} GObject introspection: ${found_introspection} diff --git a/data/conf.d/00-default.cfg b/data/conf.d/00-default.cfg index 08f85ccac..fe6e56d3c 100644 --- a/data/conf.d/00-default.cfg +++ b/data/conf.d/00-default.cfg @@ -46,7 +46,7 @@ sonames=libbd_nvme.so.3 sonames=libbd_part.so.3 [smart] -sonames=libbd_smart.so.3 +sonames=libbd_smartmontools.so.3 [swap] sonames=libbd_swap.so.3 diff --git a/include/blockdev/Makefile.am b/include/blockdev/Makefile.am index e6246748a..a26bf60e0 100644 --- a/include/blockdev/Makefile.am +++ b/include/blockdev/Makefile.am @@ -1,6 +1,7 @@ all-local: for header in ${srcdir}/../../src/plugins/*.h; do ln -sf $${header} ./; done for header in ${srcdir}/../../src/plugins/nvme/nvme.h; do ln -sf $${header} ./; done + for header in ${srcdir}/../../src/plugins/smart/smart.h; do ln -sf $${header} ./; done for header in ${srcdir}/../../src/utils/*.h; do ln -sf $${header} ./; done for header in ${srcdir}/../../src/lib/*.h; do ln -sf $${header} ./; done mkdir -p fs; diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in index 2d00036ec..9bebce0f6 100644 --- a/src/lib/blockdev.c.in +++ b/src/lib/blockdev.c.in @@ -63,7 +63,7 @@ static gchar * default_plugin_so[BD_PLUGIN_UNDEF] = { "libbd_dm.so.@MAJOR_VER@", "libbd_mdraid.so.@MAJOR_VER@", "libbd_s390.so.@MAJOR_VER@", "libbd_part.so.@MAJOR_VER@", "libbd_fs.so.@MAJOR_VER@", "libbd_nvdimm.so.@MAJOR_VER@", - "libbd_nvme.so.@MAJOR_VER@", "libbd_smart.so.@MAJOR_VER@", + "libbd_nvme.so.@MAJOR_VER@", "libbd_smartmontools.so.@MAJOR_VER@", }; static BDPluginStatus plugins[BD_PLUGIN_UNDEF] = { {{BD_PLUGIN_LVM, NULL}, NULL}, diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 1c3c26a26..99ac08abe 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -8,6 +8,10 @@ if WITH_NVME SUBDIRS += nvme endif +if WITH_SMART +SUBDIRS += smart +endif + lib_LTLIBRARIES = if WITH_BTRFS @@ -46,10 +50,6 @@ if WITH_NVDIMM lib_LTLIBRARIES += libbd_nvdimm.la endif -if WITH_SMART -lib_LTLIBRARIES += libbd_smart.la -endif - if WITH_SWAP lib_LTLIBRARIES += libbd_swap.la endif @@ -140,14 +140,6 @@ libbd_nvdimm_la_CPPFLAGS = -I${builddir}/../../include/ libbd_nvdimm_la_SOURCES = nvdimm.c nvdimm.h check_deps.c check_deps.h endif -if WITH_SMART -libbd_smart_la_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(JSON_GLIB_CFLAGS) -Wall -Wextra -Werror -libbd_smart_la_LIBADD = ${builddir}/../utils/libbd_utils.la $(GLIB_LIBS) $(GIO_LIBS) $(JSON_GLIB_LIBS) -libbd_smart_la_LDFLAGS = -L${srcdir}/../utils/ -version-info 3:0:0 -Wl,--no-undefined -libbd_smart_la_CPPFLAGS = -I${builddir}/../../include/ -libbd_smart_la_SOURCES = smart.c smart.h check_deps.c check_deps.h -endif - if WITH_SWAP libbd_swap_la_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(BLKID_CFLAGS) $(UUID_CFLAGS) -Wall -Wextra -Werror libbd_swap_la_LIBADD = ${builddir}/../utils/libbd_utils.la $(GLIB_LIBS) $(GIO_LIBS) $(BLKID_LIBS) $(UUID_LIBS) @@ -208,10 +200,6 @@ if WITH_NVDIMM libinclude_HEADERS += nvdimm.h endif -if WITH_SMART -libinclude_HEADERS += smart.h -endif - if WITH_SWAP libinclude_HEADERS += swap.h endif diff --git a/src/plugins/smart/Makefile.am b/src/plugins/smart/Makefile.am new file mode 100644 index 000000000..f432afdb5 --- /dev/null +++ b/src/plugins/smart/Makefile.am @@ -0,0 +1,29 @@ +AUTOMAKE_OPTIONS = subdir-objects + +lib_LTLIBRARIES = + + +if WITH_SMART +libincludedir = $(includedir)/blockdev +libinclude_HEADERS = smart.h +endif + + +if WITH_SMARTMONTOOLS + +lib_LTLIBRARIES += libbd_smartmontools.la + +libbd_smartmontools_la_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(JSON_GLIB_CFLAGS) -Wall -Wextra -Werror +libbd_smartmontools_la_LIBADD = ${builddir}/../../utils/libbd_utils.la $(GLIB_LIBS) $(GIO_LIBS) $(JSON_GLIB_LIBS) +libbd_smartmontools_la_LDFLAGS = -L${srcdir}/../../utils/ -version-info 3:0:0 -Wl,--no-undefined -export-symbols-regex '^bd_.*' +libbd_smartmontools_la_CPPFLAGS = -I${builddir}/../../../include/ -I${srcdir}/../ -I. -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" + +libbd_smartmontools_la_SOURCES = \ + smart.h \ + smart-private.h \ + smart-common.c \ + smartmontools.c \ + ../check_deps.c \ + ../check_deps.h + +endif diff --git a/src/plugins/smart/smart-common.c b/src/plugins/smart/smart-common.c new file mode 100644 index 000000000..f849cb962 --- /dev/null +++ b/src/plugins/smart/smart-common.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2014-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Tomas Bzatek + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "smart.h" +#include "smart-private.h" + + +/** + * bd_smart_error_quark: (skip) + */ +GQuark bd_smart_error_quark (void) +{ + return g_quark_from_static_string ("g-bd-smart-error-quark"); +} + +/** + * bd_smart_ata_attribute_free: (skip) + * @attr: (nullable): %BDSmartATAAttribute to free + * + * Frees @attr. + */ +void bd_smart_ata_attribute_free (BDSmartATAAttribute *attr) { + if (attr == NULL) + return; + g_free (attr->name); + g_free (attr->well_known_name); + g_free (attr->pretty_value_string); + g_free (attr); +} + +/** + * bd_smart_ata_attribute_copy: (skip) + * @attr: (nullable): %BDSmartATAAttribute to copy + * + * Creates a new copy of @attr. + */ +BDSmartATAAttribute * bd_smart_ata_attribute_copy (BDSmartATAAttribute *attr) { + BDSmartATAAttribute *new_attr; + + if (attr == NULL) + return NULL; + + new_attr = g_new0 (BDSmartATAAttribute, 1); + memcpy (new_attr, attr, sizeof (BDSmartATAAttribute)); + new_attr->name = g_strdup (attr->name); + new_attr->well_known_name = g_strdup (attr->well_known_name); + new_attr->pretty_value_string = g_strdup (attr->pretty_value_string); + + return new_attr; +} + +/** + * bd_smart_ata_free: (skip) + * @data: (nullable): %BDSmartATA to free + * + * Frees @data. + */ +void bd_smart_ata_free (BDSmartATA *data) { + BDSmartATAAttribute **attr; + + if (data == NULL) + return; + + for (attr = data->attributes; attr && *attr; attr++) + bd_smart_ata_attribute_free (*attr); + g_free (data->attributes); + g_free (data); +} + +/** + * bd_smart_ata_copy: (skip) + * @data: (nullable): %BDSmartATA to copy + * + * Creates a new copy of @data. + */ +BDSmartATA * bd_smart_ata_copy (BDSmartATA *data) { + BDSmartATA *new_data; + BDSmartATAAttribute **attr; + GPtrArray *ptr_array; + + if (data == NULL) + return NULL; + + new_data = g_new0 (BDSmartATA, 1); + memcpy (new_data, data, sizeof (BDSmartATA)); + + ptr_array = g_ptr_array_new (); + for (attr = data->attributes; attr && *attr; attr++) + g_ptr_array_add (ptr_array, bd_smart_ata_attribute_copy (*attr)); + g_ptr_array_add (ptr_array, NULL); + new_data->attributes = (BDSmartATAAttribute **) g_ptr_array_free (ptr_array, FALSE); + + return new_data; +} + +/** + * bd_smart_scsi_free: (skip) + * @data: (nullable): %BDSmartSCSI to free + * + * Frees @data. + */ +void bd_smart_scsi_free (BDSmartSCSI *data) { + if (data == NULL) + return; + + g_free (data->scsi_ie_string); + g_free (data); +} + +/** + * bd_smart_scsi_copy: (skip) + * @data: (nullable): %BDSmartSCSI to copy + * + * Creates a new copy of @data. + */ +BDSmartSCSI * bd_smart_scsi_copy (BDSmartSCSI *data) { + BDSmartSCSI *new_data; + + if (data == NULL) + return NULL; + + new_data = g_new0 (BDSmartSCSI, 1); + memcpy (new_data, data, sizeof (BDSmartSCSI)); + new_data->scsi_ie_string = g_strdup (data->scsi_ie_string); + + return new_data; +} diff --git a/src/plugins/smart/smart-private.h b/src/plugins/smart/smart-private.h new file mode 100644 index 000000000..764c6d6e6 --- /dev/null +++ b/src/plugins/smart/smart-private.h @@ -0,0 +1,100 @@ +#include +#include +#include + +#include "smart.h" + +#ifndef BD_SMART_PRIVATE +#define BD_SMART_PRIVATE + +/* TODO: move to a common libblockdev header */ +#ifdef __clang__ +#define ZERO_INIT {} +#else +#define ZERO_INIT {0} +#endif + +/* "C" locale to get the locale-agnostic error messages */ +#define _C_LOCALE (locale_t) 0 + + +struct WellKnownAttrInfo { + const gchar *libatasmart_name; + BDSmartATAAttributeUnit unit; + const gchar *smartmontools_names[7]; /* NULL-terminated */ +}; + +/* This table was stolen from libatasmart, including the comment below: */ +/* This data is stolen from smartmontools */ +static const struct WellKnownAttrInfo well_known_attrs[256] = { + [1] = { "raw-read-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Raw_Read_Error_Count", "Raw_Read_Error_Rate", NULL }}, + [2] = { "throughput-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Throughput_Performance", NULL }}, + [3] = { "spin-up-time", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Spin_Up_Time", NULL }}, + [4] = { "start-stop-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Start_Stop_Count", NULL }}, + [5] = { "reallocated-sector-count", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Reallocated_Block_Count", "Reallocated_Sector_Ct", NULL }}, + [6] = { "read-channel-margin", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Read_Channel_Margin", NULL }}, + [7] = { "seek-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Seek_Error_Rate", NULL }}, + [8] = { "seek-time-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Seek_Time_Performance", NULL }}, + [9] = { "power-on-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Power_On_Hours", "Power_On_Hours_and_Msec", NULL }}, + [10] = { "spin-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Spin_Retry_Count", NULL }}, + [11] = { "calibration-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Calibration_Retry_Count", NULL }}, + [12] = { "power-cycle-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power_Cycle_Count", "Device_Power_Cycle_Cnt", NULL }}, + [13] = { "read-soft-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Read_Soft_Error_Rate", NULL }}, + [170] = { "available-reserved-space", BD_SMART_ATA_ATTRIBUTE_UNIT_PERCENT, { "Available_Reservd_Space", "Reserved_Block_Pct", NULL }}, + [171] = { "program-fail-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Cnt", "Program_Fail_Count", "Program_Fail_Ct", NULL }}, + [172] = { "erase-fail-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Cnt", "Erase_Fail_Ct", "Erase_Fail_Count", "Block_Erase_Failure", NULL }}, + [175] = { "program-fail-count-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Count_Chip", NULL }}, + [176] = { "erase-fail-count-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Count_Chip", NULL }}, + [177] = { "wear-leveling-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Wear_Leveling_Count", NULL }}, + [178] = { "used-reserved-blocks-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Used_Rsvd_Blk_Cnt_Chip", "Used_Rsrvd_Blk_Cnt_Wrst", NULL }}, + [179] = { "used-reserved-blocks-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Used_Rsvd_Blk_Cnt_Tot", "Used_Rsrvd_Blk_Cnt_Tot", NULL }}, + [180] = { "unused-reserved-blocks", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Unused_Rsvd_Blk_Cnt_Tot", NULL }}, + [181] = { "program-fail-count-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Cnt_Total", NULL }}, + [182] = { "erase-fail-count-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Count_Total", NULL }}, + [183] = { "runtime-bad-block-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Runtime_Bad_Block", NULL }}, + [184] = { "end-to-end-error", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "End-to-End_Error", "End-to-End_Error_Count", NULL }}, + [187] = { "reported-uncorrect", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Reported_Uncorrect", "Reported_UE_Counts", NULL }}, + [188] = { "command-timeout", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Command_Timeout", "Command_Timeouts", NULL }}, + [189] = { "high-fly-writes", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "High_Fly_Writes", NULL }}, + [190] = { "airflow-temperature-celsius", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Airflow_Temperature_Cel", "Case_Temperature", "Drive_Temperature", "Temperature_Case", "Drive_Temp_Warning", "Temperature_Celsius", NULL }}, + [191] = { "g-sense-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "G-Sense_Error_Rate", NULL }}, + [192] = { "power-off-retract-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power-Off_Retract_Count", "Power-off_Retract_Count", NULL }}, + [193] = { "load-cycle-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Cycle_Count", NULL }}, + [194] = { "temperature-celsius-2", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Temperature_Celsius", "Device_Temperature", "Drive_Temperature", "Temperature_Internal", NULL }}, + [195] = { "hardware-ecc-recovered", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Hardware_ECC_Recovered", "Cumulativ_Corrected_ECC", "ECC_Error_Rate", NULL }}, + [196] = { "reallocated-event-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Reallocated_Event_Count", NULL }}, + [197] = { "current-pending-sector", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Current_Pending_Sector", "Pending_Sector_Count", NULL }}, + [198] = { "offline-uncorrectable", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Offline_Uncorrectable", "Uncor_Read_Error_Ct", "Uncorrectable_Sector_Ct", NULL }}, + [199] = { "udma-crc-error-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "CRC_Error_Count", "SATA_CRC_Error", "SATA_CRC_Error_Count", "UDMA_CRC_Error_Count", NULL }}, + [200] = { "multi-zone-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Multi_Zone_Error_Rate", NULL }}, + [201] = { "soft-read-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Soft_Read_Error_Rate", "Read_Error_Rate", "Uncorr_Soft_Read_Err_Rt", "Unc_Read_Error_Rate", "Unc_Soft_Read_Err_Rate", NULL }}, + [202] = { "ta-increase-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Data_Address_Mark_Errs", NULL }}, + [203] = { "run-out-cancel", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Run_Out_Cancel", NULL }}, + [204] = { "shock-count-write-open", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Soft_ECC_Correction", "Soft_ECC_Correction_Rt", "Soft_ECC_Correct_Rate", NULL }}, + [205] = { "shock-rate-write-open", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Thermal_Asperity_Rate", NULL }}, + [206] = { "flying-height", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Flying_Height", NULL }}, + [207] = { "spin-high-current", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Spin_High_Current", NULL }}, + [208] = { "spin-buzz", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Spin_Buzz", NULL }}, + [209] = { "offline-seek-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Offline_Seek_Performnce", NULL }}, + [220] = { "disk-shift", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Disk_Shift", NULL }}, + [221] = { "g-sense-error-rate-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "G-Sense_Error_Rate", NULL }}, + [222] = { "loaded-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Loaded_Hours", NULL }}, + [223] = { "load-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Retry_Count", NULL }}, + [224] = { "load-friction", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Load_Friction", NULL }}, + [225] = { "load-cycle-count-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Cycle_Count", NULL }}, + [226] = { "load-in-time", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Load-in_Time", NULL }}, + [227] = { "torq-amp-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Torq-amp_Count", NULL }}, + [228] = { "power-off-retract-count-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power-Off_Retract_Count", "Power-off_Retract_Count", NULL }}, + [230] = { "head-amplitude", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Head_Amplitude", NULL }}, + [231] = { "temperature-celsius", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Temperature_Celsius", "Controller_Temperature", NULL }}, + [232] = { "endurance-remaining", BD_SMART_ATA_ATTRIBUTE_UNIT_PERCENT, { "Spares_Remaining_Perc", "Perc_Avail_Resrvd_Space", NULL }}, + [233] = { "power-on-seconds-2", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { /* TODO */ NULL }}, + [234] = { "uncorrectable-ecc-count", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { /* TODO */ NULL }}, + [235] = { "good-block-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Good/Sys_Block_Count", NULL }}, + [240] = { "head-flying-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Head_Flying_Hours", NULL }}, + [241] = { "total-lbas-written", BD_SMART_ATA_ATTRIBUTE_UNIT_MB, { /* TODO: implement size calculation logic */ NULL }}, + [242] = { "total-lbas-read", BD_SMART_ATA_ATTRIBUTE_UNIT_MB, { /* TODO: implement size calculation logic */ NULL }}, + [250] = { "read-error-retry-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Read_Error_Retry_Rate", "Read_Retry_Count", NULL }}, +}; + +#endif /* BD_SMART_PRIVATE */ diff --git a/src/plugins/smart.h b/src/plugins/smart/smart.h similarity index 100% rename from src/plugins/smart.h rename to src/plugins/smart/smart.h diff --git a/src/plugins/smart.c b/src/plugins/smart/smartmontools.c similarity index 81% rename from src/plugins/smart.c rename to src/plugins/smart/smartmontools.c index 2d4436d86..59ccdb25d 100644 --- a/src/plugins/smart.c +++ b/src/plugins/smart/smartmontools.c @@ -28,7 +28,9 @@ #include #include + #include "smart.h" +#include "smart-private.h" /** * SECTION: smart @@ -41,14 +43,6 @@ #define SMARTCTL_MIN_VERSION "7.0" -/** - * bd_smart_error_quark: (skip) - */ -GQuark bd_smart_error_quark (void) -{ - return g_quark_from_static_string ("g-bd-smart-error-quark"); -} - static volatile guint avail_deps = 0; static GMutex deps_check_lock; @@ -128,119 +122,6 @@ gboolean bd_smart_is_tech_avail (G_GNUC_UNUSED BDSmartTech tech, G_GNUC_UNUSED g } -/** - * bd_smart_ata_attribute_free: (skip) - * @attr: (nullable): %BDSmartATAAttribute to free - * - * Frees @attr. - */ -void bd_smart_ata_attribute_free (BDSmartATAAttribute *attr) { - if (attr == NULL) - return; - g_free (attr->name); - g_free (attr->well_known_name); - g_free (attr->pretty_value_string); - g_free (attr); -} - -/** - * bd_smart_ata_attribute_copy: (skip) - * @attr: (nullable): %BDSmartATAAttribute to copy - * - * Creates a new copy of @attr. - */ -BDSmartATAAttribute * bd_smart_ata_attribute_copy (BDSmartATAAttribute *attr) { - BDSmartATAAttribute *new_attr; - - if (attr == NULL) - return NULL; - - new_attr = g_new0 (BDSmartATAAttribute, 1); - memcpy (new_attr, attr, sizeof (BDSmartATAAttribute)); - new_attr->name = g_strdup (attr->name); - new_attr->well_known_name = g_strdup (attr->well_known_name); - new_attr->pretty_value_string = g_strdup (attr->pretty_value_string); - - return new_attr; -} - -/** - * bd_smart_ata_free: (skip) - * @data: (nullable): %BDSmartATA to free - * - * Frees @data. - */ -void bd_smart_ata_free (BDSmartATA *data) { - BDSmartATAAttribute **attr; - - if (data == NULL) - return; - - for (attr = data->attributes; attr && *attr; attr++) - bd_smart_ata_attribute_free (*attr); - g_free (data->attributes); - g_free (data); -} - -/** - * bd_smart_ata_copy: (skip) - * @data: (nullable): %BDSmartATA to copy - * - * Creates a new copy of @data. - */ -BDSmartATA * bd_smart_ata_copy (BDSmartATA *data) { - BDSmartATA *new_data; - BDSmartATAAttribute **attr; - GPtrArray *ptr_array; - - if (data == NULL) - return NULL; - - new_data = g_new0 (BDSmartATA, 1); - memcpy (new_data, data, sizeof (BDSmartATA)); - - ptr_array = g_ptr_array_new (); - for (attr = data->attributes; attr && *attr; attr++) - g_ptr_array_add (ptr_array, bd_smart_ata_attribute_copy (*attr)); - g_ptr_array_add (ptr_array, NULL); - new_data->attributes = (BDSmartATAAttribute **) g_ptr_array_free (ptr_array, FALSE); - - return new_data; -} - -/** - * bd_smart_scsi_free: (skip) - * @data: (nullable): %BDSmartSCSI to free - * - * Frees @data. - */ -void bd_smart_scsi_free (BDSmartSCSI *data) { - if (data == NULL) - return; - - g_free (data->scsi_ie_string); - g_free (data); -} - -/** - * bd_smart_scsi_copy: (skip) - * @data: (nullable): %BDSmartSCSI to copy - * - * Creates a new copy of @data. - */ -BDSmartSCSI * bd_smart_scsi_copy (BDSmartSCSI *data) { - BDSmartSCSI *new_data; - - if (data == NULL) - return NULL; - - new_data = g_new0 (BDSmartSCSI, 1); - memcpy (new_data, data, sizeof (BDSmartSCSI)); - new_data->scsi_ie_string = g_strdup (data->scsi_ie_string); - - return new_data; -} - static const gchar * get_error_message_from_exit_code (gint exit_code) { /* @@ -258,86 +139,6 @@ static const gchar * get_error_message_from_exit_code (gint exit_code) { return NULL; } - -struct WellKnownAttrInfo { - const gchar *libatasmart_name; - BDSmartATAAttributeUnit unit; - const gchar *smartmontools_names[7]; /* NULL-terminated */ -}; - -/* This table was stolen from libatasmart, including the comment below: */ -/* This data is stolen from smartmontools */ -static const struct WellKnownAttrInfo well_known_attrs[256] = { - [1] = { "raw-read-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Raw_Read_Error_Count", "Raw_Read_Error_Rate", NULL }}, - [2] = { "throughput-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Throughput_Performance", NULL }}, - [3] = { "spin-up-time", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Spin_Up_Time", NULL }}, - [4] = { "start-stop-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Start_Stop_Count", NULL }}, - [5] = { "reallocated-sector-count", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Reallocated_Block_Count", "Reallocated_Sector_Ct", NULL }}, - [6] = { "read-channel-margin", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Read_Channel_Margin", NULL }}, - [7] = { "seek-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Seek_Error_Rate", NULL }}, - [8] = { "seek-time-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Seek_Time_Performance", NULL }}, - [9] = { "power-on-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Power_On_Hours", "Power_On_Hours_and_Msec", NULL }}, - [10] = { "spin-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Spin_Retry_Count", NULL }}, - [11] = { "calibration-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Calibration_Retry_Count", NULL }}, - [12] = { "power-cycle-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power_Cycle_Count", "Device_Power_Cycle_Cnt", NULL }}, - [13] = { "read-soft-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Read_Soft_Error_Rate", NULL }}, - [170] = { "available-reserved-space", BD_SMART_ATA_ATTRIBUTE_UNIT_PERCENT, { "Available_Reservd_Space", "Reserved_Block_Pct", NULL }}, - [171] = { "program-fail-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Cnt", "Program_Fail_Count", "Program_Fail_Ct", NULL }}, - [172] = { "erase-fail-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Cnt", "Erase_Fail_Ct", "Erase_Fail_Count", "Block_Erase_Failure", NULL }}, - [175] = { "program-fail-count-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Count_Chip", NULL }}, - [176] = { "erase-fail-count-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Count_Chip", NULL }}, - [177] = { "wear-leveling-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Wear_Leveling_Count", NULL }}, - [178] = { "used-reserved-blocks-chip", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Used_Rsvd_Blk_Cnt_Chip", "Used_Rsrvd_Blk_Cnt_Wrst", NULL }}, - [179] = { "used-reserved-blocks-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Used_Rsvd_Blk_Cnt_Tot", "Used_Rsrvd_Blk_Cnt_Tot", NULL }}, - [180] = { "unused-reserved-blocks", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Unused_Rsvd_Blk_Cnt_Tot", NULL }}, - [181] = { "program-fail-count-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Program_Fail_Cnt_Total", NULL }}, - [182] = { "erase-fail-count-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Erase_Fail_Count_Total", NULL }}, - [183] = { "runtime-bad-block-total", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Runtime_Bad_Block", NULL }}, - [184] = { "end-to-end-error", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "End-to-End_Error", "End-to-End_Error_Count", NULL }}, - [187] = { "reported-uncorrect", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Reported_Uncorrect", "Reported_UE_Counts", NULL }}, - [188] = { "command-timeout", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Command_Timeout", "Command_Timeouts", NULL }}, - [189] = { "high-fly-writes", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "High_Fly_Writes", NULL }}, - [190] = { "airflow-temperature-celsius", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Airflow_Temperature_Cel", "Case_Temperature", "Drive_Temperature", "Temperature_Case", "Drive_Temp_Warning", "Temperature_Celsius", NULL }}, - [191] = { "g-sense-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "G-Sense_Error_Rate", NULL }}, - [192] = { "power-off-retract-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power-Off_Retract_Count", "Power-off_Retract_Count", NULL }}, - [193] = { "load-cycle-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Cycle_Count", NULL }}, - [194] = { "temperature-celsius-2", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Temperature_Celsius", "Device_Temperature", "Drive_Temperature", "Temperature_Internal", NULL }}, - [195] = { "hardware-ecc-recovered", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Hardware_ECC_Recovered", "Cumulativ_Corrected_ECC", "ECC_Error_Rate", NULL }}, - [196] = { "reallocated-event-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Reallocated_Event_Count", NULL }}, - [197] = { "current-pending-sector", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Current_Pending_Sector", "Pending_Sector_Count", NULL }}, - [198] = { "offline-uncorrectable", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { "Offline_Uncorrectable", "Uncor_Read_Error_Ct", "Uncorrectable_Sector_Ct", NULL }}, - [199] = { "udma-crc-error-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "CRC_Error_Count", "SATA_CRC_Error", "SATA_CRC_Error_Count", "UDMA_CRC_Error_Count", NULL }}, - [200] = { "multi-zone-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Multi_Zone_Error_Rate", NULL }}, - [201] = { "soft-read-error-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Soft_Read_Error_Rate", "Read_Error_Rate", "Uncorr_Soft_Read_Err_Rt", "Unc_Read_Error_Rate", "Unc_Soft_Read_Err_Rate", NULL }}, - [202] = { "ta-increase-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Data_Address_Mark_Errs", NULL }}, - [203] = { "run-out-cancel", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Run_Out_Cancel", NULL }}, - [204] = { "shock-count-write-open", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Soft_ECC_Correction", "Soft_ECC_Correction_Rt", "Soft_ECC_Correct_Rate", NULL }}, - [205] = { "shock-rate-write-open", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Thermal_Asperity_Rate", NULL }}, - [206] = { "flying-height", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Flying_Height", NULL }}, - [207] = { "spin-high-current", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Spin_High_Current", NULL }}, - [208] = { "spin-buzz", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Spin_Buzz", NULL }}, - [209] = { "offline-seek-performance", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Offline_Seek_Performnce", NULL }}, - [220] = { "disk-shift", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Disk_Shift", NULL }}, - [221] = { "g-sense-error-rate-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "G-Sense_Error_Rate", NULL }}, - [222] = { "loaded-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Loaded_Hours", NULL }}, - [223] = { "load-retry-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Retry_Count", NULL }}, - [224] = { "load-friction", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Load_Friction", NULL }}, - [225] = { "load-cycle-count-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Load_Cycle_Count", NULL }}, - [226] = { "load-in-time", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Load-in_Time", NULL }}, - [227] = { "torq-amp-count", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Torq-amp_Count", NULL }}, - [228] = { "power-off-retract-count-2", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Power-Off_Retract_Count", "Power-off_Retract_Count", NULL }}, - [230] = { "head-amplitude", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Head_Amplitude", NULL }}, - [231] = { "temperature-celsius", BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN, { "Temperature_Celsius", "Controller_Temperature", NULL }}, - [232] = { "endurance-remaining", BD_SMART_ATA_ATTRIBUTE_UNIT_PERCENT, { "Spares_Remaining_Perc", "Perc_Avail_Resrvd_Space", NULL }}, - [233] = { "power-on-seconds-2", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { /* TODO */ NULL }}, - [234] = { "uncorrectable-ecc-count", BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS, { /* TODO */ NULL }}, - [235] = { "good-block-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN, { "Good/Sys_Block_Count", NULL }}, - [240] = { "head-flying-hours", BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS, { "Head_Flying_Hours", NULL }}, - [241] = { "total-lbas-written", BD_SMART_ATA_ATTRIBUTE_UNIT_MB, { /* TODO: implement size calculation logic */ NULL }}, - [242] = { "total-lbas-read", BD_SMART_ATA_ATTRIBUTE_UNIT_MB, { /* TODO: implement size calculation logic */ NULL }}, - [250] = { "read-error-retry-rate", BD_SMART_ATA_ATTRIBUTE_UNIT_NONE, { "Read_Error_Retry_Rate", "Read_Retry_Count", NULL }}, -}; - static void lookup_well_known_attr (BDSmartATAAttribute *a, gchar **well_known_name, diff --git a/tests/run_tests.py b/tests/run_tests.py index dbceb2aff..b1e5c3987 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -17,7 +17,7 @@ from utils import TestTags, get_version -LIBDIRS = 'src/utils/.libs:src/plugins/.libs:src/plugins/fs/.libs:src/lib/.libs:src/plugins/nvme/.libs' +LIBDIRS = 'src/utils/.libs:src/plugins/.libs:src/plugins/fs/.libs:src/lib/.libs:src/plugins/nvme/.libs:src/plugins/smart/.libs' GIDIR = 'src/lib' SKIP_CONFIG = 'skip.yml' diff --git a/tests/smart_test.py b/tests/smart_test.py index 0f9b81a65..d5ccd2669 100644 --- a/tests/smart_test.py +++ b/tests/smart_test.py @@ -15,7 +15,7 @@ class SMARTTest(unittest.TestCase): @tag_test(TestTags.NOSTORAGE) def test_plugin_version(self): - self.assertEqual(BlockDev.get_plugin_soname(BlockDev.Plugin.SMART), "libbd_smart.so.3") + self.assertEqual(BlockDev.get_plugin_soname(BlockDev.Plugin.SMART), "libbd_smartmontools.so.3") @classmethod def setUpClass(cls):