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

Generated by: LCOV version 2.0-1