Add low-level dump command to aid debugging
authorJ. Ali Harlow <ali@juiblex.co.uk>
Fri, 17 Oct 2014 09:08:28 +0000 (10:08 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Fri, 17 Oct 2014 09:08:28 +0000 (10:08 +0100)
librazor/Makefile.am
librazor/dump.c [new file with mode: 0644]
librazor/razor.h.in
librazor/types/list.c
librazor/types/types.h
src/main.c

index b800570..3c3bc2e 100644 (file)
@@ -33,6 +33,7 @@ librazor_la_SOURCES =                                 \
        razor.h                                         \
        razor.c                                         \
        root.c                                          \
+       dump.c                                          \
        util.c                                          \
        path.c                                          \
        rpm.c                                           \
diff --git a/librazor/dump.c b/librazor/dump.c
new file mode 100644 (file)
index 0000000..8f946c2
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2014  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "razor.h"
+#include "razor-internal.h"
+
+static size_t
+dump_raw(FILE *fp, void *raw, char *what, size_t length, size_t offset)
+{
+       size_t i, n = 0;
+       unsigned char *bytes = raw;
+
+       while (length) {
+               fprintf(fp, "%05lX %s", (unsigned long)(offset + n), what);
+               for (i = 0; (i < 16) && (length > 0);) {
+                       if (length >= 4) {
+                               fprintf(fp, " %08X", *(uint32_t *)bytes);
+                               bytes += 4;
+                               n += 4;
+                               length -= 4;
+                               i += 4;
+                       } else if (length >= 2) {
+                               fprintf(fp, " %04X", *(unsigned short *)bytes);
+                               bytes += 2;
+                               n += 2;
+                               length -= 2;
+                               i += 2;
+                       } else {
+                               fprintf(fp, " %02X", *bytes);
+                               bytes++;
+                               n++;
+                               length--;
+                               i++;
+                       }
+               }
+               fprintf(fp, "\n");
+       }
+
+       return n;
+}
+
+static size_t
+dump_string(FILE *fp, char *pool, size_t length, size_t offset)
+{
+       size_t n = 0;
+       unsigned char c;
+
+       fprintf(fp, "\"");
+       while (offset + n < length) {
+               c = pool[offset + n++];
+               if (c == '\0') {
+                       fprintf(fp, "\\0");
+                       break;
+               }
+               else if (c == '\\' || c == '"')
+                       fprintf(fp, "\\%c", c);
+               else if (c >= ' ' && c <= '~')
+                       fprintf(fp, "%c", c);
+               else
+                       fprintf(fp, "\\x%02X", c);
+       }
+       fprintf(fp, "\"");
+
+       return n;
+}
+
+static size_t
+dump_pool(FILE *fp, char *pool, char *what, size_t length, size_t offset)
+{
+       size_t n = 0;
+
+       fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what);
+
+       while (n < length) {
+               fprintf(fp, "    %08X ", (uint32_t)n);
+               n += dump_string(fp, pool, length, n);
+               fprintf(fp, "\n");
+       }
+
+       fprintf(fp, "}\n");
+
+       return n;
+}
+
+static size_t
+dump_header(FILE *fp, struct razor_set_header *header, size_t length,
+           size_t offset)
+{
+       if (length >= sizeof(*header)) {
+               fprintf(fp, "%05lX header ", (unsigned long)offset);
+               fprintf(fp, "{ magic=%08X version=%08X num_sections=%08X }\n",
+                       header->magic, header->version, header->num_sections);
+               return sizeof(*header);
+       } else
+               return dump_raw(fp, header, "unknown", length, offset);
+}
+
+static size_t
+dump_section(FILE *fp, struct razor_set_section *section, size_t length,
+            size_t offset, int indx)
+{
+       if (length >= sizeof(*section)) {
+               fprintf(fp, "%05lX section %X ", (unsigned long)offset, indx);
+               fprintf(fp, "{ name=%08X offset=%08X size=%08X }\n",
+                       section->name, section->offset, section->size);
+               return sizeof(*section);
+       } else
+               return dump_raw(fp, section, "unknown", length, offset);
+}
+
+static void
+dump_list_head(FILE *fp, struct list_head *head)
+{
+       fprintf(fp, "{ list_ptr=%06X flags=%02X ",
+               head->list_ptr, head->flags);
+       if (head->flags == RAZOR_EMPTY_LIST)
+               fprintf(fp, "(EMPTY_LIST) ");
+       else if (head->flags == RAZOR_IMMEDIATE)
+               fprintf(fp, "(IMMEDIATE) ");
+       fprintf(fp,"}");
+}
+
+static void
+dump_list_link(FILE *fp, struct list *list)
+{
+       fprintf(fp, "{ data=%06X flags=%02X ",
+               list->data, list->flags);
+       if (list->flags == RAZOR_ENTRY_LAST)
+               fprintf(fp, "(ENTRY_LAST) ");
+       else if (list->flags == RAZOR_ENTRY_FIRST)
+               fprintf(fp, "(ENTRY_FIRST) ");
+       fprintf(fp,"}");
+}
+
+static void
+expand_pooled_string(FILE *fp, struct array *pool, uint32_t str)
+{
+       if (pool->data && str < pool->size) {
+               fprintf(fp, "(");
+               dump_string(fp, pool->data, pool->size, str);
+               fprintf(fp, ") ");
+       }
+}
+
+static size_t
+dump_package(FILE *fp, struct razor_package *package, size_t length,
+            size_t offset, struct array *string_pool, int indx)
+{
+       if (length >= sizeof(*package)) {
+               fprintf(fp, "    %05lX package %X ", (unsigned long)offset,
+                       indx);
+               fprintf(fp, "{ name=%06X ", package->name);
+               expand_pooled_string(fp, string_pool, package->name);
+               fprintf(fp, "flags=%02X\n            version=%08X ",
+                       package->flags, package->version);
+               expand_pooled_string(fp, string_pool, package->version);
+               fprintf(fp, "arch=%08X ", package->arch);
+               expand_pooled_string(fp, string_pool, package->arch);
+               fprintf(fp, "\n            "
+                       "summary=%08X description=%08X url=%08X license=%08X\n",
+                       package->summary, package->description,
+                       package->url, package->license);
+               fprintf(fp,"            properties=");
+               dump_list_head(fp, &package->properties);
+               fprintf(fp,"\n");
+               fprintf(fp,"            files=");
+               dump_list_head(fp, &package->files);
+               fprintf(fp,"\n");
+               fprintf(fp,"            install_prefixes=");
+               dump_list_head(fp, &package->install_prefixes);
+               fprintf(fp,"\n");
+               fprintf(fp,"            preun={ program=%08X body=%08X }\n",
+                       package->preun.program, package->preun.body);
+               fprintf(fp,"            postun={ program=%08X body=%08X }\n",
+                       package->postun.program, package->postun.body);
+               fprintf(fp,"    }\n");
+               return sizeof(*package);
+       } else
+               return dump_raw(fp, package, "unknown", length, offset);
+}
+
+static size_t
+dump_packages(FILE *fp, struct razor_package *packages, size_t length,
+             size_t offset, struct array *string_pool)
+{
+       size_t n = 0;
+       int i = 0;
+
+       fprintf(fp, "%05lX packages {\n", (unsigned long)offset);
+
+       while (n < length) {
+               n += dump_package(fp, packages, length - n, n, string_pool, i);
+               packages++;
+               i++;
+       }
+
+       fprintf(fp, "}\n");
+
+       return n;
+}
+
+static size_t
+dump_property(FILE *fp, struct razor_property *property, size_t length,
+             size_t offset, struct array *string_pool)
+{
+       if (length >= sizeof(*property)) {
+               fprintf(fp, "    %05lX property ", (unsigned long)offset);
+               fprintf(fp, "{ name=%08X ", property->name);
+               expand_pooled_string(fp, string_pool, property->name);
+               fprintf(fp, "\n            flags=%08X (", property->flags);
+               if (property->flags & RAZOR_PROPERTY_LESS)
+                       fprintf(fp, "<");
+               if (property->flags & RAZOR_PROPERTY_GREATER)
+                       fprintf(fp, ">");
+               if (property->flags & RAZOR_PROPERTY_EQUAL)
+                       fprintf(fp, "=");
+               switch (property->flags & RAZOR_PROPERTY_TYPE_MASK) {
+               case RAZOR_PROPERTY_REQUIRES:
+                       fprintf(fp, " requires");
+                       break;
+               case RAZOR_PROPERTY_PROVIDES:
+                       fprintf(fp, " provides");
+                       break;
+               case RAZOR_PROPERTY_CONFLICTS:
+                       fprintf(fp, " conflicts");
+                       break;
+               case RAZOR_PROPERTY_OBSOLETES:
+                       fprintf(fp, " obsoletes");
+                       break;
+               }
+               if (property->flags & RAZOR_PROPERTY_PRE)
+                       fprintf(fp, " pre");
+               if (property->flags & RAZOR_PROPERTY_POST)
+                       fprintf(fp, " post");
+               if (property->flags & RAZOR_PROPERTY_PREUN)
+                       fprintf(fp, " preun");
+               if (property->flags & RAZOR_PROPERTY_POSTUN)
+                       fprintf(fp, " postun");
+               fprintf(fp, ") version=%08X ", property->version);
+               expand_pooled_string(fp, string_pool, property->version);
+               fprintf(fp,"\n            packages=");
+               dump_list_head(fp, &property->packages);
+               fprintf(fp,"\n");
+               fprintf(fp,"    }\n");
+               return sizeof(*property);
+       } else
+               return dump_raw(fp, property, "unknown", length, offset);
+}
+
+static size_t
+dump_properties(FILE *fp, struct razor_property *properties, size_t length,
+               size_t offset, struct array *string_pool)
+{
+       size_t n = 0;
+
+       fprintf(fp, "%05lX properties {\n", (unsigned long)offset);
+
+       while (n < length) {
+               n += dump_property(fp, properties, length - n, n, string_pool);
+               properties++;
+       }
+
+       fprintf(fp, "}\n");
+
+       return n;
+}
+
+static size_t
+dump_entry(FILE *fp, struct razor_entry *entry, size_t length, size_t offset,
+          struct array *string_pool, int indx)
+{
+       if (length >= sizeof(*entry)) {
+               fprintf(fp, "    %05lX entry %X ", (unsigned long)offset, indx);
+               fprintf(fp, "{ name=%06X ", entry->name);
+               expand_pooled_string(fp, string_pool, entry->name);
+               fprintf(fp, "\n            flags=%02X ", entry->flags);
+               if (entry->flags == RAZOR_ENTRY_LAST)
+                       fprintf(fp, "(LAST) ");
+               fprintf(fp, "start=%08X", entry->start);
+               if (!entry->start)
+                       fprintf(fp, " (NONE)");
+               fprintf(fp,"\n            packages=");
+               dump_list_head(fp, &entry->packages);
+               fprintf(fp,"\n");
+               fprintf(fp,"    }\n");
+               return sizeof(*entry);
+       } else
+               return dump_raw(fp, entry, "unknown", length, offset);
+}
+
+static size_t
+dump_files(FILE *fp, struct razor_entry *entries, size_t length, size_t offset,
+          struct array *string_pool)
+{
+       size_t n = 0;
+       int i = 0;
+
+       fprintf(fp, "%05lX files {\n", (unsigned long)offset);
+
+       while (n < length) {
+               n += dump_entry(fp, entries, length - n, n, string_pool, i);
+               i++;
+               entries++;
+       }
+
+       fprintf(fp, "}\n");
+
+       return n;
+}
+
+static size_t
+dump_lists(FILE *fp, struct list *lists, char *what, size_t length,
+          size_t offset)
+{
+       int i = 0;
+       size_t n = 0;
+
+       fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what);
+
+       while (n + sizeof(*lists) <= length) {
+               fprintf(fp, "    list %06X ", i);
+               dump_list_link(fp, lists);
+               fprintf(fp, "\n");
+               n += sizeof(*lists);
+               lists++;
+               i++;
+       }
+
+       if (length - n)
+               n += dump_raw(fp, lists, "unknown", length - n, offset + n);
+
+       fprintf(fp, "}\n");
+
+       return n;
+}
+
+RAZOR_EXPORT int
+razor_dump_database(FILE *fp, const char *root, const char *filename,
+                   struct razor_error **error)
+{
+       int i;
+       char *s, *path, *data;
+       struct array pool = { 0, };
+       struct array string_pool = { 0, };
+       struct array file_string_pool = { 0, };
+       struct array details_string_pool = { 0, };
+       unsigned char *contents;
+       size_t length, len, n, min_offset;
+       struct razor_set_header *header;
+       struct razor_set_section *section, *sections;
+       struct razor_package *package;
+       struct razor_property *prop;
+       struct razor_entry *entry;
+       struct list *list;
+
+       if (!filename)
+               filename = "system.rzdb";
+
+       s = razor_concat(razor_get_database_path(), "/", filename, NULL);
+       path = razor_path_add_root(s, root);
+       free(s);
+       contents = razor_file_get_contents(path, &length, 0, error);
+       free(path);
+
+       if (!contents)
+               return -1;
+
+       n = 0;
+
+       header = (void *)contents;
+
+       if (length - n)
+               n += dump_header(fp, header, length - n, n);
+
+       min_offset = length;
+       sections = (void *)(contents + n);
+       for (i = 0; i < header->num_sections; i++) {
+               if (n == length)
+                       break;
+               section = (void *)(contents + n);
+               if (section->offset < min_offset)
+                       min_offset = section->offset;
+               n += dump_section(fp, section, length - n, n, i);
+       }
+
+       if (length - n) {
+               pool.data = (char *)(contents + n);
+               pool.size = min_offset - n;
+               n += dump_pool(fp, pool.data, "pool", pool.size, n);
+       }
+
+       if ((length - n) && PADDING(n, 4))
+               n += dump_raw(fp, contents + n, "padding", PADDING(n, 4), n);
+
+       for (i = 0; length - n && i < header->num_sections; i++) {
+               if (sections[i].name < pool.size &&
+                   ((char *)pool.data)[pool.size - 1] == '\0')
+                       s = pool.data + sections[i].name;
+               else
+                       continue;
+
+               data = (char *)(contents + sections[i].offset);
+
+               if (!strcmp(s, "string_pool")) {
+                       string_pool.data = data;
+                       string_pool.size = sections[i].size;
+               } else if (!strcmp(s, "file_string_pool")) {
+                       file_string_pool.data = data;
+                       file_string_pool.size = sections[i].size;
+               } else if (!strcmp(s, "details_string_pool")) {
+                       details_string_pool.data = data;
+                       details_string_pool.size = sections[i].size;
+               }
+       }
+
+       for (i = 0; i < header->num_sections; i++) {
+               if (n == length)
+                       break;
+               section = sections + i;
+               if (section->offset != n)
+                       continue;
+               len = section->size;
+               if (len > length - n)
+                       len = length - n;
+
+               if (section->name < pool.size &&
+                   ((char *)pool.data)[pool.size - 1] == '\0')
+                       s = pool.data + section->name;
+               else
+                       s = "unknown";
+
+               if (!strcmp(s, "string_pool") ||
+                   !strcmp(s, "file_string_pool") ||
+                   !strcmp(s, "details_string_pool"))
+                       n += dump_pool(fp, (char *)(contents + n), s, len, n);
+               else if (!strcmp(s, "packages")) {
+                       package = (void *)(contents + n);
+                       n += dump_packages(fp, package, len, n, &string_pool);
+               } else if (!strcmp(s, "properties")) {
+                       prop = (void *)(contents + n);
+                       n += dump_properties(fp, prop, len, n, &string_pool);
+               } else if (!strcmp(s, "files")) {
+                       entry = (void *)(contents + n);
+                       n += dump_files(fp, entry, len, n, &file_string_pool);
+               } else if (!strcmp(s, "package_pool") ||
+                          !strcmp(s, "property_pool") ||
+                          !strcmp(s, "prefix_pool") ||
+                          !strcmp(s, "file_pool")) {
+                       list = (void *)(contents + n);
+                       n += dump_lists(fp, list, s, len, n);
+               } else
+                       n += dump_raw(fp, contents + n, s, len, n);
+
+               if ((length - n) && PADDING(n, 4))
+                       n += dump_raw(fp, contents + n, "padding",
+                                     PADDING(n, 4), n);
+       }
+
+       if (length - n)
+               n += dump_raw(fp, contents + n, "unknown", length - n, n);
+
+       fprintf(fp, "%05lX EOF\n", (unsigned long)n);
+
+       razor_file_free_contents(contents, length);
+
+       return 0;
+}
index 93a58c5..fd1a777 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef _RAZOR_H_
 #define _RAZOR_H_
 
+#include <stdio.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -631,4 +632,7 @@ char *razor_path_add_root(const char *path, const char *root) RAZOR_MALLOC;
 
 const char *razor_system_arch(void);
 
+int razor_dump_database(FILE *fp, const char *root, const char *filename,
+                       struct razor_error **error);
+
 #endif /* _RAZOR_H_ */
index 2d42128..7224762 100644 (file)
 
 #include "types.h"
 
-#define RAZOR_ENTRY_LAST       0x80
-#define RAZOR_ENTRY_FIRST      0x40
-#define RAZOR_IMMEDIATE                (RAZOR_ENTRY_LAST | RAZOR_ENTRY_FIRST)
-#define RAZOR_EMPTY_LIST       0xff
-
 void
 list_set_empty(struct list_head *head)
 {
index 8739257..8596271 100644 (file)
@@ -38,6 +38,11 @@ void array_release(struct array *array);
 void *array_add(struct array *array, int size);
 
 
+#define RAZOR_ENTRY_LAST       0x80
+#define RAZOR_ENTRY_FIRST      0x40
+#define RAZOR_IMMEDIATE                (RAZOR_ENTRY_LAST | RAZOR_ENTRY_FIRST)
+#define RAZOR_EMPTY_LIST       0xff
+
 struct list_head {
        uint32_t list_ptr : 24;
        uint32_t flags    : 8;
index 5eb9e09..d9d66b3 100644 (file)
@@ -1671,6 +1671,35 @@ command_download(int argc, char * const argv[])
 }
 
 static int
+command_dump(int argc, char * const argv[])
+{
+       struct razor_error *error = NULL;
+       const char *filename;
+
+       switch (razor_getopt(argc, argv, 0, NULL, "[filename]", NULL)) {
+               case -2:
+                       return 0;
+               case -1:
+                       return 1;
+       }
+
+       if (argc - optind > 1) {
+               razor_usage(argv[0], 0, NULL, "[filename]");
+               return 1;
+       }
+
+       filename = argv[optind];
+
+       if (razor_dump_database(stdout, install_root, filename, &error)) {
+               fprintf(stderr, "%s\n", razor_error_get_msg(error));
+               razor_error_free(error);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
 command_info(int argc, char * const argv[])
 {
        struct razor_error *error = NULL;
@@ -1796,6 +1825,7 @@ static struct {
 } razor_commands[] = {
        { "diff", "Show diff between two package sets", command_diff },
        { "download", "Download packages", command_download },
+       { "dump", "Low-level database dump (for debugging)", command_dump },
        { "help", "List available commands", command_help },
 #if HAVE_RPMLIB
        { "import-rpmdb", "Import the system rpm database",