/* * Copyright (C) 2014 J. Ali Harlow * * 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 #include #include #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; }