| File: | build-scan/../src/libsystemd/sd-hwdb/sd-hwdb.c |
| Warning: | line 334, column 17 Potential leak of memory pointed to by 'hwdb' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | /*** | |||
| 3 | Copyright © 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com> | |||
| 4 | ***/ | |||
| 5 | ||||
| 6 | #include <errno(*__errno_location ()).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 | ||||
| 14 | #include "sd-hwdb.h" | |||
| 15 | ||||
| 16 | #include "alloc-util.h" | |||
| 17 | #include "fd-util.h" | |||
| 18 | #include "hashmap.h" | |||
| 19 | #include "hwdb-internal.h" | |||
| 20 | #include "hwdb-util.h" | |||
| 21 | #include "refcnt.h" | |||
| 22 | #include "string-util.h" | |||
| 23 | ||||
| 24 | struct sd_hwdb { | |||
| 25 | RefCount n_ref; | |||
| 26 | int refcount; | |||
| 27 | ||||
| 28 | FILE *f; | |||
| 29 | struct stat st; | |||
| 30 | union { | |||
| 31 | struct trie_header_f *head; | |||
| 32 | const char *map; | |||
| 33 | }; | |||
| 34 | ||||
| 35 | OrderedHashmap *properties; | |||
| 36 | Iterator properties_iterator; | |||
| 37 | bool_Bool properties_modified; | |||
| 38 | }; | |||
| 39 | ||||
| 40 | struct linebuf { | |||
| 41 | char bytes[LINE_MAX2048]; | |||
| 42 | size_t size; | |||
| 43 | size_t len; | |||
| 44 | }; | |||
| 45 | ||||
| 46 | static void linebuf_init(struct linebuf *buf) { | |||
| 47 | buf->size = 0; | |||
| 48 | buf->len = 0; | |||
| 49 | } | |||
| 50 | ||||
| 51 | static const char *linebuf_get(struct linebuf *buf) { | |||
| 52 | if (buf->len + 1 >= sizeof(buf->bytes)) | |||
| 53 | return NULL((void*)0); | |||
| 54 | buf->bytes[buf->len] = '\0'; | |||
| 55 | return buf->bytes; | |||
| 56 | } | |||
| 57 | ||||
| 58 | static bool_Bool linebuf_add(struct linebuf *buf, const char *s, size_t len) { | |||
| 59 | if (buf->len + len >= sizeof(buf->bytes)) | |||
| 60 | return false0; | |||
| 61 | memcpy(buf->bytes + buf->len, s, len); | |||
| 62 | buf->len += len; | |||
| 63 | return true1; | |||
| 64 | } | |||
| 65 | ||||
| 66 | static bool_Bool linebuf_add_char(struct linebuf *buf, char c) { | |||
| 67 | if (buf->len + 1 >= sizeof(buf->bytes)) | |||
| 68 | return false0; | |||
| 69 | buf->bytes[buf->len++] = c; | |||
| 70 | return true1; | |||
| 71 | } | |||
| 72 | ||||
| 73 | static void linebuf_rem(struct linebuf *buf, size_t count) { | |||
| 74 | assert(buf->len >= count)do { if ((__builtin_expect(!!(!(buf->len >= count)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("buf->len >= count" ), "../src/libsystemd/sd-hwdb/sd-hwdb.c", 74, __PRETTY_FUNCTION__ ); } while (0); | |||
| 75 | buf->len -= count; | |||
| 76 | } | |||
| 77 | ||||
| 78 | static void linebuf_rem_char(struct linebuf *buf) { | |||
| 79 | linebuf_rem(buf, 1); | |||
| 80 | } | |||
| 81 | ||||
| 82 | static const struct trie_child_entry_f *trie_node_child(sd_hwdb *hwdb, const struct trie_node_f *node, size_t idx) { | |||
| 83 | const char *base = (const char *)node; | |||
| 84 | ||||
| 85 | base += le64toh(hwdb->head->node_size); | |||
| 86 | base += idx * le64toh(hwdb->head->child_entry_size); | |||
| 87 | return (const struct trie_child_entry_f *)base; | |||
| 88 | } | |||
| 89 | ||||
| 90 | static const struct trie_value_entry_f *trie_node_value(sd_hwdb *hwdb, const struct trie_node_f *node, size_t idx) { | |||
| 91 | const char *base = (const char *)node; | |||
| 92 | ||||
| 93 | base += le64toh(hwdb->head->node_size); | |||
| 94 | base += node->children_count * le64toh(hwdb->head->child_entry_size); | |||
| 95 | base += idx * le64toh(hwdb->head->value_entry_size); | |||
| 96 | return (const struct trie_value_entry_f *)base; | |||
| 97 | } | |||
| 98 | ||||
| 99 | static const struct trie_node_f *trie_node_from_off(sd_hwdb *hwdb, le64_t off) { | |||
| 100 | return (const struct trie_node_f *)(hwdb->map + le64toh(off)); | |||
| 101 | } | |||
| 102 | ||||
| 103 | static const char *trie_string(sd_hwdb *hwdb, le64_t off) { | |||
| 104 | return hwdb->map + le64toh(off); | |||
| 105 | } | |||
| 106 | ||||
| 107 | static int trie_children_cmp_f(const void *v1, const void *v2) { | |||
| 108 | const struct trie_child_entry_f *n1 = v1; | |||
| 109 | const struct trie_child_entry_f *n2 = v2; | |||
| 110 | ||||
| 111 | return n1->c - n2->c; | |||
| 112 | } | |||
| 113 | ||||
| 114 | static const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) { | |||
| 115 | struct trie_child_entry_f *child; | |||
| 116 | struct trie_child_entry_f search; | |||
| 117 | ||||
| 118 | search.c = c; | |||
| 119 | child = bsearch(&search, (const char *)node + le64toh(hwdb->head->node_size), node->children_count, | |||
| 120 | le64toh(hwdb->head->child_entry_size), trie_children_cmp_f); | |||
| 121 | if (child) | |||
| 122 | return trie_node_from_off(hwdb, child->child_off); | |||
| 123 | return NULL((void*)0); | |||
| 124 | } | |||
| 125 | ||||
| 126 | static int hwdb_add_property(sd_hwdb *hwdb, const struct trie_value_entry_f *entry) { | |||
| 127 | const char *key; | |||
| 128 | int r; | |||
| 129 | ||||
| 130 | assert(hwdb)do { if ((__builtin_expect(!!(!(hwdb)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 130, __PRETTY_FUNCTION__); } while (0); | |||
| 131 | ||||
| 132 | key = trie_string(hwdb, entry->key_off); | |||
| 133 | ||||
| 134 | /* | |||
| 135 | * Silently ignore all properties which do not start with a | |||
| 136 | * space; future extensions might use additional prefixes. | |||
| 137 | */ | |||
| 138 | if (key[0] != ' ') | |||
| 139 | return 0; | |||
| 140 | ||||
| 141 | key++; | |||
| 142 | ||||
| 143 | if (le64toh(hwdb->head->value_entry_size) >= sizeof(struct trie_value_entry2_f)) { | |||
| 144 | const struct trie_value_entry2_f *old, *entry2; | |||
| 145 | ||||
| 146 | entry2 = (const struct trie_value_entry2_f *)entry; | |||
| 147 | old = ordered_hashmap_get(hwdb->properties, key); | |||
| 148 | if (old) { | |||
| 149 | /* On duplicates, we order by filename priority and line-number. | |||
| 150 | * | |||
| 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_Bool lower; | |||
| 173 | ||||
| 174 | if (entry2->file_priority == 0) | |||
| 175 | lower = entry2->filename_off < old->filename_off || | |||
| 176 | (entry2->filename_off == old->filename_off && entry2->line_number < old->line_number); | |||
| 177 | else | |||
| 178 | lower = entry2->file_priority < old->file_priority || | |||
| 179 | (entry2->file_priority == old->file_priority && entry2->line_number < old->line_number); | |||
| 180 | if (lower) | |||
| 181 | return 0; | |||
| 182 | } | |||
| 183 | } | |||
| 184 | ||||
| 185 | r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops)internal_ordered_hashmap_ensure_allocated(&hwdb->properties , &string_hash_ops ); | |||
| 186 | if (r < 0) | |||
| 187 | return r; | |||
| 188 | ||||
| 189 | r = ordered_hashmap_replace(hwdb->properties, key, (void *)entry); | |||
| 190 | if (r < 0) | |||
| 191 | return r; | |||
| 192 | ||||
| 193 | hwdb->properties_modified = true1; | |||
| 194 | ||||
| 195 | return 0; | |||
| 196 | } | |||
| 197 | ||||
| 198 | 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 | prefix = trie_string(hwdb, node->prefix_off); | |||
| 206 | len = strlen(prefix + p); | |||
| 207 | linebuf_add(buf, prefix + p, len); | |||
| 208 | ||||
| 209 | for (i = 0; i < node->children_count; i++) { | |||
| 210 | const struct trie_child_entry_f *child = trie_node_child(hwdb, node, i); | |||
| 211 | ||||
| 212 | linebuf_add_char(buf, child->c); | |||
| 213 | err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search); | |||
| 214 | if (err < 0) | |||
| 215 | return err; | |||
| 216 | linebuf_rem_char(buf); | |||
| 217 | } | |||
| 218 | ||||
| 219 | if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0) | |||
| 220 | for (i = 0; i < le64toh(node->values_count); i++) { | |||
| 221 | err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, i)); | |||
| 222 | if (err < 0) | |||
| 223 | return err; | |||
| 224 | } | |||
| 225 | ||||
| 226 | linebuf_rem(buf, len); | |||
| 227 | return 0; | |||
| 228 | } | |||
| 229 | ||||
| 230 | static int trie_search_f(sd_hwdb *hwdb, const char *search) { | |||
| 231 | struct linebuf buf; | |||
| 232 | const struct trie_node_f *node; | |||
| 233 | size_t i = 0; | |||
| 234 | int err; | |||
| 235 | ||||
| 236 | linebuf_init(&buf); | |||
| 237 | ||||
| 238 | node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off); | |||
| 239 | while (node) { | |||
| 240 | const struct trie_node_f *child; | |||
| 241 | size_t p = 0; | |||
| 242 | ||||
| 243 | if (node->prefix_off) { | |||
| 244 | uint8_t c; | |||
| 245 | ||||
| 246 | for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) { | |||
| 247 | if (IN_SET(c, '*', '?', '[')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){'*', '?', '['})/sizeof(int)]; switch(c) { case '*': case '?': case '[': _found = 1; break; default: break ; } _found; })) | |||
| 248 | return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p); | |||
| 249 | if (c != search[i + p]) | |||
| 250 | return 0; | |||
| 251 | } | |||
| 252 | i += p; | |||
| 253 | } | |||
| 254 | ||||
| 255 | child = node_lookup_f(hwdb, node, '*'); | |||
| 256 | if (child) { | |||
| 257 | linebuf_add_char(&buf, '*'); | |||
| 258 | err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); | |||
| 259 | if (err < 0) | |||
| 260 | return err; | |||
| 261 | linebuf_rem_char(&buf); | |||
| 262 | } | |||
| 263 | ||||
| 264 | child = node_lookup_f(hwdb, node, '?'); | |||
| 265 | if (child) { | |||
| 266 | linebuf_add_char(&buf, '?'); | |||
| 267 | err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); | |||
| 268 | if (err < 0) | |||
| 269 | return err; | |||
| 270 | linebuf_rem_char(&buf); | |||
| 271 | } | |||
| 272 | ||||
| 273 | child = node_lookup_f(hwdb, node, '['); | |||
| 274 | if (child) { | |||
| 275 | linebuf_add_char(&buf, '['); | |||
| 276 | err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); | |||
| 277 | if (err < 0) | |||
| 278 | return err; | |||
| 279 | linebuf_rem_char(&buf); | |||
| 280 | } | |||
| 281 | ||||
| 282 | if (search[i] == '\0') { | |||
| 283 | size_t n; | |||
| 284 | ||||
| 285 | for (n = 0; n < le64toh(node->values_count); n++) { | |||
| 286 | err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, n)); | |||
| 287 | if (err < 0) | |||
| 288 | return err; | |||
| 289 | } | |||
| 290 | return 0; | |||
| 291 | } | |||
| 292 | ||||
| 293 | child = node_lookup_f(hwdb, node, search[i]); | |||
| 294 | node = child; | |||
| 295 | i++; | |||
| 296 | } | |||
| 297 | 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_USR0 | |||
| 305 | "/lib/systemd/hwdb/hwdb.bin\0" | |||
| 306 | #endif | |||
| 307 | UDEVLIBEXECDIR"/usr/lib/udev" "/hwdb.bin\0"; | |||
| 308 | ||||
| 309 | _public___attribute__ ((visibility("default"))) int sd_hwdb_new(sd_hwdb **ret) { | |||
| 310 | _cleanup_(sd_hwdb_unrefp)__attribute__((cleanup(sd_hwdb_unrefp))) sd_hwdb *hwdb = NULL((void*)0); | |||
| 311 | const char *hwdb_bin_path; | |||
| 312 | const char sig[] = HWDB_SIG{ 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }; | |||
| 313 | ||||
| 314 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 314, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| ||||
| 315 | ||||
| 316 | hwdb = new0(sd_hwdb, 1)((sd_hwdb*) calloc((1), sizeof(sd_hwdb))); | |||
| 317 | if (!hwdb) | |||
| 318 | return -ENOMEM12; | |||
| 319 | ||||
| 320 | hwdb->n_ref = REFCNT_INIT((RefCount) { ._value = 1 }); | |||
| 321 | ||||
| 322 | /* find hwdb.bin in hwdb_bin_paths */ | |||
| 323 | NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths)for ((hwdb_bin_path) = (hwdb_bin_paths); (hwdb_bin_path) && *(hwdb_bin_path); (hwdb_bin_path) = strchr((hwdb_bin_path), 0 )+1) { | |||
| 324 | hwdb->f = fopen(hwdb_bin_path, "re"); | |||
| 325 | if (hwdb->f) | |||
| 326 | break; | |||
| 327 | else if (errno(*__errno_location ()) == ENOENT2) | |||
| 328 | continue; | |||
| 329 | else | |||
| 330 | return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libsystemd/sd-hwdb/sd-hwdb.c", 330 , __func__, "error reading %s: %m", hwdb_bin_path) : -abs(_e) ; }); | |||
| 331 | } | |||
| 332 | ||||
| 333 | if (!hwdb->f
| |||
| 334 | log_debug("hwdb.bin does not exist, please run systemd-hwdb update")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 334, __func__, "hwdb.bin does not exist, please run systemd-hwdb update" ) : -abs(_e); }); | |||
| ||||
| 335 | return -ENOENT2; | |||
| 336 | } | |||
| 337 | ||||
| 338 | if (fstat(fileno(hwdb->f), &hwdb->st) < 0 || | |||
| 339 | (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len)__builtin_offsetof(struct trie_header_f, strings_len) + 8) | |||
| 340 | return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libsystemd/sd-hwdb/sd-hwdb.c", 340 , __func__, "error reading %s: %m", hwdb_bin_path) : -abs(_e) ; }); | |||
| 341 | ||||
| 342 | hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ0x1, MAP_SHARED0x01, fileno(hwdb->f), 0); | |||
| 343 | if (hwdb->map == MAP_FAILED((void *) -1)) | |||
| 344 | return log_debug_errno(errno, "error mapping %s: %m", hwdb_bin_path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/libsystemd/sd-hwdb/sd-hwdb.c", 344 , __func__, "error mapping %s: %m", hwdb_bin_path) : -abs(_e) ; }); | |||
| 345 | ||||
| 346 | if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 || | |||
| 347 | (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) { | |||
| 348 | log_debug("error recognizing the format of %s", hwdb_bin_path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 348, __func__, "error recognizing the format of %s" , hwdb_bin_path) : -abs(_e); }); | |||
| 349 | return -EINVAL22; | |||
| 350 | } | |||
| 351 | ||||
| 352 | log_debug("=== trie on-disk ===")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 352, __func__, "=== trie on-disk ===" ) : -abs(_e); }); | |||
| 353 | log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 353, __func__, "tool version: %" "l" "u", le64toh(hwdb->head->tool_version)) : -abs(_e); }); | |||
| 354 | log_debug("file size: %8"PRIi64" bytes", hwdb->st.st_size)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 354, __func__, "file size: %8" "l" "i"" bytes", hwdb->st.st_size) : -abs(_e); }); | |||
| 355 | log_debug("header size %8"PRIu64" bytes", le64toh(hwdb->head->header_size))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 355, __func__, "header size %8" "l" "u"" bytes", le64toh(hwdb->head->header_size)) : -abs (_e); }); | |||
| 356 | log_debug("strings %8"PRIu64" bytes", le64toh(hwdb->head->strings_len))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 356, __func__, "strings %8" "l" "u"" bytes", le64toh(hwdb->head->strings_len)) : -abs (_e); }); | |||
| 357 | log_debug("nodes %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-hwdb/sd-hwdb.c", 357, __func__, "nodes %8" "l" "u"" bytes", le64toh(hwdb->head->nodes_len)) : -abs (_e); }); | |||
| 358 | ||||
| 359 | *ret = TAKE_PTR(hwdb)({ typeof(hwdb) _ptr_ = (hwdb); (hwdb) = ((void*)0); _ptr_; } ); | |||
| 360 | ||||
| 361 | return 0; | |||
| 362 | } | |||
| 363 | ||||
| 364 | _public___attribute__ ((visibility("default"))) sd_hwdb *sd_hwdb_ref(sd_hwdb *hwdb) { | |||
| 365 | assert_return(hwdb, NULL)do { if (!(((__builtin_expect(!!(hwdb),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 365, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 366 | ||||
| 367 | assert_se(REFCNT_INC(hwdb->n_ref) >= 2)do { if ((__builtin_expect(!!(!((__sync_add_and_fetch(&(hwdb ->n_ref)._value, 1)) >= 2)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("REFCNT_INC(hwdb->n_ref) >= 2"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 367, __PRETTY_FUNCTION__); } while (0); | |||
| 368 | ||||
| 369 | return hwdb; | |||
| 370 | } | |||
| 371 | ||||
| 372 | _public___attribute__ ((visibility("default"))) sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) { | |||
| 373 | if (hwdb && REFCNT_DEC(hwdb->n_ref)(__sync_sub_and_fetch(&(hwdb->n_ref)._value, 1)) == 0) { | |||
| 374 | if (hwdb->map) | |||
| 375 | munmap((void *)hwdb->map, hwdb->st.st_size); | |||
| 376 | safe_fclose(hwdb->f); | |||
| 377 | ordered_hashmap_free(hwdb->properties); | |||
| 378 | free(hwdb); | |||
| 379 | } | |||
| 380 | ||||
| 381 | return NULL((void*)0); | |||
| 382 | } | |||
| 383 | ||||
| 384 | bool_Bool hwdb_validate(sd_hwdb *hwdb) { | |||
| 385 | bool_Bool found = false0; | |||
| 386 | const char* p; | |||
| 387 | struct stat st; | |||
| 388 | ||||
| 389 | if (!hwdb) | |||
| 390 | return false0; | |||
| 391 | if (!hwdb->f) | |||
| 392 | return false0; | |||
| 393 | ||||
| 394 | /* if hwdb.bin doesn't exist anywhere, we need to update */ | |||
| 395 | NULSTR_FOREACH(p, hwdb_bin_paths)for ((p) = (hwdb_bin_paths); (p) && *(p); (p) = strchr ((p), 0)+1) { | |||
| 396 | if (stat(p, &st) >= 0) { | |||
| 397 | found = true1; | |||
| 398 | break; | |||
| 399 | } | |||
| 400 | } | |||
| 401 | if (!found) | |||
| 402 | return true1; | |||
| 403 | ||||
| 404 | if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim)) | |||
| 405 | return true1; | |||
| 406 | return false0; | |||
| 407 | } | |||
| 408 | ||||
| 409 | static int properties_prepare(sd_hwdb *hwdb, const char *modalias) { | |||
| 410 | assert(hwdb)do { if ((__builtin_expect(!!(!(hwdb)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 410, __PRETTY_FUNCTION__); } while (0); | |||
| 411 | assert(modalias)do { if ((__builtin_expect(!!(!(modalias)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("modalias"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 411, __PRETTY_FUNCTION__); } while (0); | |||
| 412 | ||||
| 413 | ordered_hashmap_clear(hwdb->properties); | |||
| 414 | hwdb->properties_modified = true1; | |||
| 415 | ||||
| 416 | return trie_search_f(hwdb, modalias); | |||
| 417 | } | |||
| 418 | ||||
| 419 | _public___attribute__ ((visibility("default"))) int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) { | |||
| 420 | const struct trie_value_entry_f *entry; | |||
| 421 | int r; | |||
| 422 | ||||
| 423 | assert_return(hwdb, -EINVAL)do { if (!(((__builtin_expect(!!(hwdb),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 423, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 424 | assert_return(hwdb->f, -EINVAL)do { if (!(((__builtin_expect(!!(hwdb->f),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb->f"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 424, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 425 | assert_return(modalias, -EINVAL)do { if (!(((__builtin_expect(!!(modalias),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("modalias"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 425, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 426 | assert_return(_value, -EINVAL)do { if (!(((__builtin_expect(!!(_value),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("_value"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 426, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 427 | ||||
| 428 | r = properties_prepare(hwdb, modalias); | |||
| 429 | if (r < 0) | |||
| 430 | return r; | |||
| 431 | ||||
| 432 | entry = ordered_hashmap_get(hwdb->properties, key); | |||
| 433 | if (!entry) | |||
| 434 | return -ENOENT2; | |||
| 435 | ||||
| 436 | *_value = trie_string(hwdb, entry->value_off); | |||
| 437 | ||||
| 438 | return 0; | |||
| 439 | } | |||
| 440 | ||||
| 441 | _public___attribute__ ((visibility("default"))) int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) { | |||
| 442 | int r; | |||
| 443 | ||||
| 444 | assert_return(hwdb, -EINVAL)do { if (!(((__builtin_expect(!!(hwdb),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 444, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 445 | assert_return(hwdb->f, -EINVAL)do { if (!(((__builtin_expect(!!(hwdb->f),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb->f"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 445, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 446 | assert_return(modalias, -EINVAL)do { if (!(((__builtin_expect(!!(modalias),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("modalias"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 446, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 447 | ||||
| 448 | r = properties_prepare(hwdb, modalias); | |||
| 449 | if (r < 0) | |||
| 450 | return r; | |||
| 451 | ||||
| 452 | hwdb->properties_modified = false0; | |||
| 453 | hwdb->properties_iterator = ITERATOR_FIRST((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .next_key = ( (void*)0) }); | |||
| 454 | ||||
| 455 | return 0; | |||
| 456 | } | |||
| 457 | ||||
| 458 | _public___attribute__ ((visibility("default"))) int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) { | |||
| 459 | const struct trie_value_entry_f *entry; | |||
| 460 | const void *k; | |||
| 461 | ||||
| 462 | assert_return(hwdb, -EINVAL)do { if (!(((__builtin_expect(!!(hwdb),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("hwdb"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 462, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 463 | assert_return(key, -EINVAL)do { if (!(((__builtin_expect(!!(key),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("key"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 463, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 464 | assert_return(value, -EINVAL)do { if (!(((__builtin_expect(!!(value),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("value"), "../src/libsystemd/sd-hwdb/sd-hwdb.c" , 464, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 465 | ||||
| 466 | if (hwdb->properties_modified) | |||
| 467 | return -EAGAIN11; | |||
| 468 | ||||
| 469 | ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, (void **)&entry, &k); | |||
| 470 | if (!k) | |||
| 471 | return 0; | |||
| 472 | ||||
| 473 | *key = k; | |||
| 474 | *value = trie_string(hwdb, entry->value_off); | |||
| 475 | ||||
| 476 | return 1; | |||
| 477 | } |