ali@457: /* ali@475: * Copyright (C) 2014, 2016 J. Ali Harlow ali@457: * ali@457: * This program is free software; you can redistribute it and/or modify ali@457: * it under the terms of the GNU General Public License as published by ali@457: * the Free Software Foundation; either version 2 of the License, or ali@457: * (at your option) any later version. ali@457: * ali@457: * This program is distributed in the hope that it will be useful, ali@457: * but WITHOUT ANY WARRANTY; without even the implied warranty of ali@457: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ali@457: * GNU General Public License for more details. ali@457: * ali@457: * You should have received a copy of the GNU General Public License along ali@457: * with this program; if not, write to the Free Software Foundation, Inc., ali@457: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ali@457: */ ali@457: ali@457: #include "config.h" ali@457: ali@457: #include ali@457: #include ali@457: #include ali@457: ali@457: #include "razor.h" ali@457: #include "razor-internal.h" ali@457: ali@457: static size_t ali@457: dump_raw(FILE *fp, void *raw, char *what, size_t length, size_t offset) ali@457: { ali@457: size_t i, n = 0; ali@457: unsigned char *bytes = raw; ali@457: ali@457: while (length) { ali@457: fprintf(fp, "%05lX %s", (unsigned long)(offset + n), what); ali@457: for (i = 0; (i < 16) && (length > 0);) { ali@457: if (length >= 4) { ali@457: fprintf(fp, " %08X", *(uint32_t *)bytes); ali@457: bytes += 4; ali@457: n += 4; ali@457: length -= 4; ali@457: i += 4; ali@457: } else if (length >= 2) { ali@457: fprintf(fp, " %04X", *(unsigned short *)bytes); ali@457: bytes += 2; ali@457: n += 2; ali@457: length -= 2; ali@457: i += 2; ali@457: } else { ali@457: fprintf(fp, " %02X", *bytes); ali@457: bytes++; ali@457: n++; ali@457: length--; ali@457: i++; ali@457: } ali@457: } ali@457: fprintf(fp, "\n"); ali@457: } ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_string(FILE *fp, char *pool, size_t length, size_t offset) ali@457: { ali@457: size_t n = 0; ali@457: unsigned char c; ali@457: ali@457: fprintf(fp, "\""); ali@457: while (offset + n < length) { ali@457: c = pool[offset + n++]; ali@457: if (c == '\0') { ali@457: fprintf(fp, "\\0"); ali@457: break; ali@457: } ali@457: else if (c == '\\' || c == '"') ali@457: fprintf(fp, "\\%c", c); ali@457: else if (c >= ' ' && c <= '~') ali@457: fprintf(fp, "%c", c); ali@457: else ali@457: fprintf(fp, "\\x%02X", c); ali@457: } ali@457: fprintf(fp, "\""); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_pool(FILE *fp, char *pool, char *what, size_t length, size_t offset) ali@457: { ali@457: size_t n = 0; ali@457: ali@457: fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what); ali@457: ali@457: while (n < length) { ali@457: fprintf(fp, " %08X ", (uint32_t)n); ali@457: n += dump_string(fp, pool, length, n); ali@457: fprintf(fp, "\n"); ali@457: } ali@457: ali@457: fprintf(fp, "}\n"); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_header(FILE *fp, struct razor_set_header *header, size_t length, ali@457: size_t offset) ali@457: { ali@457: if (length >= sizeof(*header)) { ali@457: fprintf(fp, "%05lX header ", (unsigned long)offset); ali@457: fprintf(fp, "{ magic=%08X version=%08X num_sections=%08X }\n", ali@457: header->magic, header->version, header->num_sections); ali@457: return sizeof(*header); ali@457: } else ali@457: return dump_raw(fp, header, "unknown", length, offset); ali@457: } ali@457: ali@457: static size_t ali@457: dump_section(FILE *fp, struct razor_set_section *section, size_t length, ali@457: size_t offset, int indx) ali@457: { ali@457: if (length >= sizeof(*section)) { ali@457: fprintf(fp, "%05lX section %X ", (unsigned long)offset, indx); ali@457: fprintf(fp, "{ name=%08X offset=%08X size=%08X }\n", ali@457: section->name, section->offset, section->size); ali@457: return sizeof(*section); ali@457: } else ali@457: return dump_raw(fp, section, "unknown", length, offset); ali@457: } ali@457: ali@457: static void ali@457: dump_list_head(FILE *fp, struct list_head *head) ali@457: { ali@457: fprintf(fp, "{ list_ptr=%06X flags=%02X ", ali@457: head->list_ptr, head->flags); ali@457: if (head->flags == RAZOR_EMPTY_LIST) ali@457: fprintf(fp, "(EMPTY_LIST) "); ali@457: else if (head->flags == RAZOR_IMMEDIATE) ali@457: fprintf(fp, "(IMMEDIATE) "); ali@457: fprintf(fp,"}"); ali@457: } ali@457: ali@457: static void ali@457: dump_list_link(FILE *fp, struct list *list) ali@457: { ali@457: fprintf(fp, "{ data=%06X flags=%02X ", ali@457: list->data, list->flags); ali@457: if (list->flags == RAZOR_ENTRY_LAST) ali@457: fprintf(fp, "(ENTRY_LAST) "); ali@457: else if (list->flags == RAZOR_ENTRY_FIRST) ali@457: fprintf(fp, "(ENTRY_FIRST) "); ali@457: fprintf(fp,"}"); ali@457: } ali@457: ali@457: static void ali@457: expand_pooled_string(FILE *fp, struct array *pool, uint32_t str) ali@457: { ali@457: if (pool->data && str < pool->size) { ali@457: fprintf(fp, "("); ali@457: dump_string(fp, pool->data, pool->size, str); ali@457: fprintf(fp, ") "); ali@457: } ali@457: } ali@457: ali@457: static size_t ali@457: dump_package(FILE *fp, struct razor_package *package, size_t length, ali@457: size_t offset, struct array *string_pool, int indx) ali@457: { ali@457: if (length >= sizeof(*package)) { ali@457: fprintf(fp, " %05lX package %X ", (unsigned long)offset, ali@457: indx); ali@457: fprintf(fp, "{ name=%06X ", package->name); ali@457: expand_pooled_string(fp, string_pool, package->name); ali@457: fprintf(fp, "flags=%02X\n version=%08X ", ali@457: package->flags, package->version); ali@457: expand_pooled_string(fp, string_pool, package->version); ali@457: fprintf(fp, "arch=%08X ", package->arch); ali@457: expand_pooled_string(fp, string_pool, package->arch); ali@457: fprintf(fp, "\n " ali@457: "summary=%08X description=%08X url=%08X license=%08X\n", ali@457: package->summary, package->description, ali@457: package->url, package->license); ali@457: fprintf(fp," properties="); ali@457: dump_list_head(fp, &package->properties); ali@457: fprintf(fp,"\n"); ali@457: fprintf(fp," files="); ali@457: dump_list_head(fp, &package->files); ali@457: fprintf(fp,"\n"); ali@457: fprintf(fp," install_prefixes="); ali@457: dump_list_head(fp, &package->install_prefixes); ali@457: fprintf(fp,"\n"); ali@457: fprintf(fp," preun={ program=%08X body=%08X }\n", ali@457: package->preun.program, package->preun.body); ali@457: fprintf(fp," postun={ program=%08X body=%08X }\n", ali@457: package->postun.program, package->postun.body); ali@457: fprintf(fp," }\n"); ali@457: return sizeof(*package); ali@457: } else ali@457: return dump_raw(fp, package, "unknown", length, offset); ali@457: } ali@457: ali@457: static size_t ali@457: dump_packages(FILE *fp, struct razor_package *packages, size_t length, ali@457: size_t offset, struct array *string_pool) ali@457: { ali@457: size_t n = 0; ali@457: int i = 0; ali@457: ali@457: fprintf(fp, "%05lX packages {\n", (unsigned long)offset); ali@457: ali@457: while (n < length) { ali@457: n += dump_package(fp, packages, length - n, n, string_pool, i); ali@457: packages++; ali@457: i++; ali@457: } ali@457: ali@457: fprintf(fp, "}\n"); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_property(FILE *fp, struct razor_property *property, size_t length, ali@457: size_t offset, struct array *string_pool) ali@457: { ali@457: if (length >= sizeof(*property)) { ali@457: fprintf(fp, " %05lX property ", (unsigned long)offset); ali@457: fprintf(fp, "{ name=%08X ", property->name); ali@457: expand_pooled_string(fp, string_pool, property->name); ali@457: fprintf(fp, "\n flags=%08X (", property->flags); ali@457: if (property->flags & RAZOR_PROPERTY_LESS) ali@457: fprintf(fp, "<"); ali@457: if (property->flags & RAZOR_PROPERTY_GREATER) ali@457: fprintf(fp, ">"); ali@457: if (property->flags & RAZOR_PROPERTY_EQUAL) ali@457: fprintf(fp, "="); ali@457: switch (property->flags & RAZOR_PROPERTY_TYPE_MASK) { ali@457: case RAZOR_PROPERTY_REQUIRES: ali@457: fprintf(fp, " requires"); ali@457: break; ali@457: case RAZOR_PROPERTY_PROVIDES: ali@457: fprintf(fp, " provides"); ali@457: break; ali@457: case RAZOR_PROPERTY_CONFLICTS: ali@457: fprintf(fp, " conflicts"); ali@457: break; ali@457: case RAZOR_PROPERTY_OBSOLETES: ali@457: fprintf(fp, " obsoletes"); ali@457: break; ali@457: } ali@457: if (property->flags & RAZOR_PROPERTY_PRE) ali@457: fprintf(fp, " pre"); ali@457: if (property->flags & RAZOR_PROPERTY_POST) ali@457: fprintf(fp, " post"); ali@457: if (property->flags & RAZOR_PROPERTY_PREUN) ali@457: fprintf(fp, " preun"); ali@457: if (property->flags & RAZOR_PROPERTY_POSTUN) ali@457: fprintf(fp, " postun"); ali@457: fprintf(fp, ") version=%08X ", property->version); ali@457: expand_pooled_string(fp, string_pool, property->version); ali@457: fprintf(fp,"\n packages="); ali@457: dump_list_head(fp, &property->packages); ali@457: fprintf(fp,"\n"); ali@457: fprintf(fp," }\n"); ali@457: return sizeof(*property); ali@457: } else ali@457: return dump_raw(fp, property, "unknown", length, offset); ali@457: } ali@457: ali@457: static size_t ali@457: dump_properties(FILE *fp, struct razor_property *properties, size_t length, ali@457: size_t offset, struct array *string_pool) ali@457: { ali@457: size_t n = 0; ali@457: ali@457: fprintf(fp, "%05lX properties {\n", (unsigned long)offset); ali@457: ali@457: while (n < length) { ali@457: n += dump_property(fp, properties, length - n, n, string_pool); ali@457: properties++; ali@457: } ali@457: ali@457: fprintf(fp, "}\n"); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_entry(FILE *fp, struct razor_entry *entry, size_t length, size_t offset, ali@457: struct array *string_pool, int indx) ali@457: { ali@457: if (length >= sizeof(*entry)) { ali@457: fprintf(fp, " %05lX entry %X ", (unsigned long)offset, indx); ali@457: fprintf(fp, "{ name=%06X ", entry->name); ali@457: expand_pooled_string(fp, string_pool, entry->name); ali@457: fprintf(fp, "\n flags=%02X ", entry->flags); ali@457: if (entry->flags == RAZOR_ENTRY_LAST) ali@457: fprintf(fp, "(LAST) "); ali@457: fprintf(fp, "start=%08X", entry->start); ali@457: if (!entry->start) ali@457: fprintf(fp, " (NONE)"); ali@457: fprintf(fp,"\n packages="); ali@457: dump_list_head(fp, &entry->packages); ali@457: fprintf(fp,"\n"); ali@457: fprintf(fp," }\n"); ali@457: return sizeof(*entry); ali@457: } else ali@457: return dump_raw(fp, entry, "unknown", length, offset); ali@457: } ali@457: ali@457: static size_t ali@457: dump_files(FILE *fp, struct razor_entry *entries, size_t length, size_t offset, ali@457: struct array *string_pool) ali@457: { ali@457: size_t n = 0; ali@457: int i = 0; ali@457: ali@457: fprintf(fp, "%05lX files {\n", (unsigned long)offset); ali@457: ali@457: while (n < length) { ali@457: n += dump_entry(fp, entries, length - n, n, string_pool, i); ali@457: i++; ali@457: entries++; ali@457: } ali@457: ali@457: fprintf(fp, "}\n"); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: static size_t ali@457: dump_lists(FILE *fp, struct list *lists, char *what, size_t length, ali@457: size_t offset) ali@457: { ali@457: int i = 0; ali@457: size_t n = 0; ali@457: ali@457: fprintf(fp, "%05lX %s {\n", (unsigned long)offset, what); ali@457: ali@457: while (n + sizeof(*lists) <= length) { ali@457: fprintf(fp, " list %06X ", i); ali@457: dump_list_link(fp, lists); ali@457: fprintf(fp, "\n"); ali@457: n += sizeof(*lists); ali@457: lists++; ali@457: i++; ali@457: } ali@457: ali@457: if (length - n) ali@457: n += dump_raw(fp, lists, "unknown", length - n, offset + n); ali@457: ali@457: fprintf(fp, "}\n"); ali@457: ali@457: return n; ali@457: } ali@457: ali@457: RAZOR_EXPORT int ali@475: razor_dump_database(FILE *fp, const char *root_uri, const char *filename, ali@457: struct razor_error **error) ali@457: { ali@457: int i; ali@475: char *s, *uri, *data; ali@457: struct array pool = { 0, }; ali@457: struct array string_pool = { 0, }; ali@457: struct array file_string_pool = { 0, }; ali@457: struct array details_string_pool = { 0, }; ali@457: unsigned char *contents; ali@457: size_t length, len, n, min_offset; ali@457: struct razor_set_header *header; ali@457: struct razor_set_section *section, *sections; ali@457: struct razor_package *package; ali@457: struct razor_property *prop; ali@457: struct razor_entry *entry; ali@457: struct list *list; ali@457: ali@457: if (!filename) ali@457: filename = "system.rzdb"; ali@457: ali@475: uri = razor_resolve_database_file(root_uri, filename, error); ali@475: ali@475: if (!uri) ali@475: return -1; ali@475: ali@475: contents = razor_uri_get_contents(uri, &length, 0, error); ali@475: ali@475: free(uri); ali@457: ali@457: if (!contents) ali@457: return -1; ali@457: ali@457: n = 0; ali@457: ali@457: header = (void *)contents; ali@457: ali@457: if (length - n) ali@457: n += dump_header(fp, header, length - n, n); ali@457: ali@457: min_offset = length; ali@457: sections = (void *)(contents + n); ali@457: for (i = 0; i < header->num_sections; i++) { ali@457: if (n == length) ali@457: break; ali@457: section = (void *)(contents + n); ali@457: if (section->offset < min_offset) ali@457: min_offset = section->offset; ali@457: n += dump_section(fp, section, length - n, n, i); ali@457: } ali@457: ali@457: if (length - n) { ali@457: pool.data = (char *)(contents + n); ali@457: pool.size = min_offset - n; ali@457: n += dump_pool(fp, pool.data, "pool", pool.size, n); ali@457: } ali@457: ali@457: if ((length - n) && PADDING(n, 4)) ali@457: n += dump_raw(fp, contents + n, "padding", PADDING(n, 4), n); ali@457: ali@457: for (i = 0; length - n && i < header->num_sections; i++) { ali@457: if (sections[i].name < pool.size && ali@457: ((char *)pool.data)[pool.size - 1] == '\0') ali@457: s = pool.data + sections[i].name; ali@457: else ali@457: continue; ali@457: ali@457: data = (char *)(contents + sections[i].offset); ali@457: ali@457: if (!strcmp(s, "string_pool")) { ali@457: string_pool.data = data; ali@457: string_pool.size = sections[i].size; ali@457: } else if (!strcmp(s, "file_string_pool")) { ali@457: file_string_pool.data = data; ali@457: file_string_pool.size = sections[i].size; ali@457: } else if (!strcmp(s, "details_string_pool")) { ali@457: details_string_pool.data = data; ali@457: details_string_pool.size = sections[i].size; ali@457: } ali@457: } ali@457: ali@457: for (i = 0; i < header->num_sections; i++) { ali@457: if (n == length) ali@457: break; ali@457: section = sections + i; ali@457: if (section->offset != n) ali@457: continue; ali@457: len = section->size; ali@457: if (len > length - n) ali@457: len = length - n; ali@457: ali@457: if (section->name < pool.size && ali@457: ((char *)pool.data)[pool.size - 1] == '\0') ali@457: s = pool.data + section->name; ali@457: else ali@457: s = "unknown"; ali@457: ali@457: if (!strcmp(s, "string_pool") || ali@457: !strcmp(s, "file_string_pool") || ali@457: !strcmp(s, "details_string_pool")) ali@457: n += dump_pool(fp, (char *)(contents + n), s, len, n); ali@457: else if (!strcmp(s, "packages")) { ali@457: package = (void *)(contents + n); ali@457: n += dump_packages(fp, package, len, n, &string_pool); ali@457: } else if (!strcmp(s, "properties")) { ali@457: prop = (void *)(contents + n); ali@457: n += dump_properties(fp, prop, len, n, &string_pool); ali@457: } else if (!strcmp(s, "files")) { ali@457: entry = (void *)(contents + n); ali@457: n += dump_files(fp, entry, len, n, &file_string_pool); ali@457: } else if (!strcmp(s, "package_pool") || ali@457: !strcmp(s, "property_pool") || ali@457: !strcmp(s, "prefix_pool") || ali@457: !strcmp(s, "file_pool")) { ali@457: list = (void *)(contents + n); ali@457: n += dump_lists(fp, list, s, len, n); ali@457: } else ali@457: n += dump_raw(fp, contents + n, s, len, n); ali@457: ali@457: if ((length - n) && PADDING(n, 4)) ali@457: n += dump_raw(fp, contents + n, "padding", ali@457: PADDING(n, 4), n); ali@457: } ali@457: ali@457: if (length - n) ali@457: n += dump_raw(fp, contents + n, "unknown", length - n, n); ali@457: ali@457: fprintf(fp, "%05lX EOF\n", (unsigned long)n); ali@457: ali@475: razor_uri_free_contents(contents, length); ali@457: ali@457: return 0; ali@457: }