LCOV - code coverage report
Current view: top level - libsystemd/sd-hwdb - sd-hwdb.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 169 239 70.7 %
Date: 2019-08-23 13:36:53 Functions: 21 24 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 93 210 44.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <errno.h>
       7                 :            : #include <fnmatch.h>
       8                 :            : #include <inttypes.h>
       9                 :            : #include <stdio.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <string.h>
      12                 :            : #include <sys/mman.h>
      13                 :            : #include <sys/stat.h>
      14                 :            : 
      15                 :            : #include "sd-hwdb.h"
      16                 :            : 
      17                 :            : #include "alloc-util.h"
      18                 :            : #include "fd-util.h"
      19                 :            : #include "hashmap.h"
      20                 :            : #include "hwdb-internal.h"
      21                 :            : #include "hwdb-util.h"
      22                 :            : #include "nulstr-util.h"
      23                 :            : #include "string-util.h"
      24                 :            : #include "time-util.h"
      25                 :            : 
      26                 :            : struct sd_hwdb {
      27                 :            :         unsigned n_ref;
      28                 :            : 
      29                 :            :         FILE *f;
      30                 :            :         struct stat st;
      31                 :            :         union {
      32                 :            :                 struct trie_header_f *head;
      33                 :            :                 const char *map;
      34                 :            :         };
      35                 :            : 
      36                 :            :         OrderedHashmap *properties;
      37                 :            :         Iterator properties_iterator;
      38                 :            :         bool properties_modified;
      39                 :            : };
      40                 :            : 
      41                 :            : struct linebuf {
      42                 :            :         char bytes[LINE_MAX];
      43                 :            :         size_t size;
      44                 :            :         size_t len;
      45                 :            : };
      46                 :            : 
      47                 :         16 : static void linebuf_init(struct linebuf *buf) {
      48                 :         16 :         buf->size = 0;
      49                 :         16 :         buf->len = 0;
      50                 :         16 : }
      51                 :            : 
      52                 :       1796 : static const char *linebuf_get(struct linebuf *buf) {
      53         [ -  + ]:       1796 :         if (buf->len + 1 >= sizeof(buf->bytes))
      54                 :          0 :                 return NULL;
      55                 :       1796 :         buf->bytes[buf->len] = '\0';
      56                 :       1796 :         return buf->bytes;
      57                 :            : }
      58                 :            : 
      59                 :       2780 : static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
      60         [ -  + ]:       2780 :         if (buf->len + len >= sizeof(buf->bytes))
      61                 :          0 :                 return false;
      62                 :       2780 :         memcpy(buf->bytes + buf->len, s, len);
      63                 :       2780 :         buf->len += len;
      64                 :       2780 :         return true;
      65                 :            : }
      66                 :            : 
      67                 :       2768 : static bool linebuf_add_char(struct linebuf *buf, char c) {
      68         [ -  + ]:       2768 :         if (buf->len + 1 >= sizeof(buf->bytes))
      69                 :          0 :                 return false;
      70                 :       2768 :         buf->bytes[buf->len++] = c;
      71                 :       2768 :         return true;
      72                 :            : }
      73                 :            : 
      74                 :       5548 : static void linebuf_rem(struct linebuf *buf, size_t count) {
      75         [ -  + ]:       5548 :         assert(buf->len >= count);
      76                 :       5548 :         buf->len -= count;
      77                 :       5548 : }
      78                 :            : 
      79                 :       2768 : static void linebuf_rem_char(struct linebuf *buf) {
      80                 :       2768 :         linebuf_rem(buf, 1);
      81                 :       2768 : }
      82                 :            : 
      83                 :       2760 : static const struct trie_child_entry_f *trie_node_child(sd_hwdb *hwdb, const struct trie_node_f *node, size_t idx) {
      84                 :       2760 :         const char *base = (const char *)node;
      85                 :            : 
      86                 :       2760 :         base += le64toh(hwdb->head->node_size);
      87                 :       2760 :         base += idx * le64toh(hwdb->head->child_entry_size);
      88                 :       2760 :         return (const struct trie_child_entry_f *)base;
      89                 :            : }
      90                 :            : 
      91                 :        240 : static const struct trie_value_entry_f *trie_node_value(sd_hwdb *hwdb, const struct trie_node_f *node, size_t idx) {
      92                 :        240 :         const char *base = (const char *)node;
      93                 :            : 
      94                 :        240 :         base += le64toh(hwdb->head->node_size);
      95                 :        240 :         base += node->children_count * le64toh(hwdb->head->child_entry_size);
      96                 :        240 :         base += idx * le64toh(hwdb->head->value_entry_size);
      97                 :        240 :         return (const struct trie_value_entry_f *)base;
      98                 :            : }
      99                 :            : 
     100                 :       2828 : static const struct trie_node_f *trie_node_from_off(sd_hwdb *hwdb, le64_t off) {
     101                 :       2828 :         return (const struct trie_node_f *)(hwdb->map + le64toh(off));
     102                 :            : }
     103                 :            : 
     104                 :       3484 : static const char *trie_string(sd_hwdb *hwdb, le64_t off) {
     105                 :       3484 :         return hwdb->map + le64toh(off);
     106                 :            : }
     107                 :            : 
     108                 :        616 : static int trie_children_cmp_f(const void *v1, const void *v2) {
     109                 :        616 :         const struct trie_child_entry_f *n1 = v1;
     110                 :        616 :         const struct trie_child_entry_f *n2 = v2;
     111                 :            : 
     112                 :        616 :         return n1->c - n2->c;
     113                 :            : }
     114                 :            : 
     115                 :        192 : static const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
     116                 :            :         struct trie_child_entry_f *child;
     117                 :            :         struct trie_child_entry_f search;
     118                 :            : 
     119                 :        192 :         search.c = c;
     120                 :        192 :         child = bsearch(&search, (const char *)node + le64toh(hwdb->head->node_size), node->children_count,
     121                 :        192 :                         le64toh(hwdb->head->child_entry_size), trie_children_cmp_f);
     122         [ +  + ]:        192 :         if (child)
     123                 :         52 :                 return trie_node_from_off(hwdb, child->child_off);
     124                 :        140 :         return NULL;
     125                 :            : }
     126                 :            : 
     127                 :        240 : static int hwdb_add_property(sd_hwdb *hwdb, const struct trie_value_entry_f *entry) {
     128                 :            :         const char *key;
     129                 :            :         int r;
     130                 :            : 
     131         [ -  + ]:        240 :         assert(hwdb);
     132                 :            : 
     133                 :        240 :         key = trie_string(hwdb, entry->key_off);
     134                 :            : 
     135                 :            :         /*
     136                 :            :          * Silently ignore all properties which do not start with a
     137                 :            :          * space; future extensions might use additional prefixes.
     138                 :            :          */
     139         [ -  + ]:        240 :         if (key[0] != ' ')
     140                 :          0 :                 return 0;
     141                 :            : 
     142                 :        240 :         key++;
     143                 :            : 
     144         [ +  - ]:        240 :         if (le64toh(hwdb->head->value_entry_size) >= sizeof(struct trie_value_entry2_f)) {
     145                 :            :                 const struct trie_value_entry2_f *old, *entry2;
     146                 :            : 
     147                 :        240 :                 entry2 = (const struct trie_value_entry2_f *)entry;
     148                 :        240 :                 old = ordered_hashmap_get(hwdb->properties, key);
     149         [ -  + ]:        240 :                 if (old) {
     150                 :            :                         /* On duplicates, we order by filename priority and line-number.
     151                 :            :                          *
     152                 :            :                          * v2 of the format had 64 bits for the line number.
     153                 :            :                          * v3 reuses top 32 bits of line_number to store the priority.
     154                 :            :                          * We check the top bits — if they are zero we have v2 format.
     155                 :            :                          * This means that v2 clients will print wrong line numbers with
     156                 :            :                          * v3 data.
     157                 :            :                          *
     158                 :            :                          * For v3 data: we compare the priority (of the source file)
     159                 :            :                          * and the line number.
     160                 :            :                          *
     161                 :            :                          * For v2 data: we rely on the fact that the filenames in the hwdb
     162                 :            :                          * are added in the order of priority (higher later), because they
     163                 :            :                          * are *processed* in the order of priority. So we compare the
     164                 :            :                          * indices to determine which file had higher priority. Comparing
     165                 :            :                          * the strings alphabetically would be useless, because those are
     166                 :            :                          * full paths, and e.g. /usr/lib would sort after /etc, even
     167                 :            :                          * though it has lower priority. This is not reliable because of
     168                 :            :                          * suffix compression, but should work for the most common case of
     169                 :            :                          * /usr/lib/udev/hwbd.d and /etc/udev/hwdb.d, and is better than
     170                 :            :                          * not doing the comparison at all.
     171                 :            :                          */
     172                 :            :                         bool lower;
     173                 :            : 
     174         [ #  # ]:          0 :                         if (entry2->file_priority == 0)
     175         [ #  # ]:          0 :                                 lower = entry2->filename_off < old->filename_off ||
     176   [ #  #  #  # ]:          0 :                                         (entry2->filename_off == old->filename_off && entry2->line_number < old->line_number);
     177                 :            :                         else
     178         [ #  # ]:          0 :                                 lower = entry2->file_priority < old->file_priority ||
     179   [ #  #  #  # ]:          0 :                                         (entry2->file_priority == old->file_priority && entry2->line_number < old->line_number);
     180         [ #  # ]:          0 :                         if (lower)
     181                 :          0 :                                 return 0;
     182                 :            :                 }
     183                 :            :         }
     184                 :            : 
     185                 :        240 :         r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops);
     186         [ -  + ]:        240 :         if (r < 0)
     187                 :          0 :                 return r;
     188                 :            : 
     189                 :        240 :         r = ordered_hashmap_replace(hwdb->properties, key, (void *)entry);
     190         [ -  + ]:        240 :         if (r < 0)
     191                 :          0 :                 return r;
     192                 :            : 
     193                 :        240 :         hwdb->properties_modified = true;
     194                 :            : 
     195                 :        240 :         return 0;
     196                 :            : }
     197                 :            : 
     198                 :       2780 : static int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t p,
     199                 :            :                           struct linebuf *buf, const char *search) {
     200                 :            :         size_t len;
     201                 :            :         size_t i;
     202                 :            :         const char *prefix;
     203                 :            :         int err;
     204                 :            : 
     205                 :       2780 :         prefix = trie_string(hwdb, node->prefix_off);
     206                 :       2780 :         len = strlen(prefix + p);
     207                 :       2780 :         linebuf_add(buf, prefix + p, len);
     208                 :            : 
     209         [ +  + ]:       5540 :         for (i = 0; i < node->children_count; i++) {
     210                 :       2760 :                 const struct trie_child_entry_f *child = trie_node_child(hwdb, node, i);
     211                 :            : 
     212                 :       2760 :                 linebuf_add_char(buf, child->c);
     213                 :       2760 :                 err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
     214         [ -  + ]:       2760 :                 if (err < 0)
     215                 :          0 :                         return err;
     216                 :       2760 :                 linebuf_rem_char(buf);
     217                 :            :         }
     218                 :            : 
     219   [ +  +  +  + ]:       2780 :         if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0)
     220         [ +  + ]:        256 :                 for (i = 0; i < le64toh(node->values_count); i++) {
     221                 :        240 :                         err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, i));
     222         [ -  + ]:        240 :                         if (err < 0)
     223                 :          0 :                                 return err;
     224                 :            :                 }
     225                 :            : 
     226                 :       2780 :         linebuf_rem(buf, len);
     227                 :       2780 :         return 0;
     228                 :            : }
     229                 :            : 
     230                 :         16 : static int trie_search_f(sd_hwdb *hwdb, const char *search) {
     231                 :            :         struct linebuf buf;
     232                 :            :         const struct trie_node_f *node;
     233                 :         16 :         size_t i = 0;
     234                 :            :         int err;
     235                 :            : 
     236                 :         16 :         linebuf_init(&buf);
     237                 :            : 
     238                 :         16 :         node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
     239         [ +  + ]:         64 :         while (node) {
     240                 :            :                 const struct trie_node_f *child;
     241                 :         60 :                 size_t p = 0;
     242                 :            : 
     243         [ +  - ]:         60 :                 if (node->prefix_off) {
     244                 :            :                         char c;
     245                 :            : 
     246         [ +  + ]:        224 :                         for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
     247   [ +  +  +  + ]:        176 :                                 if (IN_SET(c, '*', '?', '['))
     248                 :         12 :                                         return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
     249         [ -  + ]:        164 :                                 if (c != search[i + p])
     250                 :          0 :                                         return 0;
     251                 :            :                         }
     252                 :         48 :                         i += p;
     253                 :            :                 }
     254                 :            : 
     255                 :         48 :                 child = node_lookup_f(hwdb, node, '*');
     256         [ +  + ]:         48 :                 if (child) {
     257                 :          8 :                         linebuf_add_char(&buf, '*');
     258                 :          8 :                         err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
     259         [ -  + ]:          8 :                         if (err < 0)
     260                 :          0 :                                 return err;
     261                 :          8 :                         linebuf_rem_char(&buf);
     262                 :            :                 }
     263                 :            : 
     264                 :         48 :                 child = node_lookup_f(hwdb, node, '?');
     265         [ -  + ]:         48 :                 if (child) {
     266                 :          0 :                         linebuf_add_char(&buf, '?');
     267                 :          0 :                         err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
     268         [ #  # ]:          0 :                         if (err < 0)
     269                 :          0 :                                 return err;
     270                 :          0 :                         linebuf_rem_char(&buf);
     271                 :            :                 }
     272                 :            : 
     273                 :         48 :                 child = node_lookup_f(hwdb, node, '[');
     274         [ -  + ]:         48 :                 if (child) {
     275                 :          0 :                         linebuf_add_char(&buf, '[');
     276                 :          0 :                         err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
     277         [ #  # ]:          0 :                         if (err < 0)
     278                 :          0 :                                 return err;
     279                 :          0 :                         linebuf_rem_char(&buf);
     280                 :            :                 }
     281                 :            : 
     282         [ -  + ]:         48 :                 if (search[i] == '\0') {
     283                 :            :                         size_t n;
     284                 :            : 
     285         [ #  # ]:          0 :                         for (n = 0; n < le64toh(node->values_count); n++) {
     286                 :          0 :                                 err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, n));
     287         [ #  # ]:          0 :                                 if (err < 0)
     288                 :          0 :                                         return err;
     289                 :            :                         }
     290                 :          0 :                         return 0;
     291                 :            :                 }
     292                 :            : 
     293                 :         48 :                 child = node_lookup_f(hwdb, node, search[i]);
     294                 :         48 :                 node = child;
     295                 :         48 :                 i++;
     296                 :            :         }
     297                 :          4 :         return 0;
     298                 :            : }
     299                 :            : 
     300                 :            : static const char hwdb_bin_paths[] =
     301                 :            :         "/etc/systemd/hwdb/hwdb.bin\0"
     302                 :            :         "/etc/udev/hwdb.bin\0"
     303                 :            :         "/usr/lib/systemd/hwdb/hwdb.bin\0"
     304                 :            : #if HAVE_SPLIT_USR
     305                 :            :         "/lib/systemd/hwdb/hwdb.bin\0"
     306                 :            : #endif
     307                 :            :         UDEVLIBEXECDIR "/hwdb.bin\0";
     308                 :            : 
     309                 :         12 : _public_ int sd_hwdb_new(sd_hwdb **ret) {
     310                 :         12 :         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
     311                 :            :         const char *hwdb_bin_path;
     312                 :         12 :         const char sig[] = HWDB_SIG;
     313                 :            : 
     314   [ -  +  -  + ]:         12 :         assert_return(ret, -EINVAL);
     315                 :            : 
     316                 :         12 :         hwdb = new0(sd_hwdb, 1);
     317         [ -  + ]:         12 :         if (!hwdb)
     318                 :          0 :                 return -ENOMEM;
     319                 :            : 
     320                 :         12 :         hwdb->n_ref = 1;
     321                 :            : 
     322                 :            :         /* find hwdb.bin in hwdb_bin_paths */
     323   [ +  -  +  - ]:         24 :         NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
     324         [ +  + ]:         24 :                 log_debug("Trying to open \"%s\"...", hwdb_bin_path);
     325                 :         24 :                 hwdb->f = fopen(hwdb_bin_path, "re");
     326         [ +  + ]:         24 :                 if (hwdb->f)
     327                 :         12 :                         break;
     328         [ -  + ]:         12 :                 if (errno != ENOENT)
     329         [ #  # ]:          0 :                         return log_debug_errno(errno, "Failed to open %s: %m", hwdb_bin_path);
     330                 :            :         }
     331                 :            : 
     332         [ -  + ]:         12 :         if (!hwdb->f)
     333         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
     334                 :            :                                        "hwdb.bin does not exist, please run 'systemd-hwdb update'");
     335                 :            : 
     336         [ -  + ]:         12 :         if (fstat(fileno(hwdb->f), &hwdb->st) < 0)
     337         [ #  # ]:          0 :                 return log_debug_errno(errno, "Failed to stat %s: %m", hwdb_bin_path);
     338         [ -  + ]:         12 :         if (hwdb->st.st_size < (off_t) offsetof(struct trie_header_f, strings_len) + 8)
     339         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
     340                 :            :                                        "File %s is too short: %m", hwdb_bin_path);
     341                 :            : 
     342                 :         12 :         hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
     343         [ -  + ]:         12 :         if (hwdb->map == MAP_FAILED)
     344         [ #  # ]:          0 :                 return log_debug_errno(errno, "Failed to map %s: %m", hwdb_bin_path);
     345                 :            : 
     346   [ +  -  -  + ]:         24 :         if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
     347                 :         12 :             (size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
     348         [ #  # ]:          0 :                 log_debug("Failed to recognize the format of %s", hwdb_bin_path);
     349                 :          0 :                 return -EINVAL;
     350                 :            :         }
     351                 :            : 
     352         [ +  + ]:         12 :         log_debug("=== trie on-disk ===");
     353         [ +  + ]:         12 :         log_debug("tool version:          %"PRIu64, le64toh(hwdb->head->tool_version));
     354         [ +  + ]:         12 :         log_debug("file size:        %8"PRIi64" bytes", hwdb->st.st_size);
     355         [ +  + ]:         12 :         log_debug("header size       %8"PRIu64" bytes", le64toh(hwdb->head->header_size));
     356         [ +  + ]:         12 :         log_debug("strings           %8"PRIu64" bytes", le64toh(hwdb->head->strings_len));
     357         [ +  + ]:         12 :         log_debug("nodes             %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len));
     358                 :            : 
     359                 :         12 :         *ret = TAKE_PTR(hwdb);
     360                 :            : 
     361                 :         12 :         return 0;
     362                 :            : }
     363                 :            : 
     364                 :         12 : static sd_hwdb *hwdb_free(sd_hwdb *hwdb) {
     365         [ -  + ]:         12 :         assert(hwdb);
     366                 :            : 
     367         [ +  - ]:         12 :         if (hwdb->map)
     368                 :         12 :                 munmap((void *)hwdb->map, hwdb->st.st_size);
     369                 :         12 :         safe_fclose(hwdb->f);
     370                 :         12 :         ordered_hashmap_free(hwdb->properties);
     371                 :         12 :         return mfree(hwdb);
     372                 :            : }
     373                 :            : 
     374   [ -  +  -  +  :         12 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_hwdb, sd_hwdb, hwdb_free)
                   -  + ]
     375                 :            : 
     376                 :          0 : bool hwdb_validate(sd_hwdb *hwdb) {
     377                 :          0 :         bool found = false;
     378                 :            :         const char* p;
     379                 :            :         struct stat st;
     380                 :            : 
     381         [ #  # ]:          0 :         if (!hwdb)
     382                 :          0 :                 return false;
     383         [ #  # ]:          0 :         if (!hwdb->f)
     384                 :          0 :                 return false;
     385                 :            : 
     386                 :            :         /* if hwdb.bin doesn't exist anywhere, we need to update */
     387   [ #  #  #  # ]:          0 :         NULSTR_FOREACH(p, hwdb_bin_paths)
     388         [ #  # ]:          0 :                 if (stat(p, &st) >= 0) {
     389                 :          0 :                         found = true;
     390                 :          0 :                         break;
     391                 :            :                 }
     392         [ #  # ]:          0 :         if (!found)
     393                 :          0 :                 return true;
     394                 :            : 
     395         [ #  # ]:          0 :         if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
     396                 :          0 :                 return true;
     397                 :          0 :         return false;
     398                 :            : }
     399                 :            : 
     400                 :         16 : static int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
     401         [ -  + ]:         16 :         assert(hwdb);
     402         [ -  + ]:         16 :         assert(modalias);
     403                 :            : 
     404                 :         16 :         ordered_hashmap_clear(hwdb->properties);
     405                 :         16 :         hwdb->properties_modified = true;
     406                 :            : 
     407                 :         16 :         return trie_search_f(hwdb, modalias);
     408                 :            : }
     409                 :            : 
     410                 :          0 : _public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) {
     411                 :            :         const struct trie_value_entry_f *entry;
     412                 :            :         int r;
     413                 :            : 
     414   [ #  #  #  # ]:          0 :         assert_return(hwdb, -EINVAL);
     415   [ #  #  #  # ]:          0 :         assert_return(hwdb->f, -EINVAL);
     416   [ #  #  #  # ]:          0 :         assert_return(modalias, -EINVAL);
     417   [ #  #  #  # ]:          0 :         assert_return(_value, -EINVAL);
     418                 :            : 
     419                 :          0 :         r = properties_prepare(hwdb, modalias);
     420         [ #  # ]:          0 :         if (r < 0)
     421                 :          0 :                 return r;
     422                 :            : 
     423                 :          0 :         entry = ordered_hashmap_get(hwdb->properties, key);
     424         [ #  # ]:          0 :         if (!entry)
     425                 :          0 :                 return -ENOENT;
     426                 :            : 
     427                 :          0 :         *_value = trie_string(hwdb, entry->value_off);
     428                 :            : 
     429                 :          0 :         return 0;
     430                 :            : }
     431                 :            : 
     432                 :         16 : _public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) {
     433                 :            :         int r;
     434                 :            : 
     435   [ -  +  -  + ]:         16 :         assert_return(hwdb, -EINVAL);
     436   [ -  +  -  + ]:         16 :         assert_return(hwdb->f, -EINVAL);
     437   [ -  +  -  + ]:         16 :         assert_return(modalias, -EINVAL);
     438                 :            : 
     439                 :         16 :         r = properties_prepare(hwdb, modalias);
     440         [ -  + ]:         16 :         if (r < 0)
     441                 :          0 :                 return r;
     442                 :            : 
     443                 :         16 :         hwdb->properties_modified = false;
     444                 :         16 :         hwdb->properties_iterator = ITERATOR_FIRST;
     445                 :            : 
     446                 :         16 :         return 0;
     447                 :            : }
     448                 :            : 
     449                 :        264 : _public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
     450                 :            :         const struct trie_value_entry_f *entry;
     451                 :            :         const void *k;
     452                 :            : 
     453   [ -  +  -  + ]:        264 :         assert_return(hwdb, -EINVAL);
     454   [ +  +  +  + ]:        264 :         assert_return(key, -EINVAL);
     455   [ +  +  +  + ]:        260 :         assert_return(value, -EINVAL);
     456                 :            : 
     457         [ -  + ]:        256 :         if (hwdb->properties_modified)
     458                 :          0 :                 return -EAGAIN;
     459                 :            : 
     460         [ +  + ]:        256 :         if (!ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, (void **)&entry, &k))
     461                 :         16 :                 return 0;
     462                 :            : 
     463                 :        240 :         *key = k;
     464                 :        240 :         *value = trie_string(hwdb, entry->value_off);
     465                 :            : 
     466                 :        240 :         return 1;
     467                 :            : }

Generated by: LCOV version 1.14