LCOV - code coverage report
Current view: top level - plugins/smart - drivedb-parser.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 79.8 % 99 79
Test Date: 2026-01-26 13:19:28 Functions: 100.0 % 4 4
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 "smart.h"
      27              : #include "smart-private.h"
      28              : 
      29              : 
      30           13 : void free_drivedb_attrs (DriveDBAttr **attrs) {
      31              :     DriveDBAttr **a;
      32              : 
      33           13 :     if (attrs == NULL)
      34            9 :         return;
      35          132 :     for (a = attrs; *a; a++) {
      36          128 :         g_free ((*a)->name);
      37          128 :         g_free (*a);
      38              :     }
      39            4 :     g_free (attrs);
      40              : }
      41              : 
      42              : 
      43              : #ifndef HAVE_DRIVEDB_H
      44              : DriveDBAttr** drivedb_lookup_drive (G_GNUC_UNUSED const gchar *model, G_GNUC_UNUSED const gchar *fw, G_GNUC_UNUSED gboolean include_defaults) {
      45              :     return NULL;
      46              : }
      47              : #else
      48              : 
      49              : struct drive_settings {
      50              :     const char* modelfamily;
      51              :     const char* modelregexp;
      52              :     const char* firmwareregexp;
      53              :     const char* warningmsg;
      54              :     const char* presets;
      55              : };
      56              : 
      57              : static const struct drive_settings builtin_knowndrives[] = {
      58              : #include <drivedb.h>
      59              : };
      60              : 
      61              : 
      62          129 : static gboolean parse_attribute_def (const char *arg, gint *attr_id, gchar **attr_name) {
      63          129 :     int format_str_len = 0;
      64          129 :     int attrname_str_len = 0;
      65          129 :     int hddssd_str_len = 0;
      66          129 :     char format_str[33] = {0,};
      67          129 :     char attrname_str[33] = {0,};
      68          129 :     char hddssd_str[4] = {0,};
      69              : 
      70          129 :     if (arg[0] == 'N')
      71              :         /* ignoring "N,format[,name]" as it doesn't provide attribute ID */
      72            0 :         return FALSE;
      73              : 
      74              :     /* parse "id,format[+][,name[,HDD|SSD]]" */
      75          129 :     if (sscanf (arg, "%d,%32[^,]%n,%32[^,]%n,%3[DHS]%n",
      76              :                 attr_id,
      77              :                 format_str, &format_str_len,
      78              :                 attrname_str, &attrname_str_len,
      79              :                 hddssd_str, &hddssd_str_len) < 2)
      80            0 :         return FALSE;
      81          129 :     if (*attr_id < 1 || *attr_id > 255)
      82            0 :         return FALSE;
      83          129 :     if (attrname_str_len < 1)
      84            1 :         return FALSE;
      85              : 
      86              :     /* ignoring format_str */
      87          128 :     *attr_name = g_strndup (attrname_str, attrname_str_len);
      88              :     /* ignoring hddssd_str */
      89              : 
      90          128 :     return TRUE;
      91              : }
      92              : 
      93            5 : static void parse_presets_str (const char *presets, GHashTable *attrs) {
      94          129 :     while (TRUE) {
      95              :         char opt;
      96          134 :         char arg[94] = {0,};
      97          134 :         int len = 0;
      98          134 :         gint attr_id = 0;
      99          134 :         gchar *attr_name = NULL;
     100              : 
     101          134 :         presets += strspn (presets, " \t");
     102          134 :         if (presets[0] == '\0')
     103            5 :             break;
     104          129 :         if (sscanf (presets, "-%c %80[^ ]%n", &opt, arg, &len) < 2)
     105            0 :             break;
     106          129 :         if (len < 1)
     107            0 :             break;
     108          129 :         if (opt == 'v') {
     109              :             /* parse "-v N,format[,name[,HDD|SSD]]" */
     110          129 :             if (parse_attribute_def (arg, &attr_id, &attr_name)) {
     111          128 :                 g_hash_table_replace (attrs, GINT_TO_POINTER (attr_id), attr_name);
     112              :             }
     113              :         }
     114              :         /* ignoring other switches like 'F' and 'd' */
     115              : 
     116          129 :         presets += len;
     117              :     }
     118            5 : }
     119              : 
     120           13 : DriveDBAttr** drivedb_lookup_drive (const gchar *model, const gchar *fw, gboolean include_defaults) {
     121              :     gulong i;
     122              :     GHashTable *attrs;
     123           13 :     DriveDBAttr **ret = NULL;
     124              : 
     125              :     if (G_N_ELEMENTS (builtin_knowndrives) == 0)
     126              :         return NULL;
     127              : 
     128           13 :     attrs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
     129              : 
     130              :     /* first parse the DEFAULTS definitions */
     131           13 :     if (include_defaults)
     132            0 :         for (i = 0; i < G_N_ELEMENTS (builtin_knowndrives); i++)
     133            0 :             if (builtin_knowndrives[i].modelfamily &&
     134            0 :                 builtin_knowndrives[i].presets &&
     135            0 :                 g_ascii_strncasecmp (builtin_knowndrives[i].modelfamily, "DEFAULT", 7) == 0)
     136            0 :                     parse_presets_str (builtin_knowndrives[i].presets, attrs);
     137              : 
     138              :     /* now overlay/replace with drive specific keys */
     139        10426 :     for (i = 0; i < G_N_ELEMENTS (builtin_knowndrives); i++) {
     140              :         GRegex *regex;
     141        10413 :         GError *error = NULL;
     142        10413 :         gboolean match = FALSE;
     143              : 
     144              :         /* check the modelfamily string */
     145        10413 :         if (builtin_knowndrives[i].modelfamily == NULL ||
     146        10413 :             builtin_knowndrives[i].modelregexp == NULL ||
     147        16042 :             builtin_knowndrives[i].presets == NULL || strlen (builtin_knowndrives[i].presets) < 5 ||
     148        11258 :             g_ascii_strncasecmp (builtin_knowndrives[i].modelfamily, "VERSION", 7) == 0 ||
     149         8450 :             g_ascii_strncasecmp (builtin_knowndrives[i].modelfamily, "USB", 3) == 0 ||
     150         2821 :             g_ascii_strncasecmp (builtin_knowndrives[i].modelfamily, "DEFAULT", 7) == 0)
     151        10407 :             continue;
     152              :         /* assuming modelfamily=ATA from now on... */
     153              : 
     154              :         /* match the model string */
     155         2808 :         regex = g_regex_new (builtin_knowndrives[i].modelregexp,
     156              :                              0, 0, &error);
     157         2808 :         if (regex == NULL) {
     158            0 :             bd_utils_log_format (BD_UTILS_LOG_DEBUG,
     159              :                                  "drivedb-parser: regex compilation failed for '%s': %s",
     160            0 :                                  builtin_knowndrives[i].modelregexp,
     161            0 :                                  error->message);
     162            0 :             g_error_free (error);
     163            0 :             continue;
     164              :         }
     165         2808 :         if (g_regex_match (regex, model, 0, NULL))
     166            6 :             match = TRUE;
     167         2808 :         g_regex_unref (regex);
     168         2808 :         if (!match)
     169         2802 :             continue;
     170              : 
     171              :         /* match the firmware string */
     172            6 :         if (builtin_knowndrives[i].firmwareregexp &&
     173            6 :             strlen (builtin_knowndrives[i].firmwareregexp) > 0 &&
     174            1 :             fw && strlen (fw) > 0)
     175              :         {
     176            1 :             regex = g_regex_new (builtin_knowndrives[i].firmwareregexp,
     177              :                                  0, 0, &error);
     178            1 :             if (regex == NULL) {
     179            0 :                 bd_utils_log_format (BD_UTILS_LOG_DEBUG,
     180              :                                      "drivedb-parser: regex compilation failed for '%s': %s",
     181            0 :                                      builtin_knowndrives[i].firmwareregexp,
     182            0 :                                      error->message);
     183            0 :                 g_error_free (error);
     184            0 :                 continue;
     185              :             }
     186            1 :             if (!g_regex_match (regex, model, 0, NULL))
     187            1 :                 match = FALSE;
     188            1 :             g_regex_unref (regex);
     189              :         }
     190              : 
     191            6 :         if (match)
     192            5 :             parse_presets_str (builtin_knowndrives[i].presets, attrs);
     193              :     }
     194              : 
     195           13 :     if (g_hash_table_size (attrs) > 0) {
     196              :         GHashTableIter iter;
     197              :         gpointer key, val;
     198              : 
     199              :         /* convert to NULL-terminated array */
     200            4 :         i = 0;
     201            4 :         ret = g_new0 (DriveDBAttr *, g_hash_table_size (attrs) + 1);
     202            4 :         g_hash_table_iter_init (&iter, attrs);
     203          132 :         while (g_hash_table_iter_next (&iter, &key, &val)) {
     204              :             DriveDBAttr *attr;
     205              : 
     206          128 :             attr = g_new0 (DriveDBAttr, 1);
     207          128 :             attr->id = GPOINTER_TO_INT (key);
     208          128 :             attr->name = g_strdup (val);
     209          128 :             ret[i++] = attr;
     210              :         }
     211              :     }
     212           13 :     g_hash_table_destroy (attrs);
     213              : 
     214           13 :     return ret;
     215              : }
     216              : #endif   /* HAVE_DRIVEDB_H */
        

Generated by: LCOV version 2.0-1