chiark / gitweb /
log: fix error codes handling in catalog_list_items
[elogind.git] / src / journal / catalog.c
index 7be0d20f42a3c5a6ed387a2c906eb2ef0dad7823..6b195f6920a16de5418cfdbfe883c6d7ea455fc2 100644 (file)
@@ -50,14 +50,15 @@ typedef struct CatalogHeader {
         uint8_t signature[8];  /* "RHHHKSLP" */
         le32_t compatible_flags;
         le32_t incompatible_flags;
-        le32_t header_size;
-        le32_t n_items;
+        le64_t header_size;
+        le64_t n_items;
+        le64_t catalog_item_size;
 } CatalogHeader;
 
 typedef struct CatalogItem {
         sd_id128_t id;
         char language[32];
-        le32_t offset;
+        le64_t offset;
 } CatalogItem;
 
 static unsigned catalog_hash_func(const void *p) {
@@ -117,18 +118,13 @@ static int finish_item(
         if (offset < 0)
                 return log_oom();
 
-        if (offset > 0xFFFFFFFF) {
-                log_error("Too many catalog entries.");
-                return -E2BIG;
-        }
-
         i = new0(CatalogItem, 1);
         if (!i)
                 return log_oom();
 
         i->id = id;
         strncpy(i->language, language, sizeof(i->language));
-        i->offset = htole32((uint32_t) offset);
+        i->offset = htole64((uint64_t) offset);
 
         r = hashmap_put(h, i, i);
         if (r == EEXIST) {
@@ -273,6 +269,8 @@ static int import_file(Hashmap *h, struct strbuf *sb, const char *path) {
         return 0;
 }
 
+#define CATALOG_DATABASE CATALOG_PATH "/database"
+
 int catalog_update(void) {
         _cleanup_strv_free_ char **files = NULL;
         _cleanup_fclose_ FILE *w = NULL;
@@ -298,7 +296,7 @@ int catalog_update(void) {
                 goto finish;
         }
 
-        r = conf_files_list_strv(&files, ".catalog", (const char **) conf_file_dirs);
+        r = conf_files_list_strv(&files, ".catalog", NULL, (const char **) conf_file_dirs);
         if (r < 0) {
                 log_error("Failed to get catalog files: %s", strerror(-r));
                 goto finish;
@@ -313,7 +311,8 @@ int catalog_update(void) {
                 log_info("No items in catalog.");
                 r = 0;
                 goto finish;
-        }
+        } else
+                log_debug("Found %u items in catalog.", hashmap_size(h));
 
         strbuf_complete(sb);
 
@@ -332,52 +331,61 @@ int catalog_update(void) {
         assert(n == hashmap_size(h));
         qsort(items, n, sizeof(CatalogItem), catalog_compare_func);
 
-        mkdir_p("/var/lib/systemd/catalog", 0775);
+        r = mkdir_p(CATALOG_PATH, 0775);
+        if (r < 0) {
+                log_error("Recursive mkdir %s: %s", CATALOG_PATH, strerror(-r));
+                goto finish;
+        }
 
-        r = fopen_temporary("/var/lib/systemd/catalog/database", &w, &p);
+        r = fopen_temporary(CATALOG_DATABASE, &w, &p);
         if (r < 0) {
-                log_error("Failed to open database for writing: %s", strerror(-r));
+                log_error("Failed to open database for writing: %s: %s",
+                          CATALOG_DATABASE, strerror(-r));
                 goto finish;
         }
 
         zero(header);
         memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
-        header.header_size = htole32(ALIGN_TO(sizeof(CatalogHeader), 8));
-        header.n_items = htole32(hashmap_size(h));
+        header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
+        header.catalog_item_size = htole64(sizeof(CatalogItem));
+        header.n_items = htole64(hashmap_size(h));
 
         k = fwrite(&header, 1, sizeof(header), w);
         if (k != sizeof(header)) {
-                log_error("Failed to write header.");
+                log_error("%s: failed to write header.", p);
                 goto finish;
         }
 
         k = fwrite(items, 1, n * sizeof(CatalogItem), w);
         if (k != n * sizeof(CatalogItem)) {
-                log_error("Failed to write database.");
+                log_error("%s: failed to write database.", p);
                 goto finish;
         }
 
         k = fwrite(sb->buf, 1, sb->len, w);
         if (k != sb->len) {
-                log_error("Failed to write strings.");
+                log_error("%s: failed to write strings.", p);
                 goto finish;
         }
 
         fflush(w);
 
         if (ferror(w)) {
-                log_error("Failed to write database.");
+                log_error("%s: failed to write database.", p);
                 goto finish;
         }
 
         fchmod(fileno(w), 0644);
 
-        if (rename(p, "/var/lib/systemd/catalog/database") < 0) {
-                log_error("rename() failed: %m");
+        if (rename(p, CATALOG_DATABASE) < 0) {
+                log_error("rename (%s -> %s) failed: %m", p, CATALOG_DATABASE);
                 r = -errno;
                 goto finish;
         }
 
+        log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
+                 CATALOG_DATABASE, n, sb->len, ftell(w));
+
         free(p);
         p = NULL;
 
@@ -405,7 +413,7 @@ static int open_mmap(int *_fd, struct stat *_st, void **_p) {
         assert(_st);
         assert(_p);
 
-        fd = open("/var/lib/systemd/catalog/database", O_RDONLY|O_CLOEXEC);
+        fd = open(CATALOG_DATABASE, O_RDONLY|O_CLOEXEC);
         if (fd < 0)
                 return -errno;
 
@@ -427,10 +435,11 @@ static int open_mmap(int *_fd, struct stat *_st, void **_p) {
 
         h = p;
         if (memcmp(h->signature, CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
-            le32toh(h->header_size) < sizeof(CatalogHeader) ||
+            le64toh(h->header_size) < sizeof(CatalogHeader) ||
+            le64toh(h->catalog_item_size) < sizeof(CatalogItem) ||
             h->incompatible_flags != 0 ||
-            le32toh(h->n_items) <= 0 ||
-            st.st_size < (off_t) (le32toh(h->header_size) + sizeof(CatalogItem) * le32toh(h->n_items))) {
+            le64toh(h->n_items) <= 0 ||
+            st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
                 close_nointr_nofail(fd);
                 munmap(p, st.st_size);
                 return -EBADMSG;
@@ -456,30 +465,30 @@ static const char *find_id(void *p, sd_id128_t id) {
                 strncpy(key.language, loc, sizeof(key.language));
                 key.language[strcspn(key.language, ".@")] = 0;
 
-                f = bsearch(&key, (const uint8_t*) p + le32toh(h->header_size), le32toh(h->n_items), sizeof(CatalogItem), catalog_compare_func);
+                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 + le32toh(h->header_size), le32toh(h->n_items), sizeof(CatalogItem), catalog_compare_func);
+                                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) {
                 zero(key.language);
-                f = bsearch(&key, (const uint8_t*) p + le32toh(h->header_size), le32toh(h->n_items), sizeof(CatalogItem), catalog_compare_func);
+                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)
                 return NULL;
 
         return (const char*) p +
-                le32toh(h->header_size) +
-                le32toh(h->n_items) * sizeof(CatalogItem) +
-                le32toh(f->offset);
+                le64toh(h->header_size) +
+                le64toh(h->n_items) * le64toh(h->catalog_item_size) +
+                le64toh(f->offset);
 }
 
 int catalog_get(sd_id128_t id, char **_text) {
@@ -542,7 +551,23 @@ static char *find_header(const char *s, const char *header) {
         }
 }
 
-int catalog_list(FILE *f) {
+static void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) {
+        if (oneline) {
+                _cleanup_free_ char *subject = NULL, *defined_by = NULL;
+
+                subject = find_header(s, "Subject:");
+                defined_by = find_header(s, "Defined-By:");
+
+                fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n",
+                        SD_ID128_FORMAT_VAL(id),
+                        strna(defined_by), strna(subject));
+        } else
+                fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n",
+                        SD_ID128_FORMAT_VAL(id), s);
+}
+
+
+int catalog_list(FILE *f, bool oneline) {
         _cleanup_close_ int fd = -1;
         void *p = NULL;
         struct stat st;
@@ -558,21 +583,17 @@ int catalog_list(FILE *f) {
                 return r;
 
         h = p;
-        items = (const CatalogItem*) ((const uint8_t*) p + le32toh(h->header_size));
+        items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size));
 
-        for (n = 0; n < le32toh(h->n_items); n++) {
+        for (n = 0; n < le64toh(h->n_items); n++) {
                 const char *s;
-                _cleanup_free_ char *subject = NULL, *defined_by = NULL;
 
                 if (last_id_set && sd_id128_equal(last_id, items[n].id))
                         continue;
 
                 assert_se(s = find_id(p, items[n].id));
 
-                subject = find_header(s, "Subject:");
-                defined_by = find_header(s, "Defined-By:");
-
-                fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n", SD_ID128_FORMAT_VAL(items[n].id), strna(defined_by), strna(subject));
+                dump_catalog_entry(f, items[n].id, s, oneline);
 
                 last_id_set = true;
                 last_id = items[n].id;
@@ -582,3 +603,37 @@ int catalog_list(FILE *f) {
 
         return 0;
 }
+
+int catalog_list_items(FILE *f, bool oneline, char **items) {
+        char **item;
+        int r = 0;
+
+        STRV_FOREACH(item, items) {
+                sd_id128_t id;
+                int k;
+                char _cleanup_free_ *msg = NULL;
+
+                k = sd_id128_from_string(*item, &id);
+                if (k < 0) {
+                        log_error("Failed to parse id128 '%s': %s",
+                                  *item, strerror(-k));
+                        if (r < 0)
+                                r = k;
+                        continue;
+                }
+
+                k = catalog_get(id, &msg);
+                if (k < 0) {
+                        log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
+                                 "Failed to retrieve catalog entry for '%s': %s",
+                                  *item, strerror(-k));
+                        if (r < 0)
+                                r = k;
+                        continue;
+                }
+
+                dump_catalog_entry(f, id, msg, oneline);
+        }
+
+        return r;
+}