]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/catalog.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / journal / catalog.c
index f9118f0b62807bd750e5477a1faddf9bfea748bb..4062f12c2dfc574eae5d602602d180f29d8e5252 100644 (file)
@@ -24,6 +24,7 @@
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "util.h"
 
 const char * const catalog_file_dirs[] = {
@@ -45,35 +46,30 @@ typedef struct CatalogHeader {
 
 typedef struct CatalogItem {
         sd_id128_t id;
-        char language[32];
+        char language[32]; /* One byte is used for termination, so the maximum allowed
+                            * length of the string is actually 31 bytes. */
         le64_t offset;
 } CatalogItem;
 
-static void catalog_hash_func(const void *p, struct siphash *state) {
-        const CatalogItem *i = p;
-
+static void catalog_hash_func(const CatalogItem *i, struct siphash *state) {
         siphash24_compress(&i->id, sizeof(i->id), state);
         siphash24_compress(i->language, strlen(i->language), state);
 }
 
-static int catalog_compare_func(const void *a, const void *b) {
-        const CatalogItem *i = a, *j = b;
+static int catalog_compare_func(const CatalogItem *a, const CatalogItem *b) {
         unsigned k;
+        int r;
 
-        for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
-                 if (i->id.bytes[k] < j->id.bytes[k])
-                        return -1;
-                 if (i->id.bytes[k] > j->id.bytes[k])
-                        return 1;
+        for (k = 0; k < ELEMENTSOF(b->id.bytes); k++) {
+                r = CMP(a->id.bytes[k], b->id.bytes[k]);
+                if (r != 0)
+                        return r;
         }
 
-        return strcmp(i->language, j->language);
+        return strcmp(a->language, b->language);
 }
 
-const struct hash_ops catalog_hash_ops = {
-        .hash = catalog_hash_func,
-        .compare = catalog_compare_func
-};
+DEFINE_HASH_OPS(catalog_hash_ops, CatalogItem, catalog_hash_func, catalog_compare_func);
 
 static bool next_header(const char **s) {
         const char *e;
@@ -218,14 +214,14 @@ static int catalog_entry_lang(const char* filename, int line,
         size_t c;
 
         c = strlen(t);
-        if (c == 0) {
-                log_error("[%s:%u] Language too short.", filename, line);
-                return -EINVAL;
-        }
-        if (c > 31) {
-                log_error("[%s:%u] language too long.", filename, line);
-                return -EINVAL;
-        }
+        if (c < 2)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "[%s:%u] Language too short.",
+                                       filename, line);
+        if (c > 31)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "[%s:%u] language too long.", filename,
+                                       line);
 
         if (deflang) {
                 if (streq(t, deflang)) {
@@ -268,26 +264,23 @@ int catalog_import_file(Hashmap *h, const char *path) {
                 log_debug("File %s has language %s.", path, deflang);
 
         for (;;) {
-                char line[LINE_MAX];
+                _cleanup_free_ char *line = NULL;
                 size_t line_len;
 
-                if (!fgets(line, sizeof(line), f)) {
-                        if (feof(f))
-                                break;
-
-                        return log_error_errno(errno, "Failed to read file %s: %m", path);
-                }
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read file %s: %m", path);
+                if (r == 0)
+                        break;
 
                 n++;
 
-                truncate_nl(line);
-
-                if (line[0] == 0) {
+                if (isempty(line)) {
                         empty_line = true;
                         continue;
                 }
 
-                if (strchr(COMMENTS "\n", line[0]))
+                if (strchr(COMMENTS, line[0]))
                         continue;
 
                 if (empty_line &&
@@ -308,10 +301,11 @@ int catalog_import_file(Hashmap *h, const char *path) {
                         if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
 
                                 if (got_id) {
-                                        if (payload_size == 0) {
-                                                log_error("[%s:%u] No payload text.", path, n);
-                                                return -EINVAL;
-                                        }
+                                        if (payload_size == 0)
+                                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                                       "[%s:%u] No payload text.",
+                                                                       path,
+                                                                       n);
 
                                         r = finish_item(h, id, lang ?: deflang, payload, payload_size);
                                         if (r < 0)
@@ -339,10 +333,10 @@ int catalog_import_file(Hashmap *h, const char *path) {
                 }
 
                 /* Payload */
-                if (!got_id) {
-                        log_error("[%s:%u] Got payload before ID.", path, n);
-                        return -EINVAL;
-                }
+                if (!got_id)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Got payload before ID.",
+                                               path, n);
 
                 line_len = strlen(line);
                 if (!GREEDY_REALLOC(payload, payload_allocated,
@@ -360,10 +354,10 @@ int catalog_import_file(Hashmap *h, const char *path) {
         }
 
         if (got_id) {
-                if (payload_size == 0) {
-                        log_error("[%s:%u] No payload text.", path, n);
-                        return -EINVAL;
-                }
+                if (payload_size == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] No payload text.",
+                                               path, n);
 
                 r = finish_item(h, id, lang ?: deflang, payload, payload_size);
                 if (r < 0)
@@ -495,7 +489,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
         }
 
         assert(n == hashmap_size(h));
-        qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
+        typesafe_qsort(items, n, catalog_compare_func);
 
         strbuf_complete(sb);
 
@@ -563,25 +557,44 @@ static const char *find_id(void *p, sd_id128_t id) {
         const char *loc;
 
         loc = setlocale(LC_MESSAGES, NULL);
-        if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) {
-                strncpy(key.language, loc, sizeof(key.language));
-                key.language[strcspn(key.language, ".@")] = 0;
-
-                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
-                if (!f) {
-                        char *e;
-
-                        e = strchr(key.language, '_');
-                        if (e) {
-                                *e = 0;
-                                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+        if (!isempty(loc) && !STR_IN_SET(loc, "C", "POSIX")) {
+                size_t len;
+
+                len = strcspn(loc, ".@");
+                if (len > sizeof(key.language) - 1)
+                        log_debug("LC_MESSAGES value too long, ignoring: \"%.*s\"", (int) len, loc);
+                else {
+                        strncpy(key.language, loc, len);
+                        key.language[len] = '\0';
+
+                        f = bsearch(&key,
+                                    (const uint8_t*) p + le64toh(h->header_size),
+                                    le64toh(h->n_items),
+                                    le64toh(h->catalog_item_size),
+                                    (comparison_fn_t) catalog_compare_func);
+                        if (!f) {
+                                char *e;
+
+                                e = strchr(key.language, '_');
+                                if (e) {
+                                        *e = 0;
+                                        f = bsearch(&key,
+                                                    (const uint8_t*) p + le64toh(h->header_size),
+                                                    le64toh(h->n_items),
+                                                    le64toh(h->catalog_item_size),
+                                                    (comparison_fn_t) catalog_compare_func);
+                                }
                         }
                 }
         }
 
         if (!f) {
                 zero(key.language);
-                f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+                f = bsearch(&key,
+                            (const uint8_t*) p + le64toh(h->header_size),
+                            le64toh(h->n_items),
+                            le64toh(h->catalog_item_size),
+                            (comparison_fn_t) catalog_compare_func);
         }
 
         if (!f)