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 | } |