LCOV - code coverage report
Current view: top level - plugins/smart - libatasmart.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 73.9 % 295 218
Test Date: 2026-01-26 13:19:28 Functions: 91.7 % 12 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2014-2024 Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Tomas Bzatek <tbzatek@redhat.com>
      18              :  */
      19              : 
      20              : #include <glib.h>
      21              : #include <string.h>
      22              : #include <stdio.h>
      23              : #include <unistd.h>
      24              : #include <errno.h>
      25              : 
      26              : #include <atasmart.h>
      27              : 
      28              : #include <blockdev/utils.h>
      29              : #include <check_deps.h>
      30              : 
      31              : #include "smart.h"
      32              : #include "smart-private.h"
      33              : 
      34              : /**
      35              :  * bd_smart_check_deps:
      36              :  *
      37              :  * Returns: whether the plugin's runtime dependencies are satisfied or not
      38              :  *
      39              :  * Function checking plugin's runtime dependencies.
      40              :  *
      41              :  * Deprecated: 3.5: use %bd_smart_is_tech_avail instead
      42              :  */
      43            0 : gboolean bd_smart_check_deps (void) {
      44            0 :     return TRUE;
      45              : }
      46              : 
      47              : /**
      48              :  * bd_smart_is_tech_avail:
      49              :  * @tech: the queried tech
      50              :  * @mode: a bit mask of queried modes of operation (#BDSmartTechMode) for @tech
      51              :  * @error: (out) (nullable): place to store error (details about why the @tech-@mode combination is not available)
      52              :  *
      53              :  * Returns: whether the @tech-@mode combination is available -- supported by the
      54              :  *          plugin implementation and having all the runtime dependencies available
      55              :  */
      56            2 : gboolean bd_smart_is_tech_avail (BDSmartTech tech, G_GNUC_UNUSED guint64 mode, GError **error) {
      57            2 :     switch (tech) {
      58            1 :         case BD_SMART_TECH_ATA:
      59            1 :             return TRUE;
      60            1 :         case BD_SMART_TECH_SCSI:
      61            1 :             g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_TECH_UNAVAIL, "SCSI SMART is unavailable with libatasmart");
      62            1 :             return FALSE;
      63            0 :         default:
      64            0 :             g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_TECH_UNAVAIL, "Unknown technology");
      65            0 :             return FALSE;
      66              :     }
      67              : }
      68              : 
      69              : /* copied from libatasmart/atasmart.c (a non-public symbol) */
      70          248 : static gchar *print_value (uint64_t pretty_value, SkSmartAttributeUnit pretty_unit) {
      71          248 :     switch (pretty_unit) {
      72           18 :         case SK_SMART_ATTRIBUTE_UNIT_MSECONDS:
      73           18 :             if (pretty_value >= 1000LLU*60LLU*60LLU*24LLU*365LLU)
      74            5 :                 return g_strdup_printf ("%0.1f years", ((double) pretty_value)/(1000.0*60*60*24*365));
      75           13 :             if (pretty_value >= 1000LLU*60LLU*60LLU*24LLU*30LLU)
      76            6 :                 return g_strdup_printf ("%0.1f months", ((double) pretty_value)/(1000.0*60*60*24*30));
      77            7 :             if (pretty_value >= 1000LLU*60LLU*60LLU*24LLU)
      78            2 :                 return g_strdup_printf ("%0.1f days", ((double) pretty_value)/(1000.0*60*60*24));
      79            5 :             if (pretty_value >= 1000LLU*60LLU*60LLU)
      80            0 :                 return g_strdup_printf ("%0.1f h", ((double) pretty_value)/(1000.0*60*60));
      81            5 :             if (pretty_value >= 1000LLU*60LLU)
      82            0 :                 return g_strdup_printf ("%0.1f min", ((double) pretty_value)/(1000.0*60));
      83            5 :             if (pretty_value >= 1000LLU)
      84            3 :                 return g_strdup_printf ("%0.1f s", ((double) pretty_value)/(1000.0));
      85              :             else
      86            2 :                 return g_strdup_printf ("%llu ms", (unsigned long long) pretty_value);
      87              :             break;
      88           19 :         case SK_SMART_ATTRIBUTE_UNIT_MKELVIN:
      89           19 :             return g_strdup_printf ("%0.1f C", ((double) pretty_value - 273150) / 1000);
      90              :             break;
      91           24 :         case SK_SMART_ATTRIBUTE_UNIT_SECTORS:
      92           24 :             return g_strdup_printf ("%llu sectors", (unsigned long long) pretty_value);
      93              :             break;
      94            6 :         case SK_SMART_ATTRIBUTE_UNIT_PERCENT:
      95            6 :             return g_strdup_printf ("%llu%%", (unsigned long long) pretty_value);
      96              :             break;
      97            0 :         case SK_SMART_ATTRIBUTE_UNIT_SMALL_PERCENT:
      98            0 :             return g_strdup_printf ("%0.3f%%", (double) pretty_value);
      99              :             break;
     100            9 :         case SK_SMART_ATTRIBUTE_UNIT_MB:
     101            9 :             if (pretty_value >= 1000000LLU)
     102            2 :                 return g_strdup_printf ("%0.3f TB",  (double) pretty_value / 1000000LLU);
     103            7 :             if (pretty_value >= 1000LLU)
     104            7 :                 return g_strdup_printf ("%0.3f GB",  (double) pretty_value / 1000LLU);
     105              :             else
     106            0 :                 return g_strdup_printf ("%llu MB", (unsigned long long) pretty_value);
     107              :             break;
     108          106 :         case SK_SMART_ATTRIBUTE_UNIT_NONE:
     109          106 :             return g_strdup_printf ("%llu", (unsigned long long) pretty_value);
     110              :             break;
     111           66 :         case SK_SMART_ATTRIBUTE_UNIT_UNKNOWN:
     112           66 :             return g_strdup_printf ("n/a");
     113              :             break;
     114            0 :         case _SK_SMART_ATTRIBUTE_UNIT_MAX:
     115            0 :             g_warn_if_reached ();
     116            0 :             return NULL;
     117              :     }
     118            0 :     return NULL;
     119              : }
     120              : 
     121              : struct ParseTempData {
     122              :   guint attr_id;
     123              :   guint64 value;
     124              :   DriveDBAttr **drivedb_attrs;
     125              : };
     126              : 
     127          265 : static void parse_temp_attr_cb (G_GNUC_UNUSED SkDisk             *d,
     128              :                                 const SkSmartAttributeParsedData *a,
     129              :                                 void                             *user_data) {
     130          265 :     struct ParseTempData *data = user_data;
     131              : 
     132          265 :     if (a->id != data->attr_id)
     133          253 :         return;
     134           12 :     if ((data->attr_id == 194 || data->attr_id == 190) &&
     135           12 :         a->pretty_unit != SK_SMART_ATTRIBUTE_UNIT_MKELVIN)
     136            0 :         return;
     137              :     /* TODO: Validate against drivedb when we have backwards mapping
     138              :      *       from smartmontools attribute names back to libatasmart names.
     139              :      *       At this point the well_known_attrs[] table serves only
     140              :      *       for forward validation.
     141              :      */
     142           12 :     data->value = a->pretty_value;
     143              : }
     144              : 
     145           13 : static guint64 calculate_temperature(SkDisk *d, DriveDBAttr **drivedb_attrs) {
     146           13 :     const guint temp_attrs[2] = {194, 190, /* 9, 220 */ };   /* as defined in smartmontools/atacmds.cpp:ata_return_temperature_value() */
     147              :     unsigned long int i;
     148              : 
     149           15 :     for (i = 0; i < G_N_ELEMENTS (temp_attrs); i++) {
     150           14 :         struct ParseTempData parse_data = {
     151           14 :             .attr_id = temp_attrs[i],
     152              :             .drivedb_attrs = drivedb_attrs,
     153              :             .value = 0,
     154              :         };
     155              : 
     156           14 :         if (sk_disk_smart_parse_attributes (d, parse_temp_attr_cb, &parse_data) != 0)
     157            0 :             break;
     158           14 :         if (parse_data.value != 0)
     159           12 :             return parse_data.value;
     160              :     }
     161            1 :     return 0;
     162              : }
     163              : 
     164              : struct ParseData {
     165              :   GPtrArray *ptr_array;
     166              :   const SkIdentifyParsedData *identify_data;
     167              :   DriveDBAttr **drivedb_attrs;
     168              : };
     169              : 
     170          248 : static void parse_attr_cb (G_GNUC_UNUSED SkDisk             *d,
     171              :                            const SkSmartAttributeParsedData *a,
     172              :                            void                             *user_data) {
     173          248 :     struct ParseData *data = user_data;
     174              :     BDSmartATAAttribute *attr;
     175              : 
     176          248 :     attr = g_new0 (BDSmartATAAttribute, 1);
     177          248 :     attr->id = a->id;
     178          248 :     attr->name = g_strdup (a->name);
     179          248 :     attr->well_known_name = g_strdup (a->name);
     180          248 :     attr->value = a->current_value_valid ? a->current_value : -1;
     181          248 :     attr->worst = a->worst_value_valid ? a->worst_value : -1;
     182          248 :     attr->threshold = a->threshold_valid ? a->threshold : -1;
     183          248 :     attr->failed_past = attr->worst > 0 && attr->threshold > 0 && attr->worst <= attr->threshold;
     184          248 :     attr->failing_now = attr->value > 0 && attr->threshold > 0 && attr->value <= attr->threshold;
     185          248 :     attr->value_raw = ((uint64_t) a->raw[0]) |
     186          248 :                       (((uint64_t) a->raw[1]) << 8) |
     187          248 :                       (((uint64_t) a->raw[2]) << 16) |
     188          248 :                       (((uint64_t) a->raw[3]) << 24) |
     189          248 :                       (((uint64_t) a->raw[4]) << 32) |
     190          248 :                       (((uint64_t) a->raw[5]) << 40);
     191          248 :     attr->flags = a->flags;
     192          248 :     attr->pretty_value = a->pretty_value;
     193          248 :     switch (a->pretty_unit) {
     194           66 :         case SK_SMART_ATTRIBUTE_UNIT_UNKNOWN:
     195           66 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN;
     196           66 :             break;
     197          106 :         case SK_SMART_ATTRIBUTE_UNIT_NONE:
     198          106 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_NONE;
     199          106 :             break;
     200           18 :         case SK_SMART_ATTRIBUTE_UNIT_MSECONDS:
     201           18 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_MSECONDS;
     202           18 :             break;
     203           24 :         case SK_SMART_ATTRIBUTE_UNIT_SECTORS:
     204           24 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_SECTORS;
     205           24 :             break;
     206           19 :         case SK_SMART_ATTRIBUTE_UNIT_MKELVIN:
     207           19 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_MKELVIN;
     208           19 :             break;
     209            0 :         case SK_SMART_ATTRIBUTE_UNIT_SMALL_PERCENT:
     210            0 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_SMALL_PERCENT;
     211            0 :             break;
     212            6 :         case SK_SMART_ATTRIBUTE_UNIT_PERCENT:
     213            6 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_PERCENT;
     214            6 :             break;
     215            9 :         case SK_SMART_ATTRIBUTE_UNIT_MB:
     216            9 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_MB;
     217            9 :             break;
     218            0 :         default:
     219            0 :             attr->pretty_value_unit = BD_SMART_ATA_ATTRIBUTE_UNIT_UNKNOWN;
     220            0 :             g_warn_if_reached ();
     221              :     }
     222          248 :     attr->pretty_value_string = print_value (a->pretty_value, a->pretty_unit);
     223              : 
     224              :     /* validate against drivedb */
     225          248 :     if (data->drivedb_attrs) {
     226              :         DriveDBAttr **l;
     227              : 
     228         2442 :         for (l = data->drivedb_attrs; *l; l++) {
     229         2368 :             if ((*l)->id == a->id && well_known_attrs[a->id].libatasmart_name) {
     230              :                 const gchar * const *n;
     231           28 :                 gboolean match = FALSE;
     232              : 
     233           64 :                 for (n = well_known_attrs[a->id].smartmontools_names; *n; n++)
     234           40 :                     if (g_ascii_strcasecmp ((*l)->name, *n) == 0) {
     235            4 :                         match = TRUE;
     236            4 :                         break;
     237              :                     }
     238              : 
     239           28 :                 if (!match) {
     240           24 :                     g_free (attr->well_known_name);
     241           24 :                     attr->well_known_name = NULL;
     242           24 :                     bd_utils_log_format (BD_UTILS_LOG_DEBUG,
     243              :                                          "libatasmart: drive %s: attribute [%d] \"%s\"/\"%s\" not whitelisted, reporting unknown attr",
     244           24 :                                          data->identify_data->model, a->id, a->name, (*l)->name);
     245              :                 }
     246              :             }
     247              :         }
     248              :     }
     249              : 
     250          248 :     g_ptr_array_add (data->ptr_array, attr);
     251          248 : }
     252              : 
     253           16 : static BDSmartATA * parse_sk_data (SkDisk *d, GError **error) {
     254           16 :     SkBool good = FALSE;
     255           16 :     SkBool available = FALSE;
     256           16 :     uint64_t power_on_msec = 0;
     257              :     const SkSmartParsedData *parsed_data;
     258              :     BDSmartATA *data;
     259              :     GPtrArray *ptr_array;
     260           16 :     struct ParseData parse_data = {0,};
     261              : 
     262           16 :     if (sk_disk_smart_read_data (d) != 0) {
     263            3 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     264              :                      "Error reading SMART data from device: %s",
     265            3 :                      strerror_l (errno, _C_LOCALE));
     266            3 :         return NULL;
     267              :     }
     268              : 
     269           13 :     if (sk_disk_smart_status (d, &good) != 0) {
     270            0 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     271              :                      "Error checking SMART data status: %s",
     272            0 :                      strerror_l (errno, _C_LOCALE));
     273            0 :         return NULL;
     274              :     }
     275              : 
     276           13 :     if (sk_disk_smart_parse (d, &parsed_data) != 0) {
     277            0 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     278              :                      "Error parsing SMART data: %s",
     279            0 :                      strerror_l (errno, _C_LOCALE));
     280            0 :         return NULL;
     281              :     }
     282              : 
     283           13 :     data = g_new0 (BDSmartATA, 1);
     284              : 
     285           13 :     sk_disk_smart_is_available (d, &available);
     286           13 :     data->smart_supported = available;
     287              :     /* At this point when SMART is not and cannot be enabled,
     288              :      * sk_disk_smart_read_data() would've already returned an error.
     289              :      */
     290           13 :     data->smart_enabled = TRUE;
     291           13 :     data->overall_status_passed = good;
     292              : 
     293           13 :     switch (parsed_data->offline_data_collection_status) {
     294            8 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER:
     295            8 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_NEVER_STARTED;
     296            8 :             break;
     297            3 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS:
     298            3 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_NO_ERROR;
     299            3 :             break;
     300            0 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS:
     301            0 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_IN_PROGRESS;
     302            0 :             break;
     303            2 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED:
     304            2 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED_INTR;
     305            2 :             break;
     306            0 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED:
     307            0 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_ABORTED_INTR;
     308            0 :             break;
     309            0 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL:
     310            0 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_ABORTED_ERROR;
     311            0 :             break;
     312            0 :         case SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN:
     313            0 :             data->offline_data_collection_status = BD_SMART_ATA_OFFLINE_DATA_COLLECTION_STATUS_VENDOR_SPECIFIC;
     314            0 :             break;
     315            0 :         default:
     316            0 :             g_warn_if_reached ();
     317              :     }
     318              : 
     319           13 :     data->auto_offline_data_collection_enabled = FALSE;   /* TODO */
     320           13 :     data->offline_data_collection_completion = parsed_data->total_offline_data_collection_seconds;
     321           13 :     data->offline_data_collection_capabilities = 0;       /* TODO */
     322              : 
     323           13 :     switch (parsed_data->self_test_execution_status) {
     324            9 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
     325            9 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_COMPLETED_NO_ERROR;
     326            9 :             break;
     327            2 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
     328            2 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ABORTED_HOST;
     329            2 :             break;
     330            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
     331            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_INTR_HOST_RESET;
     332            0 :             break;
     333            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
     334            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_FATAL;
     335            0 :             break;
     336            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
     337            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_UNKNOWN;
     338            0 :             break;
     339            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
     340            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_ELECTRICAL;
     341            0 :             break;
     342            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
     343            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_SERVO;
     344            0 :             break;
     345            2 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
     346            2 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_READ;
     347            2 :             break;
     348            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
     349            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_ERROR_HANDLING;
     350            0 :             break;
     351            0 :         case SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
     352            0 :             data->self_test_status = BD_SMART_ATA_SELF_TEST_STATUS_IN_PROGRESS;
     353            0 :             break;
     354            0 :         default:
     355            0 :             g_warn_if_reached ();
     356              :     }
     357              : 
     358           13 :     data->self_test_percent_remaining = parsed_data->self_test_execution_percent_remaining;
     359           13 :     data->self_test_polling_short = parsed_data->short_test_polling_minutes;
     360           13 :     data->self_test_polling_extended = parsed_data->extended_test_polling_minutes;
     361           13 :     data->self_test_polling_conveyance = parsed_data->conveyance_test_polling_minutes;
     362              : 
     363           13 :     data->smart_capabilities = 0;    /* TODO */
     364              : 
     365           13 :     sk_disk_smart_get_power_on (d, &power_on_msec);
     366           13 :     data->power_on_time = power_on_msec / 1000 / 60;
     367              : 
     368           13 :     sk_disk_smart_get_power_cycle (d, &data->power_cycle_count);
     369              : 
     370           13 :     ptr_array = g_ptr_array_new_full (0, (GDestroyNotify) bd_smart_ata_attribute_free);
     371           13 :     parse_data.ptr_array = ptr_array;
     372              : #ifdef HAVE_DRIVEDB_H
     373           13 :     sk_disk_identify_parse (d, &parse_data.identify_data);
     374           13 :     if (parse_data.identify_data)
     375           13 :         parse_data.drivedb_attrs = drivedb_lookup_drive (parse_data.identify_data->model,
     376           13 :                                                          parse_data.identify_data->firmware,
     377              :                                                          FALSE /* include_defaults */);
     378              : #endif
     379           13 :     data->temperature = calculate_temperature (d, parse_data.drivedb_attrs) / 1000;
     380              : 
     381           13 :     if (sk_disk_smart_parse_attributes (d, parse_attr_cb, &parse_data) != 0) {
     382            0 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     383              :                      "Error parsing SMART data: %s",
     384            0 :                      strerror_l (errno, _C_LOCALE));
     385            0 :         g_ptr_array_free (ptr_array, TRUE);
     386            0 :         bd_smart_ata_free (data);
     387            0 :         return NULL;
     388              :     }
     389           13 :     free_drivedb_attrs (parse_data.drivedb_attrs);
     390           13 :     g_ptr_array_add (ptr_array, NULL);
     391           13 :     data->attributes = (BDSmartATAAttribute **) g_ptr_array_free (ptr_array, FALSE);
     392              : 
     393           13 :     return data;
     394              : }
     395              : 
     396              : /**
     397              :  * bd_smart_ata_get_info:
     398              :  * @device: device to check.
     399              :  * @extra: (nullable) (array zero-terminated=1): extra options to pass through.
     400              :  * @error: (out) (optional): place to store error (if any).
     401              :  *
     402              :  * Retrieve SMART information from the drive.
     403              :  *
     404              :  * Returns: (transfer full): ATA SMART log or %NULL in case of an error (with @error set).
     405              :  *
     406              :  * Tech category: %BD_SMART_TECH_ATA-%BD_SMART_TECH_MODE_INFO
     407              :  */
     408            4 : BDSmartATA * bd_smart_ata_get_info (const gchar *device, G_GNUC_UNUSED const BDExtraArg **extra, GError **error) {
     409              :     SkDisk *d;
     410              :     BDSmartATA *data;
     411              : 
     412            4 :     g_warn_if_fail (device != NULL);
     413              : 
     414            4 :     if (sk_disk_open (device, &d) != 0) {
     415            1 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     416              :                      "Error opening device %s: %s",
     417              :                      device,
     418            1 :                      strerror_l (errno, _C_LOCALE));
     419            1 :         return NULL;
     420              :     }
     421              : 
     422            3 :     data = parse_sk_data (d, error);
     423            3 :     sk_disk_free (d);
     424              : 
     425            3 :     return data;
     426              : }
     427              : 
     428              : 
     429              : /**
     430              :  * bd_smart_ata_get_info_from_data:
     431              :  * @data: (array length=data_len): binary data to parse.
     432              :  * @data_len: length of the data supplied.
     433              :  * @error: (out) (optional): place to store error (if any).
     434              :  *
     435              :  * Retrieve SMART information from the supplied data.
     436              :  *
     437              :  * Returns: (transfer full): ATA SMART log or %NULL in case of an error (with @error set).
     438              :  *
     439              :  * Tech category: %BD_SMART_TECH_ATA-%BD_SMART_TECH_MODE_INFO
     440              :  */
     441           15 : BDSmartATA * bd_smart_ata_get_info_from_data (const guint8 *data, gsize data_len, GError **error) {
     442              :     SkDisk *d;
     443              :     BDSmartATA *ata_data;
     444              : 
     445           15 :     g_warn_if_fail (data != NULL);
     446           15 :     g_warn_if_fail (data_len > 0);
     447              : 
     448           15 :     if (sk_disk_open (NULL, &d) != 0) {
     449            0 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     450              :                      "Error parsing blob data: %s",
     451            0 :                      strerror_l (errno, _C_LOCALE));
     452            0 :         return NULL;
     453              :     }
     454              : 
     455           15 :     if (sk_disk_set_blob (d, data, data_len) != 0) {
     456            2 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     457              :                      "Error parsing blob data: %s",
     458            2 :                      strerror_l (errno, _C_LOCALE));
     459            2 :         return NULL;
     460              :     }
     461              : 
     462           13 :     ata_data = parse_sk_data (d, error);
     463           13 :     sk_disk_free (d);
     464              : 
     465           13 :     return ata_data;
     466              : }
     467              : 
     468              : 
     469              : /**
     470              :  * bd_smart_scsi_get_info:
     471              :  * @device: device to check.
     472              :  * @extra: (nullable) (array zero-terminated=1): extra options to pass through.
     473              :  * @error: (out) (optional): place to store error (if any).
     474              :  *
     475              :  * Retrieve SMART information from SCSI or SAS-compliant drive.
     476              :  *
     477              :  * Returns: (transfer full): SCSI SMART log or %NULL in case of an error (with @error set).
     478              :  *
     479              :  * Tech category: %BD_SMART_TECH_SCSI-%BD_SMART_TECH_MODE_INFO
     480              :  */
     481            4 : BDSmartSCSI * bd_smart_scsi_get_info (G_GNUC_UNUSED const gchar *device, G_GNUC_UNUSED const BDExtraArg **extra, GError **error) {
     482            4 :     g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_TECH_UNAVAIL, "SCSI SMART is unavailable with libatasmart");
     483            4 :     return FALSE;
     484              : }
     485              : 
     486              : 
     487              : /**
     488              :  * bd_smart_set_enabled:
     489              :  * @device: SMART-capable device.
     490              :  * @enabled: whether to enable or disable the SMART functionality
     491              :  * @extra: (nullable) (array zero-terminated=1): extra options to pass through.
     492              :  * @error: (out) (optional): place to store error (if any).
     493              :  *
     494              :  * Enables or disables SMART functionality on device.
     495              :  *
     496              :  * Returns: %TRUE when the functionality was set successfully or %FALSE in case of an error (with @error set).
     497              :  *
     498              :  * Tech category: %BD_SMART_TECH_ATA-%BD_SMART_TECH_MODE_INFO
     499              :  */
     500            8 : gboolean bd_smart_set_enabled (G_GNUC_UNUSED const gchar *device, G_GNUC_UNUSED gboolean enabled, G_GNUC_UNUSED const BDExtraArg **extra, GError **error) {
     501            8 :     g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_TECH_UNAVAIL, "Enabling/disabling ATA SMART functionality is unavailable with libatasmart");
     502            8 :     return FALSE;
     503              : }
     504              : 
     505              : 
     506              : /**
     507              :  * bd_smart_device_self_test:
     508              :  * @device: device to trigger the test on.
     509              :  * @operation: #BDSmartSelfTestOp self-test operation.
     510              :  * @extra: (nullable) (array zero-terminated=1): extra options to pass through.
     511              :  * @error: (out) (optional): place to store error (if any).
     512              :  *
     513              :  * Executes or aborts device self-test.
     514              :  *
     515              :  * Returns: %TRUE when the self-test was triggered successfully or %FALSE in case of an error (with @error set).
     516              :  *
     517              :  * Tech category: %BD_SMART_TECH_ATA-%BD_SMART_TECH_MODE_SELFTEST
     518              :  */
     519           20 : gboolean bd_smart_device_self_test (const gchar *device, BDSmartSelfTestOp operation, G_GNUC_UNUSED const BDExtraArg **extra, GError **error) {
     520              :     SkDisk *d;
     521              :     SkSmartSelfTest op;
     522              :     gboolean ret;
     523              : 
     524           20 :     switch (operation) {
     525            4 :         case BD_SMART_SELF_TEST_OP_ABORT:
     526            4 :             op = SK_SMART_SELF_TEST_ABORT;
     527            4 :             break;
     528            4 :         case BD_SMART_SELF_TEST_OP_SHORT:
     529            4 :             op = SK_SMART_SELF_TEST_SHORT;
     530            4 :             break;
     531            8 :         case BD_SMART_SELF_TEST_OP_LONG:
     532              :         case BD_SMART_SELF_TEST_OP_OFFLINE:
     533            8 :             op = SK_SMART_SELF_TEST_EXTENDED;
     534            8 :             break;
     535            4 :         case BD_SMART_SELF_TEST_OP_CONVEYANCE:
     536            4 :             op = SK_SMART_SELF_TEST_CONVEYANCE;
     537            4 :             break;
     538            0 :         default:
     539            0 :             g_set_error_literal (error, BD_SMART_ERROR, BD_SMART_ERROR_INVALID_ARGUMENT,
     540              :                                  "Invalid self-test operation.");
     541            0 :             return FALSE;
     542              :     }
     543              : 
     544           20 :     if (sk_disk_open (device, &d) != 0) {
     545            5 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     546              :                      "Error opening device %s: %s",
     547              :                      device,
     548            5 :                      strerror_l (errno, _C_LOCALE));
     549            5 :         return FALSE;
     550              :     }
     551              : 
     552           15 :     ret = sk_disk_smart_self_test (d, op) == 0;
     553           15 :     sk_disk_free (d);
     554           15 :     if (!ret) {
     555           15 :         g_set_error (error, BD_SMART_ERROR, BD_SMART_ERROR_FAILED,
     556              :                      "Error triggering device self-test: %s",
     557           15 :                      strerror_l (errno, _C_LOCALE));
     558           15 :         return FALSE;
     559              :     }
     560              : 
     561            0 :     return TRUE;
     562              : }
        

Generated by: LCOV version 2.0-1