File: | build-scan/../src/journal/catalog.c |
Warning: | line 491, column 32 Potential leak of memory pointed to by 'items' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <fcntl.h> | |||
5 | #include <locale.h> | |||
6 | #include <stdio.h> | |||
7 | #include <string.h> | |||
8 | #include <sys/mman.h> | |||
9 | #include <unistd.h> | |||
10 | ||||
11 | #include "sd-id128.h" | |||
12 | ||||
13 | #include "alloc-util.h" | |||
14 | #include "catalog.h" | |||
15 | #include "conf-files.h" | |||
16 | #include "fd-util.h" | |||
17 | #include "fileio.h" | |||
18 | #include "hashmap.h" | |||
19 | #include "log.h" | |||
20 | #include "mkdir.h" | |||
21 | #include "path-util.h" | |||
22 | #include "siphash24.h" | |||
23 | #include "sparse-endian.h" | |||
24 | #include "strbuf.h" | |||
25 | #include "string-util.h" | |||
26 | #include "strv.h" | |||
27 | #include "util.h" | |||
28 | ||||
29 | const char * const catalog_file_dirs[] = { | |||
30 | "/usr/local/lib/systemd/catalog/", | |||
31 | "/usr/lib/systemd/catalog/", | |||
32 | NULL((void*)0) | |||
33 | }; | |||
34 | ||||
35 | #define CATALOG_SIGNATURE(uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' } (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' } | |||
36 | ||||
37 | typedef struct CatalogHeader { | |||
38 | uint8_t signature[8]; /* "RHHHKSLP" */ | |||
39 | le32_t compatible_flags; | |||
40 | le32_t incompatible_flags; | |||
41 | le64_t header_size; | |||
42 | le64_t n_items; | |||
43 | le64_t catalog_item_size; | |||
44 | } CatalogHeader; | |||
45 | ||||
46 | typedef struct CatalogItem { | |||
47 | sd_id128_t id; | |||
48 | char language[32]; | |||
49 | le64_t offset; | |||
50 | } CatalogItem; | |||
51 | ||||
52 | static void catalog_hash_func(const void *p, struct siphash *state) { | |||
53 | const CatalogItem *i = p; | |||
54 | ||||
55 | siphash24_compress(&i->id, sizeof(i->id), state); | |||
56 | siphash24_compress(i->language, strlen(i->language), state); | |||
57 | } | |||
58 | ||||
59 | static int catalog_compare_func(const void *a, const void *b) { | |||
60 | const CatalogItem *i = a, *j = b; | |||
61 | unsigned k; | |||
62 | ||||
63 | for (k = 0; k < ELEMENTSOF(j->id.bytes)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(j->id.bytes), typeof(&*(j->id.bytes))), sizeof (j->id.bytes)/sizeof((j->id.bytes)[0]), ((void)0))); k++) { | |||
64 | if (i->id.bytes[k] < j->id.bytes[k]) | |||
65 | return -1; | |||
66 | if (i->id.bytes[k] > j->id.bytes[k]) | |||
67 | return 1; | |||
68 | } | |||
69 | ||||
70 | return strcmp(i->language, j->language); | |||
71 | } | |||
72 | ||||
73 | const struct hash_ops catalog_hash_ops = { | |||
74 | .hash = catalog_hash_func, | |||
75 | .compare = catalog_compare_func | |||
76 | }; | |||
77 | ||||
78 | static bool_Bool next_header(const char **s) { | |||
79 | const char *e; | |||
80 | ||||
81 | e = strchr(*s, '\n'); | |||
82 | ||||
83 | /* Unexpected end */ | |||
84 | if (!e) | |||
85 | return false0; | |||
86 | ||||
87 | /* End of headers */ | |||
88 | if (e == *s) | |||
89 | return false0; | |||
90 | ||||
91 | *s = e + 1; | |||
92 | return true1; | |||
93 | } | |||
94 | ||||
95 | static const char *skip_header(const char *s) { | |||
96 | while (next_header(&s)) | |||
97 | ; | |||
98 | return s; | |||
99 | } | |||
100 | ||||
101 | static char *combine_entries(const char *one, const char *two) { | |||
102 | const char *b1, *b2; | |||
103 | size_t l1, l2, n; | |||
104 | char *dest, *p; | |||
105 | ||||
106 | /* Find split point of headers to body */ | |||
107 | b1 = skip_header(one); | |||
108 | b2 = skip_header(two); | |||
109 | ||||
110 | l1 = strlen(one); | |||
111 | l2 = strlen(two); | |||
112 | dest = new(char, l1 + l2 + 1)((char*) malloc_multiply(sizeof(char), (l1 + l2 + 1))); | |||
113 | if (!dest) { | |||
114 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 114, __func__); | |||
115 | return NULL((void*)0); | |||
116 | } | |||
117 | ||||
118 | p = dest; | |||
119 | ||||
120 | /* Headers from @one */ | |||
121 | n = b1 - one; | |||
122 | p = mempcpy(p, one, n); | |||
123 | ||||
124 | /* Headers from @two, these will only be found if not present above */ | |||
125 | n = b2 - two; | |||
126 | p = mempcpy(p, two, n); | |||
127 | ||||
128 | /* Body from @one */ | |||
129 | n = l1 - (b1 - one); | |||
130 | if (n > 0) { | |||
131 | memcpy(p, b1, n); | |||
132 | p += n; | |||
133 | ||||
134 | /* Body from @two */ | |||
135 | } else { | |||
136 | n = l2 - (b2 - two); | |||
137 | memcpy(p, b2, n); | |||
138 | p += n; | |||
139 | } | |||
140 | ||||
141 | assert(p - dest <= (ptrdiff_t)(l1 + l2))do { if ((__builtin_expect(!!(!(p - dest <= (ptrdiff_t)(l1 + l2))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("p - dest <= (ptrdiff_t)(l1 + l2)" ), "../src/journal/catalog.c", 141, __PRETTY_FUNCTION__); } while (0); | |||
142 | p[0] = '\0'; | |||
143 | return dest; | |||
144 | } | |||
145 | ||||
146 | static int finish_item( | |||
147 | Hashmap *h, | |||
148 | sd_id128_t id, | |||
149 | const char *language, | |||
150 | char *payload, size_t payload_size) { | |||
151 | ||||
152 | _cleanup_free___attribute__((cleanup(freep))) CatalogItem *i = NULL((void*)0); | |||
153 | _cleanup_free___attribute__((cleanup(freep))) char *prev = NULL((void*)0), *combined = NULL((void*)0); | |||
154 | ||||
155 | assert(h)do { if ((__builtin_expect(!!(!(h)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("h"), "../src/journal/catalog.c", 155, __PRETTY_FUNCTION__ ); } while (0); | |||
156 | assert(payload)do { if ((__builtin_expect(!!(!(payload)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("payload"), "../src/journal/catalog.c", 156 , __PRETTY_FUNCTION__); } while (0); | |||
157 | assert(payload_size > 0)do { if ((__builtin_expect(!!(!(payload_size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("payload_size > 0"), "../src/journal/catalog.c" , 157, __PRETTY_FUNCTION__); } while (0); | |||
158 | ||||
159 | i = new0(CatalogItem, 1)((CatalogItem*) calloc((1), sizeof(CatalogItem))); | |||
160 | if (!i) | |||
161 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 161, __func__); | |||
162 | ||||
163 | i->id = id; | |||
164 | if (language) { | |||
165 | assert(strlen(language) > 1 && strlen(language) < 32)do { if ((__builtin_expect(!!(!(strlen(language) > 1 && strlen(language) < 32)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("strlen(language) > 1 && strlen(language) < 32" ), "../src/journal/catalog.c", 165, __PRETTY_FUNCTION__); } while (0); | |||
166 | strcpy(i->language, language); | |||
167 | } | |||
168 | ||||
169 | prev = hashmap_get(h, i); | |||
170 | if (prev) { | |||
171 | /* Already have such an item, combine them */ | |||
172 | combined = combine_entries(payload, prev); | |||
173 | if (!combined) | |||
174 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 174, __func__); | |||
175 | ||||
176 | if (hashmap_update(h, i, combined) < 0) | |||
177 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 177, __func__); | |||
178 | combined = NULL((void*)0); | |||
179 | } else { | |||
180 | /* A new item */ | |||
181 | combined = memdup(payload, payload_size + 1); | |||
182 | if (!combined) | |||
183 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 183, __func__); | |||
184 | ||||
185 | if (hashmap_put(h, i, combined) < 0) | |||
186 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 186, __func__); | |||
187 | i = NULL((void*)0); | |||
188 | combined = NULL((void*)0); | |||
189 | } | |||
190 | ||||
191 | return 0; | |||
192 | } | |||
193 | ||||
194 | int catalog_file_lang(const char* filename, char **lang) { | |||
195 | char *beg, *end, *_lang; | |||
196 | ||||
197 | end = endswith(filename, ".catalog"); | |||
198 | if (!end) | |||
199 | return 0; | |||
200 | ||||
201 | beg = end - 1; | |||
202 | while (beg > filename && !IN_SET(*beg, '.', '/')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){'.', '/'})/sizeof(int)]; switch(*beg) { case '.': case '/': _found = 1; break; default: break; } _found; } ) && end - beg < 32) | |||
203 | beg--; | |||
204 | ||||
205 | if (*beg != '.' || end <= beg + 1) | |||
206 | return 0; | |||
207 | ||||
208 | _lang = strndup(beg + 1, end - beg - 1); | |||
209 | if (!_lang) | |||
210 | return -ENOMEM12; | |||
211 | ||||
212 | *lang = _lang; | |||
213 | return 1; | |||
214 | } | |||
215 | ||||
216 | static int catalog_entry_lang(const char* filename, int line, | |||
217 | const char* t, const char* deflang, char **lang) { | |||
218 | size_t c; | |||
219 | ||||
220 | c = strlen(t); | |||
221 | if (c == 0) { | |||
222 | log_error("[%s:%u] Language too short.", filename, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 222, __func__, "[%s:%u] Language too short." , filename, line) : -abs(_e); }); | |||
223 | return -EINVAL22; | |||
224 | } | |||
225 | if (c > 31) { | |||
226 | log_error("[%s:%u] language too long.", filename, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 226, __func__, "[%s:%u] language too long." , filename, line) : -abs(_e); }); | |||
227 | return -EINVAL22; | |||
228 | } | |||
229 | ||||
230 | if (deflang) { | |||
231 | if (streq(t, deflang)(strcmp((t),(deflang)) == 0)) { | |||
232 | log_warning("[%s:%u] language specified unnecessarily",({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 233, __func__, "[%s:%u] language specified unnecessarily" , filename, line) : -abs(_e); }) | |||
233 | filename, line)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 233, __func__, "[%s:%u] language specified unnecessarily" , filename, line) : -abs(_e); }); | |||
234 | return 0; | |||
235 | } else | |||
236 | log_warning("[%s:%u] language differs from default for file",({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 237, __func__, "[%s:%u] language differs from default for file" , filename, line) : -abs(_e); }) | |||
237 | filename, line)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 237, __func__, "[%s:%u] language differs from default for file" , filename, line) : -abs(_e); }); | |||
238 | } | |||
239 | ||||
240 | *lang = strdup(t); | |||
241 | if (!*lang) | |||
242 | return -ENOMEM12; | |||
243 | ||||
244 | return 0; | |||
245 | } | |||
246 | ||||
247 | int catalog_import_file(Hashmap *h, const char *path) { | |||
248 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
249 | _cleanup_free___attribute__((cleanup(freep))) char *payload = NULL((void*)0); | |||
250 | size_t payload_size = 0, payload_allocated = 0; | |||
251 | unsigned n = 0; | |||
252 | sd_id128_t id; | |||
253 | _cleanup_free___attribute__((cleanup(freep))) char *deflang = NULL((void*)0), *lang = NULL((void*)0); | |||
254 | bool_Bool got_id = false0, empty_line = true1; | |||
255 | int r; | |||
256 | ||||
257 | assert(h)do { if ((__builtin_expect(!!(!(h)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("h"), "../src/journal/catalog.c", 257, __PRETTY_FUNCTION__ ); } while (0); | |||
258 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/journal/catalog.c", 258 , __PRETTY_FUNCTION__); } while (0); | |||
259 | ||||
260 | f = fopen(path, "re"); | |||
261 | if (!f) | |||
262 | return log_error_errno(errno, "Failed to open file %s: %m", path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/catalog.c", 262, __func__ , "Failed to open file %s: %m", path) : -abs(_e); }); | |||
263 | ||||
264 | r = catalog_file_lang(path, &deflang); | |||
265 | if (r < 0) | |||
266 | log_error_errno(r, "Failed to determine language for file %s: %m", path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 266, __func__, "Failed to determine language for file %s: %m" , path) : -abs(_e); }); | |||
267 | if (r == 1) | |||
268 | log_debug("File %s has language %s.", path, deflang)({ 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/journal/catalog.c", 268, __func__, "File %s has language %s." , path, deflang) : -abs(_e); }); | |||
269 | ||||
270 | for (;;) { | |||
271 | char line[LINE_MAX2048]; | |||
272 | size_t line_len; | |||
273 | ||||
274 | if (!fgets(line, sizeof(line), f)) { | |||
275 | if (feof(f)) | |||
276 | break; | |||
277 | ||||
278 | return log_error_errno(errno, "Failed to read file %s: %m", path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/catalog.c", 278, __func__ , "Failed to read file %s: %m", path) : -abs(_e); }); | |||
279 | } | |||
280 | ||||
281 | n++; | |||
282 | ||||
283 | truncate_nl(line); | |||
284 | ||||
285 | if (line[0] == 0) { | |||
286 | empty_line = true1; | |||
287 | continue; | |||
288 | } | |||
289 | ||||
290 | if (strchr(COMMENTS"#;" "\n", line[0])) | |||
291 | continue; | |||
292 | ||||
293 | if (empty_line && | |||
294 | strlen(line) >= 2+1+32 && | |||
295 | line[0] == '-' && | |||
296 | line[1] == '-' && | |||
297 | line[2] == ' ' && | |||
298 | IN_SET(line[2+1+32], ' ', '\0')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){' ', '\0'})/sizeof(int)]; switch(line[2+ 1+32]) { case ' ': case '\0': _found = 1; break; default: break ; } _found; })) { | |||
299 | ||||
300 | bool_Bool with_language; | |||
301 | sd_id128_t jd; | |||
302 | ||||
303 | /* New entry */ | |||
304 | ||||
305 | with_language = line[2+1+32] != '\0'; | |||
306 | line[2+1+32] = '\0'; | |||
307 | ||||
308 | if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { | |||
309 | ||||
310 | if (got_id) { | |||
311 | if (payload_size == 0) { | |||
312 | log_error("[%s:%u] No payload text.", path, n)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 312, __func__, "[%s:%u] No payload text." , path, n) : -abs(_e); }); | |||
313 | return -EINVAL22; | |||
314 | } | |||
315 | ||||
316 | r = finish_item(h, id, lang ?: deflang, payload, payload_size); | |||
317 | if (r < 0) | |||
318 | return r; | |||
319 | ||||
320 | lang = mfree(lang); | |||
321 | payload_size = 0; | |||
322 | } | |||
323 | ||||
324 | if (with_language) { | |||
325 | char *t; | |||
326 | ||||
327 | t = strstrip(line + 2 + 1 + 32 + 1); | |||
328 | r = catalog_entry_lang(path, n, t, deflang, &lang); | |||
329 | if (r < 0) | |||
330 | return r; | |||
331 | } | |||
332 | ||||
333 | got_id = true1; | |||
334 | empty_line = false0; | |||
335 | id = jd; | |||
336 | ||||
337 | continue; | |||
338 | } | |||
339 | } | |||
340 | ||||
341 | /* Payload */ | |||
342 | if (!got_id) { | |||
343 | log_error("[%s:%u] Got payload before ID.", path, n)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 343, __func__, "[%s:%u] Got payload before ID." , path, n) : -abs(_e); }); | |||
344 | return -EINVAL22; | |||
345 | } | |||
346 | ||||
347 | line_len = strlen(line); | |||
348 | if (!GREEDY_REALLOC(payload, payload_allocated,greedy_realloc((void**) &(payload), &(payload_allocated ), (payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1), sizeof ((payload)[0])) | |||
349 | payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1)greedy_realloc((void**) &(payload), &(payload_allocated ), (payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1), sizeof ((payload)[0]))) | |||
350 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 350, __func__); | |||
351 | ||||
352 | if (empty_line) | |||
353 | payload[payload_size++] = '\n'; | |||
354 | memcpy(payload + payload_size, line, line_len); | |||
355 | payload_size += line_len; | |||
356 | payload[payload_size++] = '\n'; | |||
357 | payload[payload_size] = '\0'; | |||
358 | ||||
359 | empty_line = false0; | |||
360 | } | |||
361 | ||||
362 | if (got_id) { | |||
363 | if (payload_size == 0) { | |||
364 | log_error("[%s:%u] No payload text.", path, n)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 364, __func__, "[%s:%u] No payload text." , path, n) : -abs(_e); }); | |||
365 | return -EINVAL22; | |||
366 | } | |||
367 | ||||
368 | r = finish_item(h, id, lang ?: deflang, payload, payload_size); | |||
369 | if (r < 0) | |||
370 | return r; | |||
371 | } | |||
372 | ||||
373 | return 0; | |||
374 | } | |||
375 | ||||
376 | static int64_t write_catalog(const char *database, struct strbuf *sb, | |||
377 | CatalogItem *items, size_t n) { | |||
378 | CatalogHeader header; | |||
379 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *w = NULL((void*)0); | |||
380 | int r; | |||
381 | _cleanup_free___attribute__((cleanup(freep))) char *d, *p = NULL((void*)0); | |||
382 | size_t k; | |||
383 | ||||
384 | d = dirname_malloc(database); | |||
385 | if (!d) | |||
386 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 386, __func__); | |||
387 | ||||
388 | r = mkdir_p(d, 0775); | |||
389 | if (r < 0) | |||
390 | return log_error_errno(r, "Recursive mkdir %s: %m", d)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 390, __func__, "Recursive mkdir %s: %m" , d) : -abs(_e); }); | |||
391 | ||||
392 | r = fopen_temporary(database, &w, &p); | |||
393 | if (r < 0) | |||
394 | return log_error_errno(r, "Failed to open database for writing: %s: %m",({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 395, __func__, "Failed to open database for writing: %s: %m" , database) : -abs(_e); }) | |||
395 | database)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 395, __func__, "Failed to open database for writing: %s: %m" , database) : -abs(_e); }); | |||
396 | ||||
397 | zero(header)(({ size_t _l_ = (sizeof(header)); void *_x_ = (&(header) ); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
398 | memcpy(header.signature, CATALOG_SIGNATURE(uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }, sizeof(header.signature)); | |||
399 | header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8)); | |||
400 | header.catalog_item_size = htole64(sizeof(CatalogItem)); | |||
401 | header.n_items = htole64(n); | |||
402 | ||||
403 | r = -EIO5; | |||
404 | ||||
405 | k = fwrite(&header, 1, sizeof(header), w); | |||
406 | if (k != sizeof(header)) { | |||
407 | log_error("%s: failed to write header.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 407, __func__, "%s: failed to write header." , p) : -abs(_e); }); | |||
408 | goto error; | |||
409 | } | |||
410 | ||||
411 | k = fwrite(items, 1, n * sizeof(CatalogItem), w); | |||
412 | if (k != n * sizeof(CatalogItem)) { | |||
413 | log_error("%s: failed to write database.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 413, __func__, "%s: failed to write database." , p) : -abs(_e); }); | |||
414 | goto error; | |||
415 | } | |||
416 | ||||
417 | k = fwrite(sb->buf, 1, sb->len, w); | |||
418 | if (k != sb->len) { | |||
419 | log_error("%s: failed to write strings.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 419, __func__, "%s: failed to write strings." , p) : -abs(_e); }); | |||
420 | goto error; | |||
421 | } | |||
422 | ||||
423 | r = fflush_and_check(w); | |||
424 | if (r < 0) { | |||
425 | log_error_errno(r, "%s: failed to write database: %m", p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 425, __func__, "%s: failed to write database: %m" , p) : -abs(_e); }); | |||
426 | goto error; | |||
427 | } | |||
428 | ||||
429 | fchmod(fileno(w), 0644); | |||
430 | ||||
431 | if (rename(p, database) < 0) { | |||
432 | r = log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/journal/catalog.c", 432, __func__ , "rename (%s -> %s) failed: %m", p, database) : -abs(_e); }); | |||
433 | goto error; | |||
434 | } | |||
435 | ||||
436 | return ftello(w); | |||
437 | ||||
438 | error: | |||
439 | (void) unlink(p); | |||
440 | return r; | |||
441 | } | |||
442 | ||||
443 | int catalog_update(const char* database, const char* root, const char* const* dirs) { | |||
444 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **files = NULL((void*)0); | |||
445 | char **f; | |||
446 | _cleanup_(strbuf_cleanupp)__attribute__((cleanup(strbuf_cleanupp))) struct strbuf *sb = NULL((void*)0); | |||
447 | _cleanup_hashmap_free_free_free___attribute__((cleanup(hashmap_free_free_freep))) Hashmap *h = NULL((void*)0); | |||
448 | _cleanup_free___attribute__((cleanup(freep))) CatalogItem *items = NULL((void*)0); | |||
449 | ssize_t offset; | |||
450 | char *payload; | |||
451 | CatalogItem *i; | |||
452 | Iterator j; | |||
453 | unsigned n; | |||
454 | int r; | |||
455 | int64_t sz; | |||
456 | ||||
457 | h = hashmap_new(&catalog_hash_ops)internal_hashmap_new(&catalog_hash_ops ); | |||
458 | sb = strbuf_new(); | |||
459 | if (!h || !sb) | |||
| ||||
460 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 460, __func__); | |||
461 | ||||
462 | r = conf_files_list_strv(&files, ".catalog", root, 0, dirs); | |||
463 | if (r < 0) | |||
464 | return log_error_errno(r, "Failed to get catalog files: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 464, __func__, "Failed to get catalog files: %m" ) : -abs(_e); }); | |||
465 | ||||
466 | STRV_FOREACH(f, files)for ((f) = (files); (f) && *(f); (f)++) { | |||
467 | log_debug("Reading file '%s'", *f)({ 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/journal/catalog.c", 467, __func__, "Reading file '%s'" , *f) : -abs(_e); }); | |||
468 | r = catalog_import_file(h, *f); | |||
469 | if (r < 0) | |||
470 | return log_error_errno(r, "Failed to import file '%s': %m", *f)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 470, __func__, "Failed to import file '%s': %m" , *f) : -abs(_e); }); | |||
471 | } | |||
472 | ||||
473 | if (hashmap_size(h) <= 0) { | |||
474 | log_info("No items in catalog.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 474, __func__, "No items in catalog." ) : -abs(_e); }); | |||
475 | return 0; | |||
476 | } else | |||
477 | log_debug("Found %u items in catalog.", hashmap_size(h))({ 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/journal/catalog.c", 477, __func__, "Found %u items in catalog." , hashmap_size(h)) : -abs(_e); }); | |||
478 | ||||
479 | items = new(CatalogItem, hashmap_size(h))((CatalogItem*) malloc_multiply(sizeof(CatalogItem), (hashmap_size (h)))); | |||
480 | if (!items) | |||
481 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 481, __func__); | |||
482 | ||||
483 | n = 0; | |||
484 | HASHMAP_FOREACH_KEY(payload, i, h, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((h), &(j), (void **)&(payload), (const void**) &(i)); ) { | |||
485 | log_debug("Found " SD_ID128_FORMAT_STR ", language %s",({ 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/journal/catalog.c", 487, __func__, "Found " "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ", language %s", (i->id).bytes[0], (i->id).bytes[1], ( i->id).bytes[2], (i->id).bytes[3], (i->id).bytes[4], (i->id).bytes[5], (i->id).bytes[6], (i->id).bytes[7 ], (i->id).bytes[8], (i->id).bytes[9], (i->id).bytes [10], (i->id).bytes[11], (i->id).bytes[12], (i->id). bytes[13], (i->id).bytes[14], (i->id).bytes[15], isempty (i->language) ? "C" : i->language) : -abs(_e); }) | |||
486 | SD_ID128_FORMAT_VAL(i->id),({ 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/journal/catalog.c", 487, __func__, "Found " "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ", language %s", (i->id).bytes[0], (i->id).bytes[1], ( i->id).bytes[2], (i->id).bytes[3], (i->id).bytes[4], (i->id).bytes[5], (i->id).bytes[6], (i->id).bytes[7 ], (i->id).bytes[8], (i->id).bytes[9], (i->id).bytes [10], (i->id).bytes[11], (i->id).bytes[12], (i->id). bytes[13], (i->id).bytes[14], (i->id).bytes[15], isempty (i->language) ? "C" : i->language) : -abs(_e); }) | |||
487 | isempty(i->language) ? "C" : i->language)({ 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/journal/catalog.c", 487, __func__, "Found " "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ", language %s", (i->id).bytes[0], (i->id).bytes[1], ( i->id).bytes[2], (i->id).bytes[3], (i->id).bytes[4], (i->id).bytes[5], (i->id).bytes[6], (i->id).bytes[7 ], (i->id).bytes[8], (i->id).bytes[9], (i->id).bytes [10], (i->id).bytes[11], (i->id).bytes[12], (i->id). bytes[13], (i->id).bytes[14], (i->id).bytes[15], isempty (i->language) ? "C" : i->language) : -abs(_e); }); | |||
488 | ||||
489 | offset = strbuf_add_string(sb, payload, strlen(payload)); | |||
490 | if (offset < 0) | |||
491 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/journal/catalog.c" , 491, __func__); | |||
| ||||
492 | ||||
493 | i->offset = htole64((uint64_t) offset); | |||
494 | items[n++] = *i; | |||
495 | } | |||
496 | ||||
497 | assert(n == hashmap_size(h))do { if ((__builtin_expect(!!(!(n == hashmap_size(h))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("n == hashmap_size(h)"), "../src/journal/catalog.c" , 497, __PRETTY_FUNCTION__); } while (0); | |||
498 | qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func); | |||
499 | ||||
500 | strbuf_complete(sb); | |||
501 | ||||
502 | sz = write_catalog(database, sb, items, n); | |||
503 | if (sz < 0) | |||
504 | return log_error_errno(sz, "Failed to write %s: %m", database)({ int _level = ((3)), _e = ((sz)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 504, __func__, "Failed to write %s: %m" , database) : -abs(_e); }); | |||
505 | ||||
506 | log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total 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/journal/catalog.c", 507, __func__, "%s: wrote %u items, with %zu bytes of strings, %" "l" "i"" total size.", database, n, sb->len, sz) : -abs(_e ); }) | |||
507 | database, n, sb->len, sz)({ 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/journal/catalog.c", 507, __func__, "%s: wrote %u items, with %zu bytes of strings, %" "l" "i"" total size.", database, n, sb->len, sz) : -abs(_e ); }); | |||
508 | return 0; | |||
509 | } | |||
510 | ||||
511 | static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) { | |||
512 | const CatalogHeader *h; | |||
513 | int fd; | |||
514 | void *p; | |||
515 | struct stat st; | |||
516 | ||||
517 | assert(_fd)do { if ((__builtin_expect(!!(!(_fd)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_fd"), "../src/journal/catalog.c", 517, __PRETTY_FUNCTION__); } while (0); | |||
518 | assert(_st)do { if ((__builtin_expect(!!(!(_st)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_st"), "../src/journal/catalog.c", 518, __PRETTY_FUNCTION__); } while (0); | |||
519 | assert(_p)do { if ((__builtin_expect(!!(!(_p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_p"), "../src/journal/catalog.c", 519, __PRETTY_FUNCTION__ ); } while (0); | |||
520 | ||||
521 | fd = open(database, O_RDONLY00|O_CLOEXEC02000000); | |||
522 | if (fd < 0) | |||
523 | return -errno(*__errno_location ()); | |||
524 | ||||
525 | if (fstat(fd, &st) < 0) { | |||
526 | safe_close(fd); | |||
527 | return -errno(*__errno_location ()); | |||
528 | } | |||
529 | ||||
530 | if (st.st_size < (off_t) sizeof(CatalogHeader)) { | |||
531 | safe_close(fd); | |||
532 | return -EINVAL22; | |||
533 | } | |||
534 | ||||
535 | p = mmap(NULL((void*)0), PAGE_ALIGN(st.st_size)ALIGN_TO((st.st_size), page_size()), PROT_READ0x1, MAP_SHARED0x01, fd, 0); | |||
536 | if (p == MAP_FAILED((void *) -1)) { | |||
537 | safe_close(fd); | |||
538 | return -errno(*__errno_location ()); | |||
539 | } | |||
540 | ||||
541 | h = p; | |||
542 | if (memcmp(h->signature, CATALOG_SIGNATURE(uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }, sizeof(h->signature)) != 0 || | |||
543 | le64toh(h->header_size) < sizeof(CatalogHeader) || | |||
544 | le64toh(h->catalog_item_size) < sizeof(CatalogItem) || | |||
545 | h->incompatible_flags != 0 || | |||
546 | le64toh(h->n_items) <= 0 || | |||
547 | st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) { | |||
548 | safe_close(fd); | |||
549 | munmap(p, st.st_size); | |||
550 | return -EBADMSG74; | |||
551 | } | |||
552 | ||||
553 | *_fd = fd; | |||
554 | *_st = st; | |||
555 | *_p = p; | |||
556 | ||||
557 | return 0; | |||
558 | } | |||
559 | ||||
560 | static const char *find_id(void *p, sd_id128_t id) { | |||
561 | CatalogItem *f = NULL((void*)0), key = { .id = id }; | |||
562 | const CatalogHeader *h = p; | |||
563 | const char *loc; | |||
564 | ||||
565 | loc = setlocale(LC_MESSAGES5, NULL((void*)0)); | |||
566 | if (loc && loc[0] && !streq(loc, "C")(strcmp((loc),("C")) == 0) && !streq(loc, "POSIX")(strcmp((loc),("POSIX")) == 0)) { | |||
567 | strncpy(key.language, loc, sizeof(key.language)); | |||
568 | key.language[strcspn(key.language, ".@")] = 0; | |||
569 | ||||
570 | f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); | |||
571 | if (!f) { | |||
572 | char *e; | |||
573 | ||||
574 | e = strchr(key.language, '_'); | |||
575 | if (e) { | |||
576 | *e = 0; | |||
577 | f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); | |||
578 | } | |||
579 | } | |||
580 | } | |||
581 | ||||
582 | if (!f) { | |||
583 | zero(key.language)(({ size_t _l_ = (sizeof(key.language)); void *_x_ = (&(key .language)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
584 | f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); | |||
585 | } | |||
586 | ||||
587 | if (!f) | |||
588 | return NULL((void*)0); | |||
589 | ||||
590 | return (const char*) p + | |||
591 | le64toh(h->header_size) + | |||
592 | le64toh(h->n_items) * le64toh(h->catalog_item_size) + | |||
593 | le64toh(f->offset); | |||
594 | } | |||
595 | ||||
596 | int catalog_get(const char* database, sd_id128_t id, char **_text) { | |||
597 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | |||
598 | void *p = NULL((void*)0); | |||
599 | struct stat st = {}; | |||
600 | char *text = NULL((void*)0); | |||
601 | int r; | |||
602 | const char *s; | |||
603 | ||||
604 | assert(_text)do { if ((__builtin_expect(!!(!(_text)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_text"), "../src/journal/catalog.c", 604 , __PRETTY_FUNCTION__); } while (0); | |||
605 | ||||
606 | r = open_mmap(database, &fd, &st, &p); | |||
607 | if (r < 0) | |||
608 | return r; | |||
609 | ||||
610 | s = find_id(p, id); | |||
611 | if (!s) { | |||
612 | r = -ENOENT2; | |||
613 | goto finish; | |||
614 | } | |||
615 | ||||
616 | text = strdup(s); | |||
617 | if (!text) { | |||
618 | r = -ENOMEM12; | |||
619 | goto finish; | |||
620 | } | |||
621 | ||||
622 | *_text = text; | |||
623 | r = 0; | |||
624 | ||||
625 | finish: | |||
626 | if (p) | |||
627 | munmap(p, st.st_size); | |||
628 | ||||
629 | return r; | |||
630 | } | |||
631 | ||||
632 | static char *find_header(const char *s, const char *header) { | |||
633 | ||||
634 | for (;;) { | |||
635 | const char *v; | |||
636 | ||||
637 | v = startswith(s, header); | |||
638 | if (v) { | |||
639 | v += strspn(v, WHITESPACE" \t\n\r"); | |||
640 | return strndup(v, strcspn(v, NEWLINE"\n\r")); | |||
641 | } | |||
642 | ||||
643 | if (!next_header(&s)) | |||
644 | return NULL((void*)0); | |||
645 | } | |||
646 | } | |||
647 | ||||
648 | static void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool_Bool oneline) { | |||
649 | if (oneline) { | |||
650 | _cleanup_free___attribute__((cleanup(freep))) char *subject = NULL((void*)0), *defined_by = NULL((void*)0); | |||
651 | ||||
652 | subject = find_header(s, "Subject:"); | |||
653 | defined_by = find_header(s, "Defined-By:"); | |||
654 | ||||
655 | fprintf(f, SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" " %s: %s\n", | |||
656 | SD_ID128_FORMAT_VAL(id)(id).bytes[0], (id).bytes[1], (id).bytes[2], (id).bytes[3], ( id).bytes[4], (id).bytes[5], (id).bytes[6], (id).bytes[7], (id ).bytes[8], (id).bytes[9], (id).bytes[10], (id).bytes[11], (id ).bytes[12], (id).bytes[13], (id).bytes[14], (id).bytes[15], | |||
657 | strna(defined_by), strna(subject)); | |||
658 | } else | |||
659 | fprintf(f, "-- " SD_ID128_FORMAT_STR"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "\n%s\n", | |||
660 | SD_ID128_FORMAT_VAL(id)(id).bytes[0], (id).bytes[1], (id).bytes[2], (id).bytes[3], ( id).bytes[4], (id).bytes[5], (id).bytes[6], (id).bytes[7], (id ).bytes[8], (id).bytes[9], (id).bytes[10], (id).bytes[11], (id ).bytes[12], (id).bytes[13], (id).bytes[14], (id).bytes[15], s); | |||
661 | } | |||
662 | ||||
663 | int catalog_list(FILE *f, const char *database, bool_Bool oneline) { | |||
664 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | |||
665 | void *p = NULL((void*)0); | |||
666 | struct stat st; | |||
667 | const CatalogHeader *h; | |||
668 | const CatalogItem *items; | |||
669 | int r; | |||
670 | unsigned n; | |||
671 | sd_id128_t last_id; | |||
672 | bool_Bool last_id_set = false0; | |||
673 | ||||
674 | r = open_mmap(database, &fd, &st, &p); | |||
675 | if (r < 0) | |||
676 | return r; | |||
677 | ||||
678 | h = p; | |||
679 | items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size)); | |||
680 | ||||
681 | for (n = 0; n < le64toh(h->n_items); n++) { | |||
682 | const char *s; | |||
683 | ||||
684 | if (last_id_set && sd_id128_equal(last_id, items[n].id)) | |||
685 | continue; | |||
686 | ||||
687 | assert_se(s = find_id(p, items[n].id))do { if ((__builtin_expect(!!(!(s = find_id(p, items[n].id))) ,0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("s = find_id(p, items[n].id)" ), "../src/journal/catalog.c", 687, __PRETTY_FUNCTION__); } while (0); | |||
688 | ||||
689 | dump_catalog_entry(f, items[n].id, s, oneline); | |||
690 | ||||
691 | last_id_set = true1; | |||
692 | last_id = items[n].id; | |||
693 | } | |||
694 | ||||
695 | munmap(p, st.st_size); | |||
696 | ||||
697 | return 0; | |||
698 | } | |||
699 | ||||
700 | int catalog_list_items(FILE *f, const char *database, bool_Bool oneline, char **items) { | |||
701 | char **item; | |||
702 | int r = 0; | |||
703 | ||||
704 | STRV_FOREACH(item, items)for ((item) = (items); (item) && *(item); (item)++) { | |||
705 | sd_id128_t id; | |||
706 | int k; | |||
707 | _cleanup_free___attribute__((cleanup(freep))) char *msg = NULL((void*)0); | |||
708 | ||||
709 | k = sd_id128_from_string(*item, &id); | |||
710 | if (k < 0) { | |||
711 | log_error_errno(k, "Failed to parse id128 '%s': %m", *item)({ int _level = ((3)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 711, __func__, "Failed to parse id128 '%s': %m" , *item) : -abs(_e); }); | |||
712 | if (r == 0) | |||
713 | r = k; | |||
714 | continue; | |||
715 | } | |||
716 | ||||
717 | k = catalog_get(database, id, &msg); | |||
718 | if (k < 0) { | |||
719 | log_full_errno(k == -ENOENT ? LOG_NOTICE : LOG_ERR, k,({ int _level = ((k == -2 ? 5 : 3)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 720, __func__, "Failed to retrieve catalog entry for '%s': %m" , *item) : -abs(_e); }) | |||
720 | "Failed to retrieve catalog entry for '%s': %m", *item)({ int _level = ((k == -2 ? 5 : 3)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/catalog.c", 720, __func__, "Failed to retrieve catalog entry for '%s': %m" , *item) : -abs(_e); }); | |||
721 | if (r == 0) | |||
722 | r = k; | |||
723 | continue; | |||
724 | } | |||
725 | ||||
726 | dump_catalog_entry(f, id, msg, oneline); | |||
727 | } | |||
728 | ||||
729 | return r; | |||
730 | } |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | #pragma once |
3 | |
4 | #include <alloca.h> |
5 | #include <stddef.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | |
9 | #include "macro.h" |
10 | |
11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
12 | |
13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
14 | |
15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
16 | ({ \ |
17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
19 | }) |
20 | |
21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
22 | ({ \ |
23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
25 | }) |
26 | |
27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
28 | |
29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
30 | |
31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
32 | |
33 | static inline void *mfree(void *memory) { |
34 | free(memory); |
35 | return NULL((void*)0); |
36 | } |
37 | |
38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
39 | ({ \ |
40 | free(a); \ |
41 | (a) = (b); \ |
42 | (b) = NULL((void*)0); \ |
43 | 0; \ |
44 | }) |
45 | |
46 | void* memdup(const void *p, size_t l) _alloc_(2); |
47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
48 | |
49 | static inline void freep(void *p) { |
50 | free(*(void**) p); |
51 | } |
52 | |
53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
54 | |
55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
57 | } |
58 | |
59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
60 | if (size_multiply_overflow(size, need)) |
61 | return NULL((void*)0); |
62 | |
63 | return malloc(size * need); |
64 | } |
65 | |
66 | #if !HAVE_REALLOCARRAY1 |
67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
68 | if (size_multiply_overflow(size, need)) |
69 | return NULL((void*)0); |
70 | |
71 | return realloc(p, size * need); |
72 | } |
73 | #endif |
74 | |
75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
76 | if (size_multiply_overflow(size, need)) |
77 | return NULL((void*)0); |
78 | |
79 | return memdup(p, size * need); |
80 | } |
81 | |
82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
83 | if (size_multiply_overflow(size, need)) |
84 | return NULL((void*)0); |
85 | |
86 | return memdup_suffix0(p, size * need); |
87 | } |
88 | |
89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
91 | |
92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
94 | |
95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
97 | |
98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
99 | ({ \ |
100 | char *_new_; \ |
101 | size_t _len_ = n; \ |
102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
103 | (void *) memset(_new_, 0, _len_); \ |
104 | }) |
105 | |
106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
108 | ({ \ |
109 | void *_ptr_; \ |
110 | size_t _mask_ = (align) - 1; \ |
111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
113 | }) |
114 | |
115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
116 | ({ \ |
117 | void *_new_; \ |
118 | size_t _size_ = (size); \ |
119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
120 | (void*)memset(_new_, 0, _size_); \ |
121 | }) |
122 | |
123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
126 | ({ \ |
127 | typeof(ptr) _ptr_ = (ptr); \ |
128 | (ptr) = NULL((void*)0); \ |
129 | _ptr_; \ |
130 | }) |