From 3ce6a8ad9a4145e85d7340a038fbdaf05ec0e8bc Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 27 Nov 2011 20:39:31 +0100 Subject: [PATCH] Extract debuginfo. --- .gitignore | 1 + INSTALL | 4 + macros/build.macro | 9 + macros/constants.macro | 5 +- macros/templates.macro | 19 + po/pakfire.pot | 26 +- python/pakfire/builder.py | 24 +- python/pakfire/packages/file.py | 20 +- python/pakfire/packages/make.py | 4 + python/pakfire/packages/packager.py | 6 +- scripts/Makefile | 20 +- scripts/debugedit.c | 1673 +++++++++++++++++++++++++++ scripts/extract-debuginfo | 266 +++++ scripts/hashtab.c | 523 +++++++++ scripts/hashtab.h | 143 +++ scripts/rpmiotypes.h | 653 +++++++++++ scripts/rpmsw.h | 157 +++ scripts/rpmtag.h | 1243 ++++++++++++++++++++ 18 files changed, 4773 insertions(+), 23 deletions(-) create mode 100644 scripts/debugedit.c create mode 100755 scripts/extract-debuginfo create mode 100644 scripts/hashtab.c create mode 100644 scripts/hashtab.h create mode 100644 scripts/rpmiotypes.h create mode 100644 scripts/rpmsw.h create mode 100644 scripts/rpmtag.h diff --git a/.gitignore b/.gitignore index dce47cacc..9f18a8729 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /python/pakfire/__version__.py /tmp +/scripts/debugedit *.py[co] *.o *.[ms]o diff --git a/INSTALL b/INSTALL index 02b60260b..32b5205cf 100644 --- a/INSTALL +++ b/INSTALL @@ -8,6 +8,10 @@ Requirements: * libcap * libsolv * xz + * beecrypt (requires libgomp) + * popt + * libelf + * elfutils Install instructions: diff --git a/macros/build.macro b/macros/build.macro index fae499a10..aa795db9e 100644 --- a/macros/build.macro +++ b/macros/build.macro @@ -1,6 +1,9 @@ def MACRO_EXTRACT_TARBALL + # Remove old data if existant. + rm -rf %{DIR_APP} + for source in %{sources}; do %{MACRO_EXTRACT} %{DIR_DL}/${source} || exit 1 done @@ -68,6 +71,7 @@ build make_install_targets = install def _prepare + rm -rf %{BUILDROOT}/* mkdir -p %{DIR_SRC} && cd %{DIR_SRC} %{prepare} @@ -151,4 +155,9 @@ build # XXX to be removed soon def install_post end + + # Enable strict processing of build-id by default. + # The build will fail if a file is missing its build-id. + debuginfo_strict_build_id = true + debuginfo_options = end diff --git a/macros/constants.macro b/macros/constants.macro index 8a9121d27..aeab1eff5 100644 --- a/macros/constants.macro +++ b/macros/constants.macro @@ -1,10 +1,11 @@ -BUILDROOT = %{DIR_TMP}/buildroot_%{name}-%{thisver} +BUILDROOT = %{DIR_BUILD}/%{name}-%{thisver} +DIR_BUILD = /builddir DIR_APP = %{DIR_SRC}/%{thisapp} DIR_DL = %{BASEDIR}/files DIR_PATCHES = %{BASEDIR}/patches -DIR_SRC = /usr/src +DIR_SRC = %{DIR_BUILD}/source DIR_TMP = /tmp DIR_SOURCE = %{BASEDIR} diff --git a/macros/templates.macro b/macros/templates.macro index 21538c98d..5ab342d15 100644 --- a/macros/templates.macro +++ b/macros/templates.macro @@ -8,6 +8,8 @@ packages template MAIN def files / + !/usr/lib/debug + !/usr/src/debug end def configfiles @@ -52,4 +54,21 @@ packages def configfiles end end + + template DEBUGINFO + summary = Debug information for package %{thisapp}. + description + This package provides debug information for package %{thisapp}. + + Debug information is useful when developing applications that use + this package or when debugging this package. + end + + group = Development/Debug Debug + + files + /usr/lib/debug + /usr/src/debug + end + end end diff --git a/po/pakfire.pot b/po/pakfire.pot index 2777e36b4..15ee15d7e 100644 --- a/po/pakfire.pot +++ b/po/pakfire.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-12-09 20:38+0100\n" +"POT-Creation-Date: 2011-12-10 23:35+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -178,25 +178,29 @@ msgstr "" #. Package the result. #. Make all these little package from the build environment. -#: ../python/pakfire/builder.py:837 +#: ../python/pakfire/builder.py:838 msgid "Creating packages:" msgstr "" #. Execute the buildscript of this stage. -#: ../python/pakfire/builder.py:857 +#: ../python/pakfire/builder.py:858 #, python-format msgid "Running stage %s:" msgstr "" -#: ../python/pakfire/builder.py:875 +#: ../python/pakfire/builder.py:876 #, python-format msgid "Could not remove static libraries: %s" msgstr "" -#: ../python/pakfire/builder.py:881 +#: ../python/pakfire/builder.py:882 msgid "Compressing man pages did not complete successfully." msgstr "" +#: ../python/pakfire/builder.py:902 +msgid "Extracting debuginfo did not complete with success. Aborting build." +msgstr "" + #: ../python/pakfire/cli.py:43 msgid "Pakfire command line interface." msgstr "" @@ -641,17 +645,17 @@ msgstr "" msgid "Filename: %s" msgstr "" -#: ../python/pakfire/packages/file.py:250 +#: ../python/pakfire/packages/file.py:256 #, python-format -msgid "File in archive is missing in file metadata: /%s. Skipping." +msgid "File in archive is missing in file metadata: %s. Skipping." msgstr "" -#: ../python/pakfire/packages/file.py:306 +#: ../python/pakfire/packages/file.py:312 #, python-format msgid "Config file created as %s" msgstr "" -#: ../python/pakfire/packages/file.py:320 +#: ../python/pakfire/packages/file.py:326 #, python-format msgid "Could not remove file: /%s" msgstr "" @@ -665,11 +669,11 @@ msgid "Package version is undefined." msgstr "" #. Load progressbar. -#: ../python/pakfire/packages/packager.py:358 +#: ../python/pakfire/packages/packager.py:362 msgid "Packaging" msgstr "" -#: ../python/pakfire/packages/packager.py:630 +#: ../python/pakfire/packages/packager.py:634 #, python-format msgid "Building source package %s:" msgstr "" diff --git a/python/pakfire/builder.py b/python/pakfire/builder.py index 0aa29aa0e..d196c27ce 100644 --- a/python/pakfire/builder.py +++ b/python/pakfire/builder.py @@ -156,7 +156,7 @@ class BuildEnviron(object): self.log.info("") # Path where we extract the package and put all the source files. - self.build_dir = os.path.join(self.path, "usr/src", self.pkg.friendly_name) + self.build_dir = os.path.join(self.path, "usr/src/packages", self.pkg.friendly_name) else: # No package :( self.pkg = None @@ -831,6 +831,7 @@ class Builder(object): # Run post-build stuff. self.post_compress_man_pages() self.post_remove_static_libs() + self.post_extract_debuginfo() # Package the result. # Make all these little package from the build environment. @@ -880,6 +881,27 @@ class Builder(object): except Error, e: log.warning(_("Compressing man pages did not complete successfully.")) + def post_extract_debuginfo(self): + args = [] + + # Check if we need to run with strict build-id. + strict_id = self.pkg.lexer.build.get_var("debuginfo_strict_build_id", "true") + if strict_id in ("true", "yes", "1"): + args.append("--strict-build-id") + + args.append("--buildroot=%s" % self.pkg.buildroot) + args.append("--sourcedir=%s" % self.pkg.sourcedir) + + # Get additional options to pass to script. + options = self.pkg.lexer.build.get_var("debuginfo_options", "") + args += options.split() + + try: + self.do("%s/extract-debuginfo %s %s" % (SCRIPT_DIR, " ".join(args), self.pkg.buildroot)) + except Error, e: + log.error(_("Extracting debuginfo did not complete with success. Aborting build.")) + raise + def cleanup(self): if os.path.exists(self.buildroot): util.rm(self.buildroot) diff --git a/python/pakfire/packages/file.py b/python/pakfire/packages/file.py index a585221e0..2b9487750 100644 --- a/python/pakfire/packages/file.py +++ b/python/pakfire/packages/file.py @@ -232,10 +232,10 @@ class FilePackage(Package): name2file = {} for file in self.filelist: - name = file.name - if file.is_dir(): - name = name[:-1] + name = file.name[:-1] + else: + name = file.name name2file[name] = file @@ -245,9 +245,15 @@ class FilePackage(Package): if not member: break - file = name2file.get("/%s" % member.name, None) - if not file: - log.warning(_("File in archive is missing in file metadata: /%s. Skipping.") % member.name) + # Check if file is also known in metadata. + name = member.name + if not name.startswith("/"): + name = "/%s" % name + + try: + file = name2file[name] + except KeyError: + log.warning(_("File in archive is missing in file metadata: %s. Skipping.") % name) continue # Update progress. @@ -467,7 +473,7 @@ class FilePackage(Package): if not line[7] == "-": file.hash1 = line[7] - if self.format >= 3 and not line[8] == "-": + if self.format >= 3 and len(line) >= 9 and not line[8] == "-": file.capabilities = line[8] else: diff --git a/python/pakfire/packages/make.py b/python/pakfire/packages/make.py index e430a9125..9380e3ce5 100644 --- a/python/pakfire/packages/make.py +++ b/python/pakfire/packages/make.py @@ -152,6 +152,10 @@ class MakefileBase(Package): def buildroot(self): return self.lexer.get_var("BUILDROOT") + @property + def sourcedir(self): + return self.lexer.get_var("DIR_SRC") + @property def build_host(self): return socket.gethostname() diff --git a/python/pakfire/packages/packager.py b/python/pakfire/packages/packager.py index a0046d688..282696292 100644 --- a/python/pakfire/packages/packager.py +++ b/python/pakfire/packages/packager.py @@ -138,7 +138,11 @@ class Packager(object): f = open(filelist, "w") datafile = InnerTarFileXz.open(datafile) - for m in datafile.getmembers(): + while True: + m = datafile.next() + if not m: + break + log.debug(" %s %-8s %-8s %s %6s %s" % \ (tarfile.filemode(m.mode), m.uname, m.gname, "%d-%02d-%02d %02d:%02d:%02d" % time.localtime(m.mtime)[:6], diff --git a/scripts/Makefile b/scripts/Makefile index e3922fd33..223a5db79 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -1,13 +1,25 @@ include ../Makeconfig +# Elfutils +LIBS_ELF = -lelf + +# Beecrypt +LIBS_BEECRYPT = -lbeecrypt -lgomp + +# popt +LIBS_POPT = -lpopt + SCRIPTS = $(SCRIPTS_BIN) $(SCRIPTS_SHELL) -SCRIPTS_BIN = +SCRIPTS_BIN = \ + debugedit + SCRIPTS_SHELL = \ chroot-shell \ cleanup \ compress-man-pages \ dependency-tracker \ + extract-debuginfo \ pakfire-multicall.py \ patch \ py-compile \ @@ -20,6 +32,12 @@ SCRIPTS_SHELL = \ .PHONY: all all: $(SCRIPTS) +%.o: %.c Makefile + $(CC) $(CFLAGS) -I. -o $@ -c $< + +debugedit: debugedit.o hashtab.o + $(CC) $(CFLAGS) $(LIBS_BEECRYPT) $(LIBS_ELF) $(LIBS_POPT) -o $@ $? + .PHONY: install install: $(SCRIPTS) -mkdir -pv $(DESTDIR)$(SCRIPT_DIR) diff --git a/scripts/debugedit.c b/scripts/debugedit.c new file mode 100644 index 000000000..bc6bf70c3 --- /dev/null +++ b/scripts/debugedit.c @@ -0,0 +1,1673 @@ +/* Copyright (C) 2001, 2002, 2003, 2005, 2007, 2009 Red Hat, Inc. + Written by Alexander Larsson , 2002 + Based on code by Jakub Jelinek , 2001. + + 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Needed for libelf */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* some defines taken from the dwarf standard */ + +#define DW_TAG_compile_unit 0x11 + +#define DW_AT_name 0x03 +#define DW_AT_stmt_list 0x10 +#define DW_AT_comp_dir 0x1b + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 + +#include +#include "hashtab.h" +#include + +#define DW_TAG_partial_unit 0x3c + +char *base_dir = NULL; +char *dest_dir = NULL; +char *list_file = NULL; +int list_file_fd = -1; +int do_build_id = 0; + +typedef struct +{ + Elf *elf; + GElf_Ehdr ehdr; + Elf_Scn **scn; + const char *filename; + int lastscn; + GElf_Shdr shdr[0]; +} DSO; + +typedef struct +{ + unsigned char *ptr; + rpmuint32_t addend; +} REL; + +#define read_uleb128(ptr) ({ \ + unsigned int ret = 0; \ + unsigned int c; \ + int shift = 0; \ + do \ + { \ + c = *ptr++; \ + ret |= (c & 0x7f) << shift; \ + shift += 7; \ + } while (c & 0x80); \ + \ + if (shift >= 35) \ + ret = UINT_MAX; \ + ret; \ +}) + +static rpmuint16_t (*do_read_16) (unsigned char *ptr); +static rpmuint32_t (*do_read_32) (unsigned char *ptr); +static void (*write_32) (unsigned char *ptr, GElf_Addr val); + +static int ptr_size; +static int cu_version; + +static inline rpmuint16_t +buf_read_ule16 (unsigned char *data) +{ + return data[0] | (data[1] << 8); +} + +static inline rpmuint16_t +buf_read_ube16 (unsigned char *data) +{ + return data[1] | (data[0] << 8); +} + +static inline rpmuint32_t +buf_read_ule32 (unsigned char *data) +{ + return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +} + +static inline rpmuint32_t +buf_read_ube32 (unsigned char *data) +{ + return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); +} + +static const char * +strptr (DSO *dso, int sec, off_t offset) +{ + Elf_Scn *scn; + Elf_Data *data; + + scn = dso->scn[sec]; + if (offset >= 0 && (GElf_Addr) offset < dso->shdr[sec].sh_size) + { + data = NULL; + while ((data = elf_rawdata (scn, data)) != NULL) + { + if (data->d_buf + && offset >= data->d_off + && offset < data->d_off + (off_t)data->d_size) + return (const char *) data->d_buf + (offset - data->d_off); + } + } + + return NULL; +} + + +#define read_1(ptr) *ptr++ + +#define read_16(ptr) ({ \ + rpmuint16_t ret = do_read_16 (ptr); \ + ptr += 2; \ + ret; \ +}) + +#define read_32(ptr) ({ \ + rpmuint32_t ret = do_read_32 (ptr); \ + ptr += 4; \ + ret; \ +}) + +REL *relptr, *relend; +int reltype; + +#define do_read_32_relocated(ptr) ({ \ + rpmuint32_t dret = do_read_32 (ptr); \ + if (relptr) \ + { \ + while (relptr < relend && relptr->ptr < ptr) \ + ++relptr; \ + if (relptr < relend && relptr->ptr == ptr) \ + { \ + if (reltype == SHT_REL) \ + dret += relptr->addend; \ + else \ + dret = relptr->addend; \ + } \ + } \ + dret; \ +}) + +#define read_32_relocated(ptr) ({ \ + rpmuint32_t ret = do_read_32_relocated (ptr); \ + ptr += 4; \ + ret; \ +}) + +static void +dwarf2_write_le32 (unsigned char *p, GElf_Addr val) +{ + rpmuint32_t v = (rpmuint32_t) val; + + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +} + + +static void +dwarf2_write_be32 (unsigned char *p, GElf_Addr val) +{ + rpmuint32_t v = (rpmuint32_t) val; + + p[3] = v; + p[2] = v >> 8; + p[1] = v >> 16; + p[0] = v >> 24; +} + +static struct + { + const char *name; + unsigned char *data; + Elf_Data *elf_data; + size_t size; + int sec, relsec; + } debug_sections[] = + { +#define DEBUG_INFO 0 +#define DEBUG_ABBREV 1 +#define DEBUG_LINE 2 +#define DEBUG_ARANGES 3 +#define DEBUG_PUBNAMES 4 +#define DEBUG_PUBTYPES 5 +#define DEBUG_MACINFO 6 +#define DEBUG_LOC 7 +#define DEBUG_STR 8 +#define DEBUG_FRAME 9 +#define DEBUG_RANGES 10 + { ".debug_info", NULL, NULL, 0, 0, 0 }, + { ".debug_abbrev", NULL, NULL, 0, 0, 0 }, + { ".debug_line", NULL, NULL, 0, 0, 0 }, + { ".debug_aranges", NULL, NULL, 0, 0, 0 }, + { ".debug_pubnames", NULL, NULL, 0, 0, 0 }, + { ".debug_pubtypes", NULL, NULL, 0, 0, 0 }, + { ".debug_macinfo", NULL, NULL, 0, 0, 0 }, + { ".debug_loc", NULL, NULL, 0, 0, 0 }, + { ".debug_str", NULL, NULL, 0, 0, 0 }, + { ".debug_frame", NULL, NULL, 0, 0, 0 }, + { ".debug_ranges", NULL, NULL, 0, 0, 0 }, + { NULL, NULL, NULL, 0, 0, 0 } + }; + +struct abbrev_attr + { + unsigned int attr; + unsigned int form; + }; + +struct abbrev_tag + { + unsigned int entry; + unsigned int tag; + int nattr; + struct abbrev_attr attr[0]; + }; + +static hashval_t +abbrev_hash (const void *p) +{ + struct abbrev_tag *t = (struct abbrev_tag *)p; + + return t->entry; +} + +static int +abbrev_eq (const void *p, const void *q) +{ + struct abbrev_tag *t1 = (struct abbrev_tag *)p; + struct abbrev_tag *t2 = (struct abbrev_tag *)q; + + return t1->entry == t2->entry; +} + +static void +abbrev_del (void *p) +{ + free (p); +} + +static htab_t +read_abbrev (DSO *dso, unsigned char *ptr) +{ + htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del); + unsigned int attr, form; + struct abbrev_tag *t; + int size; + void **slot; + + if (h == NULL) + { +no_memory: + error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename); + if (h) + htab_delete (h); + return NULL; + } + + while ((attr = read_uleb128 (ptr)) != 0) + { + size = 10; + t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr)); + if (t == NULL) + goto no_memory; + t->entry = attr; + t->nattr = 0; + slot = htab_find_slot (h, t, INSERT); + if (slot == NULL) + { + free (t); + goto no_memory; + } + if (*slot != NULL) + { + error (0, 0, "%s: Duplicate DWARF abbreviation %d", dso->filename, + t->entry); + free (t); + htab_delete (h); + return NULL; + } + t->tag = read_uleb128 (ptr); + ++ptr; /* skip children flag. */ + while ((attr = read_uleb128 (ptr)) != 0) + { + if (t->nattr == size) + { + size += 10; + t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr)); + if (t == NULL) + goto no_memory; + } + form = read_uleb128 (ptr); + if (form == 2 || form > DW_FORM_indirect) + { + error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form); + htab_delete (h); + return NULL; + } + + t->attr[t->nattr].attr = attr; + t->attr[t->nattr++].form = form; + } + if (read_uleb128 (ptr) != 0) + { + error (0, 0, "%s: DWARF abbreviation does not end with 2 zeros", + dso->filename); + htab_delete (h); + return NULL; + } + *slot = t; + } + + return h; +} + +#define IS_DIR_SEPARATOR(c) ((c)=='/') + +static char * +canonicalize_path (const char *s, char *d) +{ + char *rv = d; + const char *sroot; + char *droot; + + if (IS_DIR_SEPARATOR (*s)) + { + *d++ = *s++; + if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1])) + { + /* Special case for "//foo" meaning a Posix namespace + escape. */ + *d++ = *s++; + } + while (IS_DIR_SEPARATOR (*s)) + s++; + } + droot = d; + sroot = s; + + while (*s) + { + /* At this point, we're always at the beginning of a path + segment. */ + + if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1]))) + { + s++; + if (*s) + while (IS_DIR_SEPARATOR (*s)) + ++s; + } + + else if (s[0] == '.' && s[1] == '.' + && (s[2] == 0 || IS_DIR_SEPARATOR (s[2]))) + { + char *pre = d - 1; /* includes slash */ + while (droot < pre && IS_DIR_SEPARATOR (*pre)) + pre--; + if (droot <= pre && ! IS_DIR_SEPARATOR (*pre)) + { + while (droot < pre && ! IS_DIR_SEPARATOR (*pre)) + pre--; + /* pre now points to the slash */ + if (droot < pre) + pre++; + if (pre + 3 == d && pre[0] == '.' && pre[1] == '.') + { + *d++ = *s++; + *d++ = *s++; + } + else + { + d = pre; + s += 2; + if (*s) + while (IS_DIR_SEPARATOR (*s)) + s++; + } + } + else + { + *d++ = *s++; + *d++ = *s++; + } + } + else + { + while (*s && ! IS_DIR_SEPARATOR (*s)) + *d++ = *s++; + } + + if (IS_DIR_SEPARATOR (*s)) + { + *d++ = *s++; + while (IS_DIR_SEPARATOR (*s)) + s++; + } + } + while (droot < d && IS_DIR_SEPARATOR (d[-1])) + --d; + if (d == rv) + *d++ = '.'; + *d = 0; + + return rv; +} + +static int +has_prefix (const char *str, + const char *prefix) +{ + size_t str_len; + size_t prefix_len; + + str_len = strlen (str); + prefix_len = strlen (prefix); + + if (str_len < prefix_len) + return 0; + + return strncmp (str, prefix, prefix_len) == 0; +} + +static int +edit_dwarf2_line (DSO *dso, rpmuint32_t off, char *comp_dir, int phase) +{ + unsigned char *ptr = debug_sections[DEBUG_LINE].data, *dir; + unsigned char **dirt; + unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size; + unsigned char *endcu, *endprol; + unsigned char opcode_base; + rpmuint32_t value, dirt_cnt; + size_t comp_dir_len = strlen (comp_dir); + size_t abs_file_cnt = 0, abs_dir_cnt = 0; + + if (phase != 0) + return 0; + + ptr += off; + + endcu = ptr + 4; + endcu += read_32 (ptr); + if (endcu == ptr + 0xffffffff) + { + error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); + return 1; + } + + if (endcu > endsec) + { + error (0, 0, "%s: .debug_line CU does not fit into section", + dso->filename); + return 1; + } + + value = read_16 (ptr); + if (value != 2 && value != 3) + { + error (0, 0, "%s: DWARF version %d unhandled", dso->filename, + value); + return 1; + } + + endprol = ptr + 4; + endprol += read_32 (ptr); + if (endprol > endcu) + { + error (0, 0, "%s: .debug_line CU prologue does not fit into CU", + dso->filename); + return 1; + } + + opcode_base = ptr[4]; + ptr = dir = ptr + 4 + opcode_base; + + /* dir table: */ + value = 1; + while (*ptr != 0) + { + ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1; + ++value; + } + + dirt = (unsigned char **) alloca (value * sizeof (unsigned char *)); + dirt[0] = (unsigned char *) "."; + dirt_cnt = 1; + ptr = dir; + while (*ptr != 0) + { + dirt[dirt_cnt++] = ptr; + ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1; + } + ptr++; + + /* file table: */ + while (*ptr != 0) + { + char *s, *file; + size_t file_len, dir_len; + + file = (char *) ptr; + ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1; + value = read_uleb128 (ptr); + + if (value >= dirt_cnt) + { + error (0, 0, "%s: Wrong directory table index %u", + dso->filename, value); + return 1; + } + file_len = strlen (file); + dir_len = strlen ((char *)dirt[value]); + s = malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1); + if (s == NULL) + { + error (0, ENOMEM, "%s: Reading file table", dso->filename); + return 1; + } + if (*file == '/') + { + memcpy (s, file, file_len + 1); + if (dest_dir && has_prefix (file, base_dir)) + ++abs_file_cnt; + } + else if (*dirt[value] == '/') + { + memcpy (s, dirt[value], dir_len); + s[dir_len] = '/'; + memcpy (s + dir_len + 1, file, file_len + 1); + } + else + { + char *p = s; + if (comp_dir_len != 0) + { + memcpy (s, comp_dir, comp_dir_len); + s[comp_dir_len] = '/'; + p += comp_dir_len + 1; + } + memcpy (p, dirt[value], dir_len); + p[dir_len] = '/'; + memcpy (p + dir_len + 1, file, file_len + 1); + } + canonicalize_path (s, s); + if (list_file_fd != -1) + { + char *p = NULL; + if (base_dir == NULL) + p = s; + else if (has_prefix (s, base_dir)) + p = s + strlen (base_dir); + else if (has_prefix (s, dest_dir)) + p = s + strlen (dest_dir); + + if (p) + { + size_t size = strlen (p) + 1; + while (size > 0) + { + ssize_t ret = write (list_file_fd, p, size); + if (ret == -1) + break; + size -= ret; + p += ret; + } + } + } + + free (s); + + read_uleb128 (ptr); + read_uleb128 (ptr); + } + ++ptr; + + if (dest_dir) + { + unsigned char *srcptr, *buf = NULL; + size_t base_len = strlen (base_dir); + size_t dest_len = strlen (dest_dir); + size_t shrank = 0; + + if (dest_len == base_len) + abs_file_cnt = 0; + if (abs_file_cnt) + { + srcptr = buf = malloc (ptr - dir); + memcpy (srcptr, dir, ptr - dir); + ptr = dir; + } + else + ptr = srcptr = dir; + while (*srcptr != 0) + { + size_t len = strlen ((char *)srcptr) + 1; + const unsigned char *readptr = srcptr; + + if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir)) + { + if (dest_len < base_len) + ++abs_dir_cnt; + memcpy (ptr, dest_dir, dest_len); + ptr += dest_len; + readptr += base_len; + } + srcptr += len; + + shrank += srcptr - readptr; + canonicalize_path ((char *)readptr, (char *)ptr); + len = strlen ((char *)ptr) + 1; + shrank -= len; + ptr += len; + + elf_flagdata (debug_sections[DEBUG_STR].elf_data, + ELF_C_SET, ELF_F_DIRTY); + } + + if (shrank > 0) + { + if (--shrank == 0) + error (EXIT_FAILURE, 0, + "canonicalization unexpectedly shrank by one character"); + else + { + memset (ptr, 'X', shrank); + ptr += shrank; + *ptr++ = '\0'; + } + } + + if (abs_dir_cnt + abs_file_cnt != 0) + { + size_t len = (abs_dir_cnt + abs_file_cnt) * (base_len - dest_len); + + if (len == 1) + error (EXIT_FAILURE, 0, "-b arg has to be either the same length as -d arg, or more than 1 char shorter"); + memset (ptr, 'X', len - 1); + ptr += len - 1; + *ptr++ = '\0'; + } + *ptr++ = '\0'; + ++srcptr; + + while (*srcptr != 0) + { + size_t len = strlen ((char *)srcptr) + 1; + + if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir)) + { + memcpy (ptr, dest_dir, dest_len); + if (dest_len < base_len) + { + memmove (ptr + dest_len, srcptr + base_len, + len - base_len); + ptr += dest_len - base_len; + } + elf_flagdata (debug_sections[DEBUG_STR].elf_data, + ELF_C_SET, ELF_F_DIRTY); + } + else if (ptr != srcptr) + memmove (ptr, srcptr, len); + srcptr += len; + ptr += len; + dir = srcptr; + read_uleb128 (srcptr); + read_uleb128 (srcptr); + read_uleb128 (srcptr); + if (ptr != dir) + memmove (ptr, dir, srcptr - dir); + ptr += srcptr - dir; + } + *ptr = '\0'; + free (buf); + } + return 0; +} + + + +static unsigned char * +edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) +{ + int i; + rpmuint32_t list_offs; + int found_list_offs; + char *comp_dir; + + comp_dir = NULL; + list_offs = 0; + found_list_offs = 0; + for (i = 0; i < t->nattr; ++i) + { + rpmuint32_t form = t->attr[i].form; + size_t len = 0; + size_t base_len, dest_len; + + + while (1) + { + if (t->attr[i].attr == DW_AT_stmt_list) + { + if (form == DW_FORM_data4) + { + list_offs = do_read_32_relocated (ptr); + found_list_offs = 1; + } + } + + if (t->attr[i].attr == DW_AT_comp_dir) + { + if ( form == DW_FORM_string ) + { + free (comp_dir); + comp_dir = strdup ((char *)ptr); + + if (phase == 1 && dest_dir && has_prefix ((char *)ptr, base_dir)) + { + base_len = strlen (base_dir); + dest_len = strlen (dest_dir); + + memcpy (ptr, dest_dir, dest_len); + if (dest_len < base_len) + { + memset(ptr + dest_len, '/', + base_len - dest_len); + + } + elf_flagdata (debug_sections[DEBUG_INFO].elf_data, + ELF_C_SET, ELF_F_DIRTY); + } + } + + else if (form == DW_FORM_strp && + debug_sections[DEBUG_STR].data) + { + char *dir; + + dir = (char *) debug_sections[DEBUG_STR].data + + do_read_32_relocated (ptr); + + free (comp_dir); + comp_dir = strdup (dir); + + if (phase == 1 && dest_dir && has_prefix (dir, base_dir)) + { + base_len = strlen (base_dir); + dest_len = strlen (dest_dir); + + memcpy (dir, dest_dir, dest_len); + if (dest_len < base_len) + { + memmove (dir + dest_len, dir + base_len, + strlen (dir + base_len) + 1); + } + elf_flagdata (debug_sections[DEBUG_STR].elf_data, + ELF_C_SET, ELF_F_DIRTY); + } + } + } + else if ((t->tag == DW_TAG_compile_unit + || t->tag == DW_TAG_partial_unit) + && t->attr[i].attr == DW_AT_name + && form == DW_FORM_strp + && debug_sections[DEBUG_STR].data) + { + char *name; + + name = (char *) debug_sections[DEBUG_STR].data + + do_read_32_relocated (ptr); + if (*name == '/' && comp_dir == NULL) + { + char *enddir = strrchr (name, '/'); + + if (enddir != name) + { + comp_dir = malloc (enddir - name + 1); + memcpy (comp_dir, name, enddir - name); + comp_dir [enddir - name] = '\0'; + } + else + comp_dir = strdup ("/"); + } + + if (phase == 1 && dest_dir && has_prefix (name, base_dir)) + { + base_len = strlen (base_dir); + dest_len = strlen (dest_dir); + + memcpy (name, dest_dir, dest_len); + if (dest_len < base_len) + { + memmove (name + dest_len, name + base_len, + strlen (name + base_len) + 1); + } + elf_flagdata (debug_sections[DEBUG_STR].elf_data, + ELF_C_SET, ELF_F_DIRTY); + } + } + + switch (form) + { + case DW_FORM_ref_addr: + if (cu_version == 2) + ptr += ptr_size; + else + ptr += 4; + break; + case DW_FORM_addr: + ptr += ptr_size; + break; + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_data1: + ++ptr; + break; + case DW_FORM_ref2: + case DW_FORM_data2: + ptr += 2; + break; + case DW_FORM_ref4: + case DW_FORM_data4: + ptr += 4; + break; + case DW_FORM_ref8: + case DW_FORM_data8: + ptr += 8; + break; + case DW_FORM_sdata: + case DW_FORM_ref_udata: + case DW_FORM_udata: + read_uleb128 (ptr); + break; + case DW_FORM_strp: + ptr += 4; + break; + case DW_FORM_string: + ptr = (unsigned char *) strchr ((char *)ptr, '\0') + 1; + break; + case DW_FORM_indirect: + form = read_uleb128 (ptr); + continue; + case DW_FORM_block1: + len = *ptr++; + break; + case DW_FORM_block2: + len = read_16 (ptr); + form = DW_FORM_block1; + break; + case DW_FORM_block4: + len = read_32 (ptr); + form = DW_FORM_block1; + break; + case DW_FORM_block: + len = read_uleb128 (ptr); + form = DW_FORM_block1; + assert (len < UINT_MAX); + break; + default: + error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, + form); + return NULL; + } + + if (form == DW_FORM_block1) + ptr += len; + + break; + } + } + + /* Ensure the CU current directory will exist even if only empty. Source + filenames possibly located in its parent directories refer relatively to + it and the debugger (GDB) cannot safely optimize out the missing + CU current dir subdirectories. */ + if (comp_dir && list_file_fd != -1) + { + char *p; + size_t size; + + if (base_dir && has_prefix (comp_dir, base_dir)) + p = comp_dir + strlen (base_dir); + else if (dest_dir && has_prefix (comp_dir, dest_dir)) + p = comp_dir + strlen (dest_dir); + else + p = comp_dir; + + size = strlen (p) + 1; + while (size > 0) + { + ssize_t ret = write (list_file_fd, p, size); + if (ret == -1) + break; + size -= ret; + p += ret; + } + } + + if (found_list_offs && comp_dir) + edit_dwarf2_line (dso, list_offs, comp_dir, phase); + + free (comp_dir); + + return ptr; +} + +static int +rel_cmp (const void *a, const void *b) +{ + REL *rela = (REL *) a, *relb = (REL *) b; + + if (rela->ptr < relb->ptr) + return -1; + + if (rela->ptr > relb->ptr) + return 1; + + return 0; +} + +static int +edit_dwarf2 (DSO *dso) +{ + Elf_Data *data; + Elf_Scn *scn; + int i, j; + + for (i = 0; debug_sections[i].name; ++i) + { + debug_sections[i].data = NULL; + debug_sections[i].size = 0; + debug_sections[i].sec = 0; + debug_sections[i].relsec = 0; + } + ptr_size = 0; + + for (i = 1; i < dso->ehdr.e_shnum; ++i) + if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) + && dso->shdr[i].sh_size) + { + const char *name = strptr (dso, dso->ehdr.e_shstrndx, + dso->shdr[i].sh_name); + + if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0) + { + for (j = 0; debug_sections[j].name; ++j) + if (strcmp (name, debug_sections[j].name) == 0) + { + if (debug_sections[j].data) + { + error (0, 0, "%s: Found two copies of %s section", + dso->filename, name); + return 1; + } + + scn = dso->scn[i]; + data = elf_rawdata (scn, NULL); + assert (data != NULL && data->d_buf != NULL); + assert (elf_rawdata (scn, data) == NULL); + assert (data->d_off == 0); + assert (data->d_size == dso->shdr[i].sh_size); + debug_sections[j].data = data->d_buf; + debug_sections[j].elf_data = data; + debug_sections[j].size = data->d_size; + debug_sections[j].sec = i; + break; + } + + if (debug_sections[j].name == NULL) + { + error (0, 0, "%s: Unknown debugging section %s", + dso->filename, name); + } + } + else if (dso->ehdr.e_type == ET_REL + && ((dso->shdr[i].sh_type == SHT_REL + && strncmp (name, ".rel.debug_", + sizeof (".rel.debug_") - 1) == 0) + || (dso->shdr[i].sh_type == SHT_RELA + && strncmp (name, ".rela.debug_", + sizeof (".rela.debug_") - 1) == 0))) + { + for (j = 0; debug_sections[j].name; ++j) + if (strcmp (name + sizeof (".rel") - 1 + + (dso->shdr[i].sh_type == SHT_RELA), + debug_sections[j].name) == 0) + { + debug_sections[j].relsec = i; + break; + } + } + } + + if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + { + do_read_16 = buf_read_ule16; + do_read_32 = buf_read_ule32; + write_32 = dwarf2_write_le32; + } + else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) + { + do_read_16 = buf_read_ube16; + do_read_32 = buf_read_ube32; + write_32 = dwarf2_write_be32; + } + else + { + error (0, 0, "%s: Wrong ELF data enconding", dso->filename); + return 1; + } + + if (debug_sections[DEBUG_INFO].data != NULL) + { + unsigned char *ptr, *endcu, *endsec; + rpmuint32_t value; + htab_t abbrev; + struct abbrev_tag tag, *t; + int phase; + REL *relbuf = NULL; + + if (debug_sections[DEBUG_INFO].relsec) + { + int ndx, maxndx; + GElf_Rel rel; + GElf_Rela rela; + GElf_Sym sym; + GElf_Addr base = dso->shdr[debug_sections[DEBUG_INFO].sec].sh_addr; + Elf_Data *symdata = NULL; + int rtype; + + i = debug_sections[DEBUG_INFO].relsec; + scn = dso->scn[i]; + data = elf_getdata (scn, NULL); + assert (data != NULL && data->d_buf != NULL); + assert (elf_getdata (scn, data) == NULL); + assert (data->d_off == 0); + assert (data->d_size == dso->shdr[i].sh_size); + maxndx = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize; + relbuf = malloc (maxndx * sizeof (REL)); + reltype = dso->shdr[i].sh_type; + if (relbuf == NULL) + error (1, errno, "%s: Could not allocate memory", dso->filename); + + symdata = elf_getdata (dso->scn[dso->shdr[i].sh_link], NULL); + assert (symdata != NULL && symdata->d_buf != NULL); + assert (elf_getdata (dso->scn[dso->shdr[i].sh_link], symdata) + == NULL); + assert (symdata->d_off == 0); + assert (symdata->d_size + == dso->shdr[dso->shdr[i].sh_link].sh_size); + + for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) + { + if (dso->shdr[i].sh_type == SHT_REL) + { + gelf_getrel (data, ndx, &rel); + rela.r_offset = rel.r_offset; + rela.r_info = rel.r_info; + rela.r_addend = 0; + } + else + gelf_getrela (data, ndx, &rela); + gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); + /* Relocations against section symbols are uninteresting + in REL. */ + if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) + continue; + /* Only consider relocations against .debug_str, .debug_line + and .debug_abbrev. */ + if (sym.st_shndx != debug_sections[DEBUG_STR].sec + && sym.st_shndx != debug_sections[DEBUG_LINE].sec + && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) + continue; + rela.r_addend += sym.st_value; + rtype = ELF64_R_TYPE (rela.r_info); + switch (dso->ehdr.e_machine) + { + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) + goto fail; + break; + case EM_386: + if (rtype != R_386_32) + goto fail; + break; + case EM_PPC: + case EM_PPC64: + if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) + goto fail; + break; + case EM_S390: + if (rtype != R_390_32) + goto fail; + break; + case EM_IA_64: + if (rtype != R_IA64_SECREL32LSB) + goto fail; + break; + case EM_X86_64: + if (rtype != R_X86_64_32) + goto fail; + break; + case EM_ALPHA: + if (rtype != R_ALPHA_REFLONG) + goto fail; + break; + default: + fail: + error (1, 0, "%s: Unhandled relocation %d in .debug_info section", + dso->filename, rtype); + } + relend->ptr = debug_sections[DEBUG_INFO].data + + (rela.r_offset - base); + relend->addend = rela.r_addend; + ++relend; + } + if (relbuf == relend) + { + free (relbuf); + relbuf = NULL; + relend = NULL; + } + else + qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); + } + + for (phase = 0; phase < 2; phase++) + { + ptr = debug_sections[DEBUG_INFO].data; + relptr = relbuf; + endsec = ptr + debug_sections[DEBUG_INFO].size; + while (ptr < endsec) + { + if (ptr + 11 > endsec) + { + error (0, 0, "%s: .debug_info CU header too small", + dso->filename); + return 1; + } + + endcu = ptr + 4; + endcu += read_32 (ptr); + if (endcu == ptr + 0xffffffff) + { + error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); + return 1; + } + + if (endcu > endsec) + { + error (0, 0, "%s: .debug_info too small", dso->filename); + return 1; + } + + cu_version = read_16 (ptr); + if (cu_version != 2 && cu_version != 3) + { + error (0, 0, "%s: DWARF version %d unhandled", dso->filename, + cu_version); + return 1; + } + + value = read_32_relocated (ptr); + if (value >= debug_sections[DEBUG_ABBREV].size) + { + if (debug_sections[DEBUG_ABBREV].data == NULL) + error (0, 0, "%s: .debug_abbrev not present", dso->filename); + else + error (0, 0, "%s: DWARF CU abbrev offset too large", + dso->filename); + return 1; + } + + if (ptr_size == 0) + { + ptr_size = read_1 (ptr); + if (ptr_size != 4 && ptr_size != 8) + { + error (0, 0, "%s: Invalid DWARF pointer size %d", + dso->filename, ptr_size); + return 1; + } + } + else if (read_1 (ptr) != ptr_size) + { + error (0, 0, "%s: DWARF pointer size differs between CUs", + dso->filename); + return 1; + } + + abbrev = read_abbrev (dso, + debug_sections[DEBUG_ABBREV].data + value); + if (abbrev == NULL) + return 1; + + while (ptr < endcu) + { + tag.entry = read_uleb128 (ptr); + if (tag.entry == 0) + continue; + t = htab_find_with_hash (abbrev, &tag, tag.entry); + if (t == NULL) + { + error (0, 0, "%s: Could not find DWARF abbreviation %d", + dso->filename, tag.entry); + htab_delete (abbrev); + return 1; + } + + ptr = edit_attributes (dso, ptr, t, phase); + if (ptr == NULL) + break; + } + + htab_delete (abbrev); + } + } + free (relbuf); + } + + return 0; +} + +static struct poptOption optionsTable[] = { + { "base-dir", 'b', POPT_ARG_STRING, &base_dir, 0, + "base build directory of objects", NULL }, + { "dest-dir", 'd', POPT_ARG_STRING, &dest_dir, 0, + "directory to rewrite base-dir into", NULL }, + { "list-file", 'l', POPT_ARG_STRING, &list_file, 0, + "file where to put list of source and header file names", NULL }, + { "build-id", 'i', POPT_ARG_NONE, &do_build_id, 0, + "recompute build ID note and print ID on stdout", NULL }, + POPT_AUTOHELP + { NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +static DSO * +fdopen_dso (int fd, const char *name) +{ + Elf *elf = NULL; + GElf_Ehdr ehdr; + int i; + DSO *dso = NULL; + + elf = elf_begin (fd, ELF_C_RDWR_MMAP, NULL); + if (elf == NULL) + { + error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1)); + goto error_out; + } + + if (elf_kind (elf) != ELF_K_ELF) + { + error (0, 0, "\"%s\" is not an ELF file", name); + goto error_out; + } + + if (gelf_getehdr (elf, &ehdr) == NULL) + { + error (0, 0, "cannot get the ELF header: %s", + elf_errmsg (-1)); + goto error_out; + } + + if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC && ehdr.e_type != ET_REL) + { + error (0, 0, "\"%s\" is not a shared library", name); + goto error_out; + } + + /* Allocate DSO structure. Leave place for additional 20 new section + headers. */ + dso = (DSO *) + malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr) + + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *)); + if (!dso) + { + error (0, ENOMEM, "Could not open DSO"); + goto error_out; + } + + elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT); + + memset (dso, 0, sizeof(DSO)); + dso->elf = elf; + dso->ehdr = ehdr; + dso->scn = (Elf_Scn **) &dso->shdr[ehdr.e_shnum + 20]; + + for (i = 0; i < ehdr.e_shnum; ++i) + { + dso->scn[i] = elf_getscn (elf, i); + gelf_getshdr (dso->scn[i], dso->shdr + i); + } + + dso->filename = (const char *) strdup (name); + return dso; + +error_out: + if (dso) + { + free ((char *) dso->filename); + free (dso); + } + if (elf) + elf_end (elf); + if (fd != -1) + close (fd); + return NULL; +} + +/* Compute a fresh build ID bit-string from the editted file contents. */ +static void +handle_build_id (DSO *dso, Elf_Data *build_id, + size_t build_id_offset, size_t build_id_size) +{ + hashFunctionContext ctx; + const hashFunction *hf = NULL; + int i = hashFunctionCount (); + + while (i-- > 0) + { + hf = hashFunctionGet (i); + if (hf != NULL && hf->digestsize == build_id_size) + break; + } + if (hf == NULL) + { + fprintf (stderr, "Cannot handle %Zu-byte build ID\n", build_id_size); + exit (1); + } + + if (elf_update (dso->elf, ELF_C_NULL) < 0) + { + fprintf (stderr, "Failed to update file: %s\n", + elf_errmsg (elf_errno ())); + exit (1); + } + + /* Clear the old bits so they do not affect the new hash. */ + memset ((char *) build_id->d_buf + build_id_offset, 0, build_id_size); + + hashFunctionContextInit (&ctx, hf); + + /* Slurp the relevant header bits and section contents and feed them + into the hash function. The only bits we ignore are the offset + fields in ehdr and shdrs, since the semantically identical ELF file + could be written differently if it doesn't change the phdr layout. + We always use the GElf (i.e. Elf64) formats for the bits to hash + since it is convenient. It doesn't matter whether this is an Elf32 + or Elf64 object, only that we are consistent in what bits feed the + hash so it comes out the same for the same file contents. */ + { + auto inline void process (const void *data, size_t size); + auto inline void process (const void *data, size_t size) + { + memchunk chunk = { .data = (void *) data, .size = size }; + hashFunctionContextUpdateMC (&ctx, &chunk); + } + union + { + GElf_Ehdr ehdr; + GElf_Phdr phdr; + GElf_Shdr shdr; + } u; + Elf_Data x = { .d_version = EV_CURRENT, .d_buf = &u }; + + x.d_type = ELF_T_EHDR; + x.d_size = sizeof u.ehdr; + u.ehdr = dso->ehdr; + u.ehdr.e_phoff = u.ehdr.e_shoff = 0; + if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL) + { + bad: + fprintf (stderr, "Failed to compute header checksum: %s\n", + elf_errmsg (elf_errno ())); + exit (1); + } + + x.d_type = ELF_T_PHDR; + x.d_size = sizeof u.phdr; + for (i = 0; i < dso->ehdr.e_phnum; ++i) + { + if (gelf_getphdr (dso->elf, i, &u.phdr) == NULL) + goto bad; + if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL) + goto bad; + process (x.d_buf, x.d_size); + } + + x.d_type = ELF_T_SHDR; + x.d_size = sizeof u.shdr; + for (i = 0; i < dso->ehdr.e_shnum; ++i) + if (dso->scn[i] != NULL) + { + u.shdr = dso->shdr[i]; + u.shdr.sh_offset = 0; + if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL) + goto bad; + process (x.d_buf, x.d_size); + + if (u.shdr.sh_type != SHT_NOBITS) + { + Elf_Data *d = elf_rawdata (dso->scn[i], NULL); + if (d == NULL) + goto bad; + process (d->d_buf, d->d_size); + } + } + } + + hashFunctionContextDigest (&ctx, (byte *) build_id->d_buf + build_id_offset); + hashFunctionContextFree (&ctx); + + elf_flagdata (build_id, ELF_C_SET, ELF_F_DIRTY); + + /* Now format the build ID bits in hex to print out. */ + { + const rpmuint8_t * id = (rpmuint8_t *)build_id->d_buf + build_id_offset; + char hex[build_id_size * 2 + 1]; + int n = snprintf (hex, 3, "%02" PRIx8, id[0]); + assert (n == 2); + for (i = 1; i < (int)build_id_size; ++i) + { + n = snprintf (&hex[i * 2], 3, "%02" PRIx8, id[i]); + assert (n == 2); + } + puts (hex); + } +} + +int +main (int argc, char *argv[]) +{ + DSO *dso; + int fd, i; + const char *file; + poptContext optCon; /* context for parsing command-line options */ + int nextopt; + const char **args; + struct stat stat_buf; + char *p; + Elf_Data *build_id = NULL; + size_t build_id_offset = 0, build_id_size = 0; + + optCon = poptGetContext("debugedit", argc, (const char **)argv, optionsTable, 0); + + while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT) + /* do nothing */ ; + + if (nextopt != -1) + { + fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n", + poptBadOption (optCon, 0), + poptStrerror (nextopt), + argv[0]); + exit (1); + } + + args = poptGetArgs (optCon); + if (args == NULL || args[0] == NULL || args[1] != NULL) + { + poptPrintHelp(optCon, stdout, 0); + exit (1); + } + + if (dest_dir != NULL) + { + if (base_dir == NULL) + { + fprintf (stderr, "You must specify a base dir if you specify a dest dir\n"); + exit (1); + } + if (strlen (dest_dir) > strlen (base_dir)) + { + fprintf (stderr, "Only dest dir longer than base dir not supported\n"); + exit (1); + } + } + + /* Make sure there are trailing slashes in dirs */ + if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/') + { + p = malloc (strlen (base_dir) + 2); + strcpy (p, base_dir); + strcat (p, "/"); + free (base_dir); + base_dir = p; + } + if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/') + { + p = malloc (strlen (dest_dir) + 2); + strcpy (p, dest_dir); + strcat (p, "/"); + free (dest_dir); + dest_dir = p; + } + + if (list_file != NULL) + { + list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644); + } + + file = args[0]; + + if (elf_version(EV_CURRENT) == EV_NONE) + { + fprintf (stderr, "library out of date\n"); + exit (1); + } + + if (stat(file, &stat_buf) < 0) + { + fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno)); + exit (1); + } + + /* Make sure we can read and write */ + chmod (file, stat_buf.st_mode | S_IRUSR | S_IWUSR); + + fd = open (file, O_RDWR); + if (fd < 0) + { + fprintf (stderr, "Failed to open input file '%s': %s\n", file, strerror(errno)); + exit (1); + } + + dso = fdopen_dso (fd, file); + if (dso == NULL) + exit (1); + + for (i = 1; i < dso->ehdr.e_shnum; i++) + { + const char *name; + + switch (dso->shdr[i].sh_type) + { + case SHT_PROGBITS: + case SHT_MIPS_DWARF: + name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name); + /* TODO: Handle stabs */ +#if 0 + if (strcmp (name, ".stab") == 0) + edit_stabs (dso, i); +#endif + if (strcmp (name, ".debug_info") == 0) + edit_dwarf2 (dso); + + break; + case SHT_NOTE: + if (do_build_id + && build_id == NULL && (dso->shdr[i].sh_flags & SHF_ALLOC)) + { + /* Look for a build-ID note here. */ + Elf_Data *data = elf_rawdata (elf_getscn (dso->elf, i), NULL); + Elf32_Nhdr nh; + Elf_Data dst = + { + .d_version = EV_CURRENT, .d_type = ELF_T_NHDR, + .d_buf = &nh, .d_size = sizeof nh + }; + Elf_Data src = dst; + src.d_buf = data->d_buf; + assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); + while ((char *) data->d_buf + data->d_size - + (char *) src.d_buf > (int) sizeof nh + && elf32_xlatetom (&dst, &src, dso->ehdr.e_ident[EI_DATA])) + { + Elf32_Word len = sizeof nh + nh.n_namesz; + len = (len + 3) & ~3; + + if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3 + && !memcmp ((char *) src.d_buf + sizeof nh, "GNU", sizeof "GNU")) + { + build_id = data; + build_id_offset = (char *) src.d_buf + len - + (char *) data->d_buf; + build_id_size = nh.n_descsz; + break; + } + + len += nh.n_descsz; + len = (len + 3) & ~3; + src.d_buf = (char *) src.d_buf + len; + } + } + break; + default: + break; + } + } + + if (do_build_id && build_id != NULL) + handle_build_id (dso, build_id, build_id_offset, build_id_size); + + if (elf_update (dso->elf, ELF_C_WRITE) < 0) + { + fprintf (stderr, "Failed to write file: %s\n", elf_errmsg (elf_errno())); + exit (1); + } + if (elf_end (dso->elf) < 0) + { + fprintf (stderr, "elf_end failed: %s\n", elf_errmsg (elf_errno())); + exit (1); + } + close (fd); + + /* Restore old access rights */ + chmod (file, stat_buf.st_mode); + + poptFreeContext (optCon); + + return 0; +} diff --git a/scripts/extract-debuginfo b/scripts/extract-debuginfo new file mode 100755 index 000000000..5999fa54c --- /dev/null +++ b/scripts/extract-debuginfo @@ -0,0 +1,266 @@ +#!/bin/bash +# extract-debuginfo.sh - automagically generate debug info +# +# Usage: extract-debuginfo.sh [--strict-build-id] [-g] [-r] +# [builddir] +# +# The -g flag says to use strip -g instead of full strip on DSOs. +# The --strict-build-id flag says to exit with failure status if +# any ELF binary processed fails to contain a build-id note. +# The -r flag says to use eu-strip --reloc-debug-sections. +# +# All file names in switches are relative to builddir (. if not given). +# + +echo "Extracting debuginfo to /usr/lib/debug..." + +export LC_ALL=C + +# With -g arg, pass it to strip on libraries. +strip_g=false + +# with -r arg, pass --reloc-debug-sections to eu-strip. +strip_r=false + +# Barf on missing build IDs. +strict=false + +BUILDDIR=. +while [ $# -gt 0 ]; do + case "${1}" in + --sourcedir=*) + SOURCEDIR=${1#--sourcedir=} + ;; + --buildroot=*) + BUILDROOT=${1#--buildroot=} + ;; + --strict-build-id) + strict=true + ;; + -g) + strip_g=true + ;; + -r) + strip_r=true + ;; + *) + BUILDDIR=${1} + shift + break + ;; + esac + shift +done + +debugdir="${BUILDROOT}/usr/lib/debug" + +# A list of source files that are included in the -debuginfo packages. +SOURCEFILE="$(mktemp)" + +strip_to_debug() { + local g= + local r= + ${strip_r} && r=--reloc-debug-sections + ${strip_g} && \ + case "$(file -bi "${2}")" in + application/x-sharedlib*) + g=-g + ;; + esac + + eu-strip --remove-comment ${r} ${g} -f "${1}" "${2}" || exit + chmod 444 "${1}" || exit +} + +# Make a relative symlink to $1 called $3$2 +shopt -s extglob +link_relative() { + local t="$1" f="$2" pfx="$3" + local fn="${f#/}" tn="${t#/}" + local fd td d + + while fd="${fn%%/*}"; td="${tn%%/*}"; [ "$fd" = "$td" ]; do + fn="${fn#*/}" + tn="${tn#*/}" + done + + d="${fn%/*}" + if [ "$d" != "$fn" ]; then + d="${d//+([!\/])/..}" + tn="${d}/${tn}" + fi + + mkdir -p "$(dirname "$pfx$f")" && ln -snf "$tn" "$pfx$f" +} + +# Make a symlink in /usr/lib/debug/$2 to $1 +debug_link() { + local l="/usr/lib/debug$2" + local t="$1" + link_relative "$t" "$l" "$BUILDROOT" +} + +# Provide .2, .3, ... symlinks to all filename instances of this build-id. +make_id_dup_link() { + local id="${1}" file="${2}" idfile + + local n=1 + while true; do + idfile=".build-id/${id:0:2}/${id:2}.${n}" + [ $# -eq 3 ] && idfile="${idfile}$3" + if [ ! -L "${BUILDROOT}/usr/lib/debug/${idfile}" ]; then + break + fi + n=$[${n}+1] + done + debug_link "${file}" "/${idfile}" +} + +# Make a build-id symlink for id $1 with suffix $3 to file $2. +make_id_link() { + local id="${1}" file="${2}" + local idfile=".build-id/${id:0:2}/${id:2}" + [ $# -eq 3 ] && idfile="${idfile}${3}" + local root_idfile="${BUILDROOT}/usr/lib/debug/${idfile}" + + if [ ! -L "${root_idfile}" ]; then + debug_link "${file}" "/${idfile}" + return + fi + + make_id_dup_link "$@" + + [ $# -eq 3 ] && return 0 + + local other=$(readlink -m "${root_idfile}") + other=${other#$BUILDROOT} + if cmp -s "${root_idfile}" "${BUILDROOT}${file}" || + eu-elfcmp -q "${root_idfile}" "${BUILDROOT}${file}" 2> /dev/null; then + # Two copies. Maybe one has to be setuid or something. + echo >&2 "*** WARNING: identical binaries are copied, not linked:" + echo >&2 " ${file}" + echo >&2 " and ${other}" + else + # This is pathological, break the build. + echo >&2 "*** ERROR: same build ID in nonidentical files!" + echo >&2 " ${file}" + echo >&2 " and ${other}" + exit 2 + fi +} + +get_debugfn() { + dn=$(dirname "${1#$BUILDROOT}") + bn=$(basename "$1" .debug).debug + + debugdn=${debugdir}${dn} + debugfn=${debugdn}/${bn} +} + +set -o pipefail + +strict_error=ERROR +${strict} || strict_error=WARNING + + +# Strip ELF binaries +find "$BUILDROOT" ! -path "${debugdir}/*.debug" -type f \ + \( -perm -0100 -or -perm -0010 -or -perm -0001 \) \ + -print | + file -N -f - | sed -n -e 's/^\(.*\):[ ]*.*ELF.*, not stripped/\1/p' | + xargs --no-run-if-empty stat -c '%h %D_%i %n' | + while read nlinks inum f; do + get_debugfn "${f}" + [ -f "${debugfn}" ] && continue + + # If this file has multiple links, keep track and make + # the corresponding .debug files all links to one file too. + if [ ${nlinks} -gt 1 ]; then + eval linked=\$linked_${inum} + if [ -n "${linked}" ]; then + eval id=\${linkedid_${inum}} + make_id_dup_link "${id}" "${dn}/$(basename ${f})" + make_id_dup_link "${id}" "/usr/lib/debug${dn}/${bn}" .debug + link=${debugfn} + get_debugfn "${linked}" + echo " hard linked ${link} to ${debugfn}" + mkdir -p "$(dirname "$link")" && ln -nf "$debugfn" "$link" + continue + else + eval linked_${inum}=\${f} + echo " file ${f} has $[${nlinks} - 1] other hard links" + fi + fi + + echo " Extracting debug info from ${f#${BUILDROOT}}" + id=$(/usr/lib/pakfire/debugedit -i \ + -b "${SOURCEDIR}" \ + -d /usr/src/debug \ + -l "${SOURCEFILE}" \ + "${f}") || exit + + if [ ${nlinks} -gt 1 ]; then + eval linkedid_${inum}=\${id} + fi + + if [ -z "$id" ]; then + echo >&2 "*** ${strict_error}: No build ID note found in ${f#${BUILDROOT}}" + ${strict} && exit 2 + fi + + [ -x /usr/bin/gdb-add-index ] && /usr/bin/gdb-add-index "${f}" > /dev/null 2>&1 + + # A binary already copied into /usr/lib/debug doesn't get stripped, + # just has its file names collected and adjusted. + case "${dn}" in + /usr/lib/debug/*) + [ -z "${id}" ] || make_id_link "${id}" "${dn}/$(basename ${f})" + continue + ;; + esac + + mkdir -p "${debugdn}" + if test -w "${f}"; then + strip_to_debug "${debugfn}" "${f}" + else + chmod u+w "${f}" + strip_to_debug "${debugfn}" "${f}" + chmod u-w "${f}" + fi + + if [ -n "${id}" ]; then + make_id_link "${id}" "${dn}/$(basename ${f})" + make_id_link "${id}" "/usr/lib/debug${dn}/${bn}" .debug + fi + done || exit + +# For each symlink whose target has a .debug file, +# make a .debug symlink to that file. +find $BUILDROOT ! -path "${debugdir}/*" -type l -print | + while read f; do + t=$(readlink -m "$f").debug + f=${f#$BUILDROOT} + t=${t#$BUILDROOT} + if [ -f "$debugdir$t" ]; then + echo "symlinked /usr/lib/debug$t to /usr/lib/debug${f}.debug" + debug_link "/usr/lib/debug$t" "${f}.debug" + fi + done + +if [ -s "${SOURCEFILE}" ]; then + mkdir -p "${BUILDROOT}/usr/src/debug" + + sort -z -u "${SOURCEFILE}" | grep -E -v -z '(|)$' | \ + (cd "${SOURCEDIR}"; cpio -pd0mL "${BUILDROOT}/usr/src/debug" 2>/dev/null) + + # stupid cpio creates new directories in mode 0700, fixup + find "${BUILDROOT}/usr/src/debug" -type d -print0 | \ + xargs --no-run-if-empty -0 chmod a+rx + + # Fix ownership. + chown root:root -R ${BUILDROOT}/usr/src/debug +fi + +rm -f ${SOURCEFILE} + +exit 0 diff --git a/scripts/hashtab.c b/scripts/hashtab.c new file mode 100644 index 000000000..e4985456c --- /dev/null +++ b/scripts/hashtab.c @@ -0,0 +1,523 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#include +#include +#include +#include +#include "hashtab.h" + +/* This macro defines reserved value for empty table entry. */ + +#define EMPTY_ENTRY ((void *) 0) + +/* This macro defines reserved value for table entry which contained + a deleted element. */ + +#define DELETED_ENTRY ((void *) 1) + +static unsigned long higher_prime_number (unsigned long); +static hashval_t hash_pointer (const void *); +static int eq_pointer (const void *, const void *); +static int htab_expand (htab_t); +static void **find_empty_slot_for_expand (htab_t, hashval_t); + +/* At some point, we could make these be NULL, and modify the + hash-table routines to handle NULL specially; that would avoid + function-call overhead for the common case of hashing pointers. */ +htab_hash htab_hash_pointer = hash_pointer; +htab_eq htab_eq_pointer = eq_pointer; + +/* The following function returns a nearest prime number which is + greater than N, and near a power of two. */ + +static unsigned long +higher_prime_number (n) + unsigned long n; +{ + /* These are primes that are near, but slightly smaller than, a + power of two. */ + static unsigned long primes[] = { + (unsigned long) 2, + (unsigned long) 7, + (unsigned long) 13, + (unsigned long) 31, + (unsigned long) 61, + (unsigned long) 127, + (unsigned long) 251, + (unsigned long) 509, + (unsigned long) 1021, + (unsigned long) 2039, + (unsigned long) 4093, + (unsigned long) 8191, + (unsigned long) 16381, + (unsigned long) 32749, + (unsigned long) 65521, + (unsigned long) 131071, + (unsigned long) 262139, + (unsigned long) 524287, + (unsigned long) 1048573, + (unsigned long) 2097143, + (unsigned long) 4194301, + (unsigned long) 8388593, + (unsigned long) 16777213, + (unsigned long) 33554393, + (unsigned long) 67108859, + (unsigned long) 134217689, + (unsigned long) 268435399, + (unsigned long) 536870909, + (unsigned long) 1073741789, + (unsigned long) 2147483647, + /* 4294967291L */ + ((unsigned long) 2147483647) + ((unsigned long) 2147483644), + }; + + unsigned long* low = &primes[0]; + unsigned long* high = &primes[sizeof(primes) / sizeof(primes[0])]; + + while (low != high) + { + unsigned long* mid = low + (high - low) / 2; + if (n > *mid) + low = mid + 1; + else + high = mid; + } + + /* If we've run out of primes, abort. */ + if (n > *low) + { + fprintf (stderr, "Cannot find prime bigger than %lu\n", n); + abort (); + } + + return *low; +} + +/* Returns a hash code for P. */ + +static hashval_t +hash_pointer (p) + const void * p; +{ + return (hashval_t) ((long)p >> 3); +} + +/* Returns non-zero if P1 and P2 are equal. */ + +static int +eq_pointer (p1, p2) + const void * p1; + const void * p2; +{ + return p1 == p2; +} + +/* This function creates table with length slightly longer than given + source length. The created hash table is initiated as empty (all the + hash table entries are EMPTY_ENTRY). The function returns the created + hash table. Memory allocation may fail; it may return NULL. */ + +htab_t +htab_try_create (size, hash_f, eq_f, del_f) + size_t size; + htab_hash hash_f; + htab_eq eq_f; + htab_del del_f; +{ + htab_t result; + + size = higher_prime_number (size); + result = (htab_t) calloc (1, sizeof (struct htab)); + if (result == NULL) + return NULL; + + result->entries = (void **) calloc (size, sizeof (void *)); + if (result->entries == NULL) + { + free (result); + return NULL; + } + + result->size = size; + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; + result->return_allocation_failure = 1; + return result; +} + +/* This function frees all memory allocated for given hash table. + Naturally the hash table must already exist. */ + +void +htab_delete (htab) + htab_t htab; +{ + int i; + + if (htab->del_f) + for (i = htab->size - 1; i >= 0; i--) + if (htab->entries[i] != EMPTY_ENTRY + && htab->entries[i] != DELETED_ENTRY) + (*htab->del_f) (htab->entries[i]); + + free (htab->entries); + free (htab); +} + +/* This function clears all entries in the given hash table. */ + +void +htab_empty (htab) + htab_t htab; +{ + int i; + + if (htab->del_f) + for (i = htab->size - 1; i >= 0; i--) + if (htab->entries[i] != EMPTY_ENTRY + && htab->entries[i] != DELETED_ENTRY) + (*htab->del_f) (htab->entries[i]); + + memset (htab->entries, 0, htab->size * sizeof (void *)); +} + +/* Similar to htab_find_slot, but without several unwanted side effects: + - Does not call htab->eq_f when it finds an existing entry. + - Does not change the count of elements/searches/collisions in the + hash table. + This function also assumes there are no deleted entries in the table. + HASH is the hash value for the element to be inserted. */ + +static void ** +find_empty_slot_for_expand (htab, hash) + htab_t htab; + hashval_t hash; +{ + size_t size = htab->size; + hashval_t hash2 = 1 + hash % (size - 2); + unsigned int index = hash % size; + + for (;;) + { + void **slot = htab->entries + index; + + if (*slot == EMPTY_ENTRY) + return slot; + else if (*slot == DELETED_ENTRY) + abort (); + + index += hash2; + if (index >= size) + index -= size; + } +} + +/* The following function changes size of memory allocated for the + entries and repeatedly inserts the table elements. The occupancy + of the table after the call will be about 50%. Naturally the hash + table must already exist. Remember also that the place of the + table entries is changed. If memory allocation failures are allowed, + this function will return zero, indicating that the table could not be + expanded. If all goes well, it will return a non-zero value. */ + +static int +htab_expand (htab) + htab_t htab; +{ + void **oentries; + void **olimit; + void **p; + + oentries = htab->entries; + olimit = oentries + htab->size; + + htab->size = higher_prime_number (htab->size * 2); + + if (htab->return_allocation_failure) + { + void **nentries = (void **) calloc (htab->size, sizeof (void **)); + if (nentries == NULL) + return 0; + htab->entries = nentries; + } + + htab->n_elements -= htab->n_deleted; + htab->n_deleted = 0; + + p = oentries; + do + { + void * x = *p; + + if (x != EMPTY_ENTRY && x != DELETED_ENTRY) + { + void **q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); + + *q = x; + } + + p++; + } + while (p < olimit); + + free (oentries); + return 1; +} + +/* This function searches for a hash table entry equal to the given + element. It cannot be used to insert or delete an element. */ + +void * +htab_find_with_hash (htab, element, hash) + htab_t htab; + const void * element; + hashval_t hash; +{ + unsigned int index; + hashval_t hash2; + size_t size; + void * entry; + + htab->searches++; + size = htab->size; + index = hash % size; + + entry = htab->entries[index]; + if (entry == EMPTY_ENTRY + || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + + hash2 = 1 + hash % (size - 2); + + for (;;) + { + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; + if (entry == EMPTY_ENTRY + || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element))) + return entry; + } +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +void * +htab_find (htab, element) + htab_t htab; + const void * element; +{ + return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); +} + +/* This function searches for a hash table slot containing an entry + equal to the given element. To delete an entry, call this with + INSERT = 0, then call htab_clear_slot on the slot returned (possibly + after doing some checks). To insert an entry, call this with + INSERT = 1, then write the value you want into the returned slot. + When inserting an entry, NULL may be returned if memory allocation + fails. */ + +void ** +htab_find_slot_with_hash (htab, element, hash, insert) + htab_t htab; + const void * element; + hashval_t hash; + enum insert_option insert; +{ + void **first_deleted_slot; + unsigned int index; + hashval_t hash2; + size_t size; + + if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4 + && htab_expand (htab) == 0) + return NULL; + + size = htab->size; + hash2 = 1 + hash % (size - 2); + index = hash % size; + + htab->searches++; + first_deleted_slot = NULL; + + for (;;) + { + void * entry = htab->entries[index]; + if (entry == EMPTY_ENTRY) + { + if (insert == NO_INSERT) + return NULL; + + htab->n_elements++; + + if (first_deleted_slot) + { + *first_deleted_slot = EMPTY_ENTRY; + return first_deleted_slot; + } + + return &htab->entries[index]; + } + + if (entry == DELETED_ENTRY) + { + if (!first_deleted_slot) + first_deleted_slot = &htab->entries[index]; + } + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + } +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ + +void ** +htab_find_slot (htab, element, insert) + htab_t htab; + const void * element; + enum insert_option insert; +{ + return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), + insert); +} + +/* This function deletes an element with the given value from hash + table. If there is no matching element in the hash table, this + function does nothing. */ + +void +htab_remove_elt (htab, element) + htab_t htab; + void * element; +{ + void **slot; + + slot = htab_find_slot (htab, element, NO_INSERT); + if (*slot == EMPTY_ENTRY) + return; + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function clears a specified slot in a hash table. It is + useful when you've already done the lookup and don't want to do it + again. */ + +void +htab_clear_slot (htab, slot) + htab_t htab; + void **slot; +{ + if (slot < htab->entries || slot >= htab->entries + htab->size + || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY) + abort (); + + if (htab->del_f) + (*htab->del_f) (*slot); + + *slot = DELETED_ENTRY; + htab->n_deleted++; +} + +/* This function scans over the entire hash table calling + CALLBACK for each live entry. If CALLBACK returns false, + the iteration stops. INFO is passed as CALLBACK's second + argument. */ + +void +htab_traverse (htab, callback, info) + htab_t htab; + htab_trav callback; + void * info; +{ + void **slot = htab->entries; + void **limit = slot + htab->size; + + do + { + void * x = *slot; + + if (x != EMPTY_ENTRY && x != DELETED_ENTRY) + if (!(*callback) (slot, info)) + break; + } + while (++slot < limit); +} + +/* Return the current size of given hash table. */ + +size_t +htab_size (htab) + htab_t htab; +{ + return htab->size; +} + +/* Return the current number of elements in given hash table. */ + +size_t +htab_elements (htab) + htab_t htab; +{ + return htab->n_elements - htab->n_deleted; +} + +/* Return the fraction of fixed collisions during all work with given + hash table. */ + +double +htab_collisions (htab) + htab_t htab; +{ + if (htab->searches == 0) + return 0.0; + + return (double) htab->collisions / (double) htab->searches; +} diff --git a/scripts/hashtab.h b/scripts/hashtab.h new file mode 100644 index 000000000..9ed18aeaa --- /dev/null +++ b/scripts/hashtab.h @@ -0,0 +1,143 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* The type for a hash code. */ +typedef unsigned int hashval_t; + +/* Callback function pointer types. */ + +/* Calculate hash of a table entry. */ +typedef hashval_t (*htab_hash) (const void *); + +/* Compare a table entry with a possible entry. The entry already in + the table always comes first, so the second element can be of a + different type (but in this case htab_find and htab_find_slot + cannot be used; instead the variants that accept a hash value + must be used). */ +typedef int (*htab_eq) (const void *, const void *); + +/* Cleanup function called whenever a live element is removed from + the hash table. */ +typedef void (*htab_del) (void *); + +/* Function called by htab_traverse for each live element. The first + arg is the slot of the element (which can be passed to htab_clear_slot + if desired), the second arg is the auxiliary pointer handed to + htab_traverse. Return 1 to continue scan, 0 to stop. */ +typedef int (*htab_trav) (void **, void *); + +/* Hash tables are of the following type. The structure + (implementation) of this type is not needed for using the hash + tables. All work with hash table should be executed only through + functions mentioned below. */ + +struct htab +{ + /* Pointer to hash function. */ + htab_hash hash_f; + + /* Pointer to comparison function. */ + htab_eq eq_f; + + /* Pointer to cleanup function. */ + htab_del del_f; + + /* Table itself. */ + void **entries; + + /* Current size (in entries) of the hash table */ + size_t size; + + /* Current number of elements including also deleted elements */ + size_t n_elements; + + /* Current number of deleted elements in the table */ + size_t n_deleted; + + /* The following member is used for debugging. Its value is number + of all calls of `htab_find_slot' for the hash table. */ + unsigned int searches; + + /* The following member is used for debugging. Its value is number + of collisions fixed for time of work with the hash table. */ + unsigned int collisions; + + /* This is non-zero if we are allowed to return NULL for function calls + that allocate memory. */ + int return_allocation_failure; +}; + +typedef struct htab *htab_t; + +/* An enum saying whether we insert into the hash table or not. */ +enum insert_option {NO_INSERT, INSERT}; + +/* The prototypes of the package functions. */ + +/* This function is like htab_create, but may return NULL if memory + allocation fails, and also signals that htab_find_slot_with_hash and + htab_find_slot are allowed to return NULL when inserting. */ +extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del); +extern void htab_delete (htab_t); +extern void htab_empty (htab_t); + +extern void *htab_find (htab_t, const void *); +extern void **htab_find_slot (htab_t, const void *, enum insert_option); +extern void *htab_find_with_hash (htab_t, const void *, hashval_t); +extern void **htab_find_slot_with_hash (htab_t, const void *, hashval_t, + enum insert_option); +extern void htab_clear_slot (htab_t, void **); +extern void htab_remove_elt (htab_t, void *); + +extern void htab_traverse (htab_t, htab_trav, void *); + +extern size_t htab_size (htab_t); +extern size_t htab_elements (htab_t); +extern double htab_collisions (htab_t); + +/* A hash function for pointers. */ +extern htab_hash htab_hash_pointer; + +/* An equality function for pointers. */ +extern htab_eq htab_eq_pointer; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __HASHTAB_H */ diff --git a/scripts/rpmiotypes.h b/scripts/rpmiotypes.h new file mode 100644 index 000000000..04891a174 --- /dev/null +++ b/scripts/rpmiotypes.h @@ -0,0 +1,653 @@ +#ifndef _H_RPMIOTYPES_ +#define _H_RPMIOTYPES_ + +/** \ingroup rpmio + * \file rpmio/rpmiotypes.h + */ + +/** \ingroup rpmio + * RPM return codes. + */ +typedef enum rpmRC_e { + RPMRC_OK = 0, /*!< Generic success code */ + RPMRC_NOTFOUND = 1, /*!< Generic not found code. */ + RPMRC_FAIL = 2, /*!< Generic failure code. */ + RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */ + RPMRC_NOKEY = 4 /*!< Public key is unavailable. */ +} rpmRC; + +/** \ingroup rpmio + * Private int typedefs to avoid C99 portability issues. + */ +typedef /*@unsignedintegraltype@*/ unsigned char rpmuint8_t; +typedef /*@unsignedintegraltype@*/ unsigned short rpmuint16_t; +typedef /*@unsignedintegraltype@*/ unsigned int rpmuint32_t; +typedef /*@unsignedintegraltype@*/ unsigned long long rpmuint64_t; + +/** \ingroup rpmio + */ +typedef /*@signedintegraltype@*/ int rpmint32_t; + +/** + */ +typedef /*@refcounted@*/ struct rpmioItem_s * rpmioItem; +struct rpmioItem_s { +/*@null@*/ + void *use; /*!< use count -- return to pool when zero */ +/*@kept@*/ /*@null@*/ + void *pool; /*!< pool (or NULL if malloc'd) */ +#if defined(__LCLINT__) +/*@refs@*/ + int nrefs; /*!< (unused) keep splint happy */ +#endif +}; + +/** + */ +typedef struct rpmioPool_s * rpmioPool; + +/** \ingroup rpmio + */ +typedef /*@abstract@*/ /*@refcounted@*/ struct rpmiob_s * rpmiob; + +/** \ingroup rpmio + */ +/*@unchecked@*/ +extern size_t _rpmiob_chunk; + +/** \ingroup rpmio + */ +typedef struct rpmioP_s { + char * str; + char * next; + const char ** av; + int ac; +} * rpmioP; + +/** \ingroup rpmpgp + */ +typedef /*@abstract@*/ struct DIGEST_CTX_s * DIGEST_CTX; + +/** \ingroup rpmpgp + */ +typedef /*@abstract@*/ struct pgpPkt_s * pgpPkt; + +/** \ingroup rpmpgp + */ +typedef /*@abstract@*/ /*@refcounted@*/ struct pgpDig_s * pgpDig; + +/** \ingroup rpmpgp + */ +typedef /*@abstract@*/ struct pgpDigParams_s * pgpDigParams; + +/** \ingroup rpmpgp + */ +typedef rpmuint8_t pgpKeyID_t[8]; + +/** \ingroup rpmpgp + */ +typedef rpmuint8_t pgpTime_t[4]; + +/** \ingroup rpmpgp + * Bit(s) to control digest and signature verification. + */ +typedef enum pgpVSFlags_e { + RPMVSF_DEFAULT = 0, + RPMVSF_NOHDRCHK = (1 << 0), + RPMVSF_NEEDPAYLOAD = (1 << 1), + /* bit(s) 2-7 unused */ + RPMVSF_NOSHA1HEADER = (1 << 8), + RPMVSF_NOMD5HEADER = (1 << 9), /* unimplemented */ + RPMVSF_NODSAHEADER = (1 << 10), + RPMVSF_NORSAHEADER = (1 << 11), + /* bit(s) 12-15 unused */ + RPMVSF_NOSHA1 = (1 << 16), /* unimplemented */ + RPMVSF_NOMD5 = (1 << 17), + RPMVSF_NODSA = (1 << 18), + RPMVSF_NORSA = (1 << 19) + /* bit(s) 20-31 unused */ +} pgpVSFlags; + +#define _RPMVSF_NODIGESTS \ + ( RPMVSF_NOSHA1HEADER | \ + RPMVSF_NOMD5HEADER | \ + RPMVSF_NOSHA1 | \ + RPMVSF_NOMD5 ) + +#define _RPMVSF_NOSIGNATURES \ + ( RPMVSF_NODSAHEADER | \ + RPMVSF_NORSAHEADER | \ + RPMVSF_NODSA | \ + RPMVSF_NORSA ) + +#define _RPMVSF_NOHEADER \ + ( RPMVSF_NOSHA1HEADER | \ + RPMVSF_NOMD5HEADER | \ + RPMVSF_NODSAHEADER | \ + RPMVSF_NORSAHEADER ) + +#define _RPMVSF_NOPAYLOAD \ + ( RPMVSF_NOSHA1 | \ + RPMVSF_NOMD5 | \ + RPMVSF_NODSA | \ + RPMVSF_NORSA ) + +/*@-redef@*/ /* LCL: ??? */ +typedef /*@abstract@*/ const void * fnpyKey; +/*@=redef@*/ + +/** + * Bit(s) to identify progress callbacks. + */ +typedef enum rpmCallbackType_e { + RPMCALLBACK_UNKNOWN = 0, + RPMCALLBACK_INST_PROGRESS = (1 << 0), + RPMCALLBACK_INST_START = (1 << 1), + RPMCALLBACK_INST_OPEN_FILE = (1 << 2), + RPMCALLBACK_INST_CLOSE_FILE = (1 << 3), + RPMCALLBACK_TRANS_PROGRESS = (1 << 4), + RPMCALLBACK_TRANS_START = (1 << 5), + RPMCALLBACK_TRANS_STOP = (1 << 6), + RPMCALLBACK_UNINST_PROGRESS = (1 << 7), + RPMCALLBACK_UNINST_START = (1 << 8), + RPMCALLBACK_UNINST_STOP = (1 << 9), + RPMCALLBACK_REPACKAGE_PROGRESS = (1 << 10), + RPMCALLBACK_REPACKAGE_START = (1 << 11), + RPMCALLBACK_REPACKAGE_STOP = (1 << 12), + RPMCALLBACK_UNPACK_ERROR = (1 << 13), + RPMCALLBACK_CPIO_ERROR = (1 << 14), + RPMCALLBACK_SCRIPT_ERROR = (1 << 15) +} rpmCallbackType; + +/** + */ +typedef void * rpmCallbackData; + +/** \ingroup rpmpgp + * 9.4. Hash Algorithms + * +\verbatim + ID Algorithm Text Name + -- --------- ---- ---- + 1 - MD5 "MD5" + 2 - SHA-1 "SHA1" + 3 - RIPE-MD/160 "RIPEMD160" + 4 - Reserved for double-width SHA (experimental) + 5 - MD2 "MD2" + 6 - Reserved for TIGER/192 "TIGER192" + 7 - Reserved for HAVAL (5 pass, 160-bit) "HAVAL-5-160" + 100 to 110 - Private/Experimental algorithm. +\endverbatim + * + * Implementations MUST implement SHA-1. Implementations SHOULD + * implement MD5. + * @todo Add SHA256. + */ +typedef enum pgpHashAlgo_e { + PGPHASHALGO_ERROR = -1, + PGPHASHALGO_NONE = 0, + PGPHASHALGO_MD5 = 1, /*!< MD5 */ + PGPHASHALGO_SHA1 = 2, /*!< SHA-1 */ + PGPHASHALGO_RIPEMD160 = 3, /*!< RIPEMD-160 */ + PGPHASHALGO_MD2 = 5, /*!< MD2 */ + PGPHASHALGO_TIGER192 = 6, /*!< TIGER-192 */ + PGPHASHALGO_HAVAL_5_160 = 7, /*!< HAVAL-5-160 */ + PGPHASHALGO_SHA256 = 8, /*!< SHA-256 */ + PGPHASHALGO_SHA384 = 9, /*!< SHA-384 */ + PGPHASHALGO_SHA512 = 10, /*!< SHA-512 */ + PGPHASHALGO_SHA224 = 11, /*!< SHA-224 */ + + PGPHASHALGO_MD4 = 104, /*!< (private) MD4 */ + PGPHASHALGO_RIPEMD128 = 105, /*!< (private) RIPEMD-128 */ + PGPHASHALGO_CRC32 = 106, /*!< (private) CRC-32 */ + PGPHASHALGO_ADLER32 = 107, /*!< (private) ADLER-32 */ + PGPHASHALGO_CRC64 = 108, /*!< (private) CRC-64 */ + PGPHASHALGO_JLU32 = 109, /*!< (private) Jenkins lookup3.c */ + + PGPHASHALGO_RIPEMD256 = 111, /*!< (private) RIPEMD-256 */ + PGPHASHALGO_RIPEMD320 = 112, /*!< (private) RIPEMD-320 */ + PGPHASHALGO_SALSA10 = 113, /*!< (private) SALSA-10 */ + PGPHASHALGO_SALSA20 = 114, /*!< (private) SALSA-20 */ + + PGPHASHALGO_MD6_224 = 128+0,/*!< (private) MD6-224 */ + PGPHASHALGO_MD6_256 = 128+1,/*!< (private) MD6-256 */ + PGPHASHALGO_MD6_384 = 128+2,/*!< (private) MD6-384 */ + PGPHASHALGO_MD6_512 = 128+3,/*!< (private) MD6-512 */ + + PGPHASHALGO_CUBEHASH_224 = 136+0,/*!< (private) CUBEHASH-224 */ + PGPHASHALGO_CUBEHASH_256 = 136+1,/*!< (private) CUBEHASH-256 */ + PGPHASHALGO_CUBEHASH_384 = 136+2,/*!< (private) CUBEHASH-384 */ + PGPHASHALGO_CUBEHASH_512 = 136+3,/*!< (private) CUBEHASH-512 */ + + PGPHASHALGO_KECCAK_224 = 144+0,/*!< (private) KECCAK-224 */ + PGPHASHALGO_KECCAK_256 = 144+1,/*!< (private) KECCAK-256 */ + PGPHASHALGO_KECCAK_384 = 144+2,/*!< (private) KECCAK-384 */ + PGPHASHALGO_KECCAK_512 = 144+3,/*!< (private) KECCAK-384 */ + + PGPHASHALGO_ECHO_224 = 148+0,/*!< (private) ECHO-224 */ + PGPHASHALGO_ECHO_256 = 148+1,/*!< (private) ECHO-256 */ + PGPHASHALGO_ECHO_384 = 148+2,/*!< (private) ECHO-384 */ + PGPHASHALGO_ECHO_512 = 148+3,/*!< (private) ECHO-384 */ + + PGPHASHALGO_EDONR_224 = 152+0,/*!< (private) EDON-R-224 */ + PGPHASHALGO_EDONR_256 = 152+1,/*!< (private) EDON-R-256 */ + PGPHASHALGO_EDONR_384 = 152+2,/*!< (private) EDON-R-384 */ + PGPHASHALGO_EDONR_512 = 152+3,/*!< (private) EDON-R-512 */ + + PGPHASHALGO_FUGUE_224 = 156+0,/*!< (private) FUGUE-224 */ + PGPHASHALGO_FUGUE_256 = 156+1,/*!< (private) FUGUE-256 */ + PGPHASHALGO_FUGUE_384 = 156+2,/*!< (private) FUGUE-384 */ + PGPHASHALGO_FUGUE_512 = 156+3,/*!< (private) FUGUE-512 */ + + PGPHASHALGO_SKEIN_224 = 160+0,/*!< (private) SKEIN-224 */ + PGPHASHALGO_SKEIN_256 = 160+1,/*!< (private) SKEIN-256 */ + PGPHASHALGO_SKEIN_384 = 160+2,/*!< (private) SKEIN-384 */ + PGPHASHALGO_SKEIN_512 = 160+3,/*!< (private) SKEIN-512 */ + PGPHASHALGO_SKEIN_1024 = 160+4,/*!< (private) SKEIN-1024 */ + + PGPHASHALGO_BMW_224 = 168+0,/*!< (private) BMW-224 */ + PGPHASHALGO_BMW_256 = 168+1,/*!< (private) BMW-256 */ + PGPHASHALGO_BMW_384 = 168+2,/*!< (private) BMW-384 */ + PGPHASHALGO_BMW_512 = 168+3,/*!< (private) BMW-512 */ + + PGPHASHALGO_SHABAL_224 = 176+0,/*!< (private) SHABAL-224 */ + PGPHASHALGO_SHABAL_256 = 176+1,/*!< (private) SHABAL-256 */ + PGPHASHALGO_SHABAL_384 = 176+2,/*!< (private) SHABAL-384 */ + PGPHASHALGO_SHABAL_512 = 176+3,/*!< (private) SHABAL-512 */ + + PGPHASHALGO_SHAVITE3_224 = 180+0,/*!< (private) SHAVITE3-224 */ + PGPHASHALGO_SHAVITE3_256 = 180+1,/*!< (private) SHAVITE3-256 */ + PGPHASHALGO_SHAVITE3_384 = 180+2,/*!< (private) SHAVITE3-384 */ + PGPHASHALGO_SHAVITE3_512 = 180+3,/*!< (private) SHAVITE3-512 */ + + PGPHASHALGO_BLAKE_224 = 184+0,/*!< (private) BLAKE-224 */ + PGPHASHALGO_BLAKE_256 = 184+1,/*!< (private) BLAKE-256 */ + PGPHASHALGO_BLAKE_384 = 184+2,/*!< (private) BLAKE-384 */ + PGPHASHALGO_BLAKE_512 = 184+3,/*!< (private) BLAKE-512 */ + + PGPHASHALGO_TIB3_224 = 192+0,/*!< (private) TIB3-224 */ + PGPHASHALGO_TIB3_256 = 192+1,/*!< (private) TIB3-256 */ + PGPHASHALGO_TIB3_384 = 192+2,/*!< (private) TIB3-384 */ + PGPHASHALGO_TIB3_512 = 192+3,/*!< (private) TIB3-512 */ + + PGPHASHALGO_SIMD_224 = 200+0,/*!< (private) SIMD-224 */ + PGPHASHALGO_SIMD_256 = 200+1,/*!< (private) SIMD-256 */ + PGPHASHALGO_SIMD_384 = 200+2,/*!< (private) SIMD-384 */ + PGPHASHALGO_SIMD_512 = 200+3,/*!< (private) SIMD-512 */ + + PGPHASHALGO_ARIRANG_224 = 208+0,/*!< (private) ARIRANG-224 */ + PGPHASHALGO_ARIRANG_256 = 208+1,/*!< (private) ARIRANG-256 */ + PGPHASHALGO_ARIRANG_384 = 208+2,/*!< (private) ARIRANG-384 */ + PGPHASHALGO_ARIRANG_512 = 208+3,/*!< (private) ARIRANG-512 */ + + PGPHASHALGO_LANE_224 = 212+0,/*!< (private) LANE-224 */ + PGPHASHALGO_LANE_256 = 212+1,/*!< (private) LANE-256 */ + PGPHASHALGO_LANE_384 = 212+2,/*!< (private) LANE-384 */ + PGPHASHALGO_LANE_512 = 212+3,/*!< (private) LANE-512 */ + + PGPHASHALGO_LUFFA_224 = 216+0,/*!< (private) LUFFA-224 */ + PGPHASHALGO_LUFFA_256 = 216+1,/*!< (private) LUFFA-256 */ + PGPHASHALGO_LUFFA_384 = 216+2,/*!< (private) LUFFA-384 */ + PGPHASHALGO_LUFFA_512 = 216+3,/*!< (private) LUFFA-512 */ + + PGPHASHALGO_CHI_224 = 224+0,/*!< (private) CHI-224 */ + PGPHASHALGO_CHI_256 = 224+1,/*!< (private) CHI-256 */ + PGPHASHALGO_CHI_384 = 224+2,/*!< (private) CHI-384 */ + PGPHASHALGO_CHI_512 = 224+3,/*!< (private) CHI-512 */ + + PGPHASHALGO_JH_224 = 232+0,/*!< (private) JH-224 */ + PGPHASHALGO_JH_256 = 232+1,/*!< (private) JH-256 */ + PGPHASHALGO_JH_384 = 232+2,/*!< (private) JH-384 */ + PGPHASHALGO_JH_512 = 232+3,/*!< (private) JH-512 */ + + PGPHASHALGO_GROESTL_224 = 240+0,/*!< (private) GROESTL-224 */ + PGPHASHALGO_GROESTL_256 = 240+1,/*!< (private) GROESTL-256 */ + PGPHASHALGO_GROESTL_384 = 240+2,/*!< (private) GROESTL-384 */ + PGPHASHALGO_GROESTL_512 = 240+3,/*!< (private) GROESTL-512 */ + + PGPHASHALGO_HAMSI_224 = 248+0,/*!< (private) HAMSI-224 */ + PGPHASHALGO_HAMSI_256 = 248+1,/*!< (private) HAMSI-256 */ + PGPHASHALGO_HAMSI_384 = 248+2,/*!< (private) HAMSI-384 */ + PGPHASHALGO_HAMSI_512 = 248+3,/*!< (private) HAMSI-512 */ + +} pgpHashAlgo; + +/** \ingroup rpmpgp + * Bit(s) to control digest operation. + */ +typedef enum rpmDigestFlags_e { + RPMDIGEST_NONE = 0, +} rpmDigestFlags; + +#if defined(_RPMIOB_INTERNAL) +/** \ingroup rpmio + */ +struct rpmiob_s{ + struct rpmioItem_s _item; /*!< usage mutex and pool identifier. */ + rpmuint8_t * b; /*!< data octects. */ + size_t blen; /*!< no. of octets used. */ + size_t allocated; /*!< no. of octets allocated. */ +#if defined(__LCLINT__) +/*@refs@*/ + int nrefs; /*!< (unused) keep splint happy */ +#endif +}; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** \ingroup rpmpgp + * Return digest algorithm identifier. + * @param ctx digest context + * @return digest hash algorithm identifier + */ +pgpHashAlgo rpmDigestAlgo(DIGEST_CTX ctx) + /*@*/; + +/** \ingroup rpmpgp + * Return digest flags. + * @param ctx digest context + * @return digest flags + */ +rpmDigestFlags rpmDigestF(DIGEST_CTX ctx) + /*@*/; + +/** \ingroup rpmpgp + * Return digest name. + * @param ctx digest context + * @return digest name + */ +/*@observer@*/ +const char * rpmDigestName(DIGEST_CTX ctx) + /*@*/; + +/** \ingroup rpmpgp + * Return digest ASN1 oid string. + * Values from PKCS#1 v2.1 (aka RFC-3447). + * @param ctx digest context + * @return digest ASN1 oid string + */ +/*@observer@*/ /*@null@*/ +const char * rpmDigestASN1(DIGEST_CTX ctx) + /*@*/; + +/** \ingroup rpmpgp + * Duplicate a digest context. + * @param octx existing digest context + * @return duplicated digest context + */ +/*@only@*/ +DIGEST_CTX rpmDigestDup(DIGEST_CTX octx) + /*@*/; + +/** \ingroup rpmpgp + * Initialize digest. + * Set bit count to 0 and buffer to mysterious initialization constants. + * @param hashalgo type of digest + * @param flags bit(s) to control digest operation + * @return digest context + */ +/*@only@*/ /*@null@*/ +DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags) + /*@*/; + +/** \ingroup rpmpgp + * Update context with next plain text buffer. + * @param ctx digest context + * @param data next data buffer + * @param len no. bytes of data + * @return 0 on success + */ +int rpmDigestUpdate(/*@null@*/ DIGEST_CTX ctx, const void * data, size_t len) + /*@modifies ctx @*/; + +/** \ingroup rpmpgp + * Return digest and destroy context. + * + * @param ctx digest context + * @retval *datap digest + * @retval *lenp no. bytes of digest + * @param asAscii return digest as ascii string? + * @return 0 on success + */ +int rpmDigestFinal(/*@only@*/ /*@null@*/ DIGEST_CTX ctx, + /*@null@*/ /*@out@*/ void * datap, + /*@null@*/ /*@out@*/ size_t * lenp, int asAscii) + /*@modifies *datap, *lenp @*/; + +/** \ingroup rpmpgp + * + * Compute key material and add to digest context. + * @param ctx digest context + * @param key HMAC key (NULL does digest instead) + * @param keylen HMAC key length(bytes) (0 uses strlen(key)) + * @return 0 on success + */ +int rpmHmacInit(DIGEST_CTX ctx, const void * key, size_t keylen) + /*@*/; + +/** \ingroup rpmio + */ +typedef void * (*rpmCallbackFunction) + (/*@null@*/ const void * h, + const rpmCallbackType what, + const rpmuint64_t amount, + const rpmuint64_t total, + /*@null@*/ fnpyKey key, + /*@null@*/ rpmCallbackData data) + /*@globals internalState@*/ + /*@modifies internalState@*/; + +#if !defined(SWIG) +/** \ingroup rpmio + * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. + * @param p memory to free + * @return NULL always + */ +#if defined(WITH_DMALLOC) +#define _free(p) ((p) != NULL ? free((void *)(p)) : (void)0, NULL) +#else +/*@unused@*/ static inline /*@null@*/ +void * _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) + /*@modifies p @*/ +{ + if (p != NULL) free((void *)p); + return NULL; +} +#endif +#endif + +/*@unused@*/ static inline int xislower(int c) /*@*/ { + return (c >= (int)'a' && c <= (int)'z'); +} +/*@unused@*/ static inline int xisupper(int c) /*@*/ { + return (c >= (int)'A' && c <= (int)'Z'); +} +/*@unused@*/ static inline int xisalpha(int c) /*@*/ { + return (xislower(c) || xisupper(c)); +} +/*@unused@*/ static inline int xisdigit(int c) /*@*/ { + return (c >= (int)'0' && c <= (int)'9'); +} +/*@unused@*/ static inline int xisalnum(int c) /*@*/ { + return (xisalpha(c) || xisdigit(c)); +} +/*@unused@*/ static inline int xisblank(int c) /*@*/ { + return (c == (int)' ' || c == (int)'\t'); +} +/*@unused@*/ static inline int xisspace(int c) /*@*/ { + return (xisblank(c) || c == (int)'\n' || c == (int)'\r' || c == (int)'\f' || c == (int)'\v'); +} +/*@unused@*/ static inline int xiscntrl(int c) /*@*/ { + return (c < (int)' '); +} +/*@unused@*/ static inline int xisascii(int c) /*@*/ { + return ((c & 0x80) != 0x80); +} +/*@unused@*/ static inline int xisprint(int c) /*@*/ { + return (c >= (int)' ' && xisascii(c)); +} +/*@unused@*/ static inline int xisgraph(int c) /*@*/ { + return (c > (int)' ' && xisascii(c)); +} +/*@unused@*/ static inline int xispunct(int c) /*@*/ { + return (xisgraph(c) && !xisalnum(c)); +} + +/*@unused@*/ static inline int xtolower(int c) /*@*/ { + return ((xisupper(c)) ? (c | ('a' - 'A')) : c); +} +/*@unused@*/ static inline int xtoupper(int c) /*@*/ { + return ((xislower(c)) ? (c & ~('a' - 'A')) : c); +} + +/** \ingroup rpmio + * Locale insensitive strcasecmp(3). + */ +int xstrcasecmp(const char * s1, const char * s2) /*@*/; + +/** \ingroup rpmio + * Locale insensitive strncasecmp(3). + */ +int xstrncasecmp(const char *s1, const char * s2, size_t n) /*@*/; + +/** \ingroup rpmio + * Force encoding of string. + */ +/*@only@*/ /*@null@*/ +const char * xstrtolocale(/*@only@*/ const char *str) + /*@modifies *str @*/; + +/** + * Unreference a I/O buffer instance. + * @param iob hash table + * @return NULL if free'd + */ +/*@unused@*/ /*@null@*/ +rpmiob rpmiobUnlink (/*@killref@*/ /*@null@*/ rpmiob iob) + /*@globals fileSystem @*/ + /*@modifies iob, fileSystem @*/; +#define rpmiobUnlink(_iob) \ + ((rpmiob)rpmioUnlinkPoolItem((rpmioItem)(_iob), __FUNCTION__, __FILE__, __LINE__)) + +/** + * Reference a I/O buffer instance. + * @param iob I/O buffer + * @return new I/O buffer reference + */ +/*@unused@*/ /*@newref@*/ /*@null@*/ +rpmiob rpmiobLink (/*@null@*/ rpmiob iob) + /*@globals fileSystem @*/ + /*@modifies iob, fileSystem @*/; +#define rpmiobLink(_iob) \ + ((rpmiob)rpmioLinkPoolItem((rpmioItem)(_iob), __FUNCTION__, __FILE__, __LINE__)) + +/** + * Destroy a I/O buffer instance. + * @param iob I/O buffer + * @return NULL on last dereference + */ +/*@null@*/ +rpmiob rpmiobFree( /*@killref@*/ rpmiob iob) + /*@globals fileSystem @*/ + /*@modifies iob, fileSystem @*/; +#define rpmiobFree(_iob) \ + ((rpmiob)rpmioFreePoolItem((rpmioItem)(_iob), __FUNCTION__, __FILE__, __LINE__)) + +/** + * Create an I/O buffer. + * @param len no. of octets to allocate + * @return new I/O buffer + */ +/*@newref@*/ /*@null@*/ +rpmiob rpmiobNew(size_t len) + /*@globals fileSystem @*/ + /*@modifies fileSystem @*/; + +/** + * Empty an I/O buffer. + * @param iob I/O buffer + * @return I/O buffer + */ +rpmiob rpmiobEmpty(/*@returned@*/ rpmiob iob) + /*@modifies iob @*/; + +/** + * Trim trailing white space. + * @param iob I/O buffer + * @return I/O buffer + */ +rpmiob rpmiobRTrim(/*@returned@*/ rpmiob iob) + /*@modifies iob @*/; + +/** + * Append string to I/O buffer. + * @param iob I/O buffer + * @param s string + * @param nl append NL? + * @return I/O buffer + */ +rpmiob rpmiobAppend(/*@returned@*/ rpmiob iob, const char * s, size_t nl) + /*@modifies iob @*/; + +/** + * Return I/O buffer. + * @param iob I/O buffer + * @return I/O buffer (as octets) + */ +rpmuint8_t * rpmiobBuf(rpmiob iob) + /*@*/; + +/** + * Return I/O buffer (as string). + * @param iob I/O buffer + * @return I/O buffer (as string) + */ +char * rpmiobStr(rpmiob iob) + /*@*/; + +/** + * Return I/O buffer len. + * @param iob I/O buffer + * @return I/O buffer length + */ +size_t rpmiobLen(rpmiob iob) + /*@*/; + +#if defined(_RPMIOB_INTERNAL) +/** + * Read an entire file into a buffer. + * @param fn file name to read + * @retval *iobp I/O buffer + * @return 0 on success + */ +int rpmiobSlurp(const char * fn, rpmiob * iobp) + /*@globals h_errno, fileSystem, internalState @*/ + /*@modifies *iobp, fileSystem, internalState @*/; +#endif + +/** + * Destroy a rpmioP object. + * @param P parser state + * @return NULL + */ +/*@null@*/ +rpmioP rpmioPFree(/*@only@*/ /*@null@*/ rpmioP P) + /*@modifies P @*/; + +/** + * Parse next command out of a string incrementally. + * @param *Pptr parser state + * @param str string to parse + * @return RPMRC_OK on success + */ +rpmRC rpmioParse(rpmioP *Pptr, const char * str) + /*@modifies *Pptr @*/; + +#ifdef __cplusplus +} +#endif + +#endif /* _H_RPMIOTYPES_ */ diff --git a/scripts/rpmsw.h b/scripts/rpmsw.h new file mode 100644 index 000000000..9023d0b96 --- /dev/null +++ b/scripts/rpmsw.h @@ -0,0 +1,157 @@ +#ifndef H_RPMSW +#define H_RPMSW + +/** \ingroup rpmio + * \file rpmio/rpmsw.h + */ + +/** \ingroup rpmio + */ +typedef unsigned long int rpmtime_t; + +/** \ingroup rpmio + */ +typedef struct rpmsw_s * rpmsw; + +/** \ingroup rpmio + */ +typedef struct rpmop_s * rpmop; + +/** \ingroup rpmio + */ +struct rpmsw_s { + union { + struct timeval tv; + unsigned long long int ticks; + unsigned long int tocks[2]; + } u; +}; + +/** \ingroup rpmio + * Cumulative statistics for an operation. + */ +struct rpmop_s { + struct rpmsw_s begin; /*!< Starting time stamp. */ + int count; /*!< Number of operations. */ + unsigned long long bytes; /*!< Number of bytes transferred. */ + rpmtime_t usecs; /*!< Number of ticks. */ +}; + +/*@unchecked@*/ +extern int _rpmsw_stats; + +/** \ingroup rpmio + * Indices for timestamps. + */ +typedef enum rpmswOpX_e { + RPMSW_OP_TOTAL = 0, + RPMSW_OP_CHECK = 1, + RPMSW_OP_ORDER = 2, + RPMSW_OP_FINGERPRINT = 3, + RPMSW_OP_REPACKAGE = 4, + RPMSW_OP_INSTALL = 5, + RPMSW_OP_ERASE = 6, + RPMSW_OP_SCRIPTLETS = 7, + RPMSW_OP_COMPRESS = 8, + RPMSW_OP_UNCOMPRESS = 9, + RPMSW_OP_DIGEST = 10, + RPMSW_OP_SIGNATURE = 11, + RPMSW_OP_DBADD = 12, + RPMSW_OP_DBREMOVE = 13, + RPMSW_OP_DBGET = 14, + RPMSW_OP_DBPUT = 15, + RPMSW_OP_DBDEL = 16, + RPMSW_OP_READHDR = 17, + RPMSW_OP_HDRLOAD = 18, + RPMSW_OP_HDRGET = 19, + RPMSW_OP_DEBUG = 20, + RPMSW_OP_MAX = 20 +} rpmswOpX; + +#ifdef __cplusplus +extern "C" { +#endif + +/** Return benchmark time stamp. + * @param *sw time stamp + * @return 0 on success + */ +/*@-exportlocal@*/ +/*@null@*/ +rpmsw rpmswNow(/*@returned@*/ rpmsw sw) + /*@globals internalState @*/ + /*@modifies sw, internalState @*/; +/*@=exportlocal@*/ + +/** Return benchmark time stamp difference. + * @param *end end time stamp + * @param *begin begin time stamp + * @return difference in micro-seconds + */ +/*@-exportlocal@*/ +rpmtime_t rpmswDiff(/*@null@*/ rpmsw end, /*@null@*/ rpmsw begin) + /*@*/; +/*@=exportlocal@*/ + +/** Return benchmark time stamp overhead. + * @return overhead in micro-seconds + */ +/*@-exportlocal@*/ +rpmtime_t rpmswInit(void) + /*@globals internalState @*/ + /*@modifies internalState @*/; +/*@=exportlocal@*/ + +/** \ingroup rpmio + * Enter timed operation. + * @param op operation statistics + * @param rc -1 clears usec counter + * @return 0 always + */ +int rpmswEnter(/*@null@*/ rpmop op, ssize_t rc) + /*@globals internalState @*/ + /*@modifies *op, internalState @*/; + +/** \ingroup rpmio + * Exit timed operation. + * @param op operation statistics + * @param rc per-operation data (e.g. bytes transferred) + * @return cumulative usecs for operation + */ +rpmtime_t rpmswExit(/*@null@*/ rpmop op, ssize_t rc) + /*@globals internalState @*/ + /*@modifies op, internalState @*/; + +/** \ingroup rpmio + * Sum statistic counters. + * @param to result statistics + * @param from operation statistics + * @return cumulative usecs for operation + */ +rpmtime_t rpmswAdd(/*@null@*/ rpmop to, /*@null@*/ rpmop from) + /*@modifies to @*/; + +/** \ingroup rpmio + * Subtract statistic counters. + * @param to result statistics + * @param from operation statistics + * @return cumulative usecs for operation + */ +rpmtime_t rpmswSub(rpmop to, rpmop from) + /*@modifies to @*/; + +/** \ingroup rpmio + * Print operation statistics. + * @param name operation name + * @param op operation statistics + * @param fp file handle (NULL uses stderr) + */ +void rpmswPrint(const char * name, /*@null@*/ rpmop op, /*@null@*/ FILE * fp) + /*@globals fileSystem @*/ + /*@modifies fp, fileSystem @*/; + +#ifdef __cplusplus +} +#endif + +#endif /* H_RPMSW */ diff --git a/scripts/rpmtag.h b/scripts/rpmtag.h new file mode 100644 index 000000000..f0f71aa8a --- /dev/null +++ b/scripts/rpmtag.h @@ -0,0 +1,1243 @@ +#ifndef H_RPMTAG +#define H_RPMTAG + +/** \ingroup header + * \file rpmdb/rpmtag.h + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \ingroup header + */ +typedef const char * errmsg_t; + +/** \ingroup header + */ +typedef /*@abstract@*/ /*@refcounted@*/ struct headerToken_s * Header; + +/** \ingroup header + * The basic types of data in tags from headers. + */ +enum rpmTagType_e { + /* RPM_NULL_TYPE = 0 - never been used. */ + /* RPM_CHAR_TYPE = 1 - never been used, same as RPM_UINT8_TYPE. */ + RPM_UINT8_TYPE = 2, + RPM_UINT16_TYPE = 3, + RPM_UINT32_TYPE = 4, + RPM_UINT64_TYPE = 5, + RPM_STRING_TYPE = 6, + RPM_BIN_TYPE = 7, + RPM_STRING_ARRAY_TYPE = 8, + RPM_I18NSTRING_TYPE = 9 + /* RPM_ASN1_TYPE = 10 - never been used. */ + /* RPM_OPENPGP_TYPE= 11 - never been used. */ +}; +#define RPM_MIN_TYPE 2 +#define RPM_MAX_TYPE 9 +#define RPM_MASK_TYPE 0x0000ffff + +/** \ingroup header + */ +typedef enum rpmTagType_e rpmTagType; /*!< tag data type. */ + +/** \ingroup header + */ +typedef union rpmDataType_u rpmTagData; /*!< tag data. */ + +/** \ingroup header + */ +typedef rpmuint32_t rpmTagCount; /*!< tag data element count. */ + +/** \ingroup header + */ +typedef struct _HE_s * HE_t; /*!< tag container. */ + +/** \ingroup header + */ +/*@-typeuse -fielduse@*/ +#if !defined(SWIG) +union rpmDataType_u { +/*@null@*/ + void * ptr; + rpmuint8_t * ui8p; /*!< RPM_UINT8_TYPE | RPM_CHAR_TYPE */ + rpmuint16_t * ui16p; /*!< RPM_UINT16_TYPE */ + rpmuint32_t * ui32p; /*!< RPM_UINT32_TYPE */ + rpmuint64_t * ui64p; /*!< RPM_UINT64_TYPE */ +/*@relnull@*/ + const char * str; /*!< RPM_STRING_TYPE */ + unsigned char * blob; /*!< RPM_BIN_TYPE */ + const char ** argv; /*!< RPM_STRING_ARRAY_TYPE */ + HE_t he; +}; +#endif +/*@=typeuse =fielduse@*/ + +/*@=typeuse =fielduse@*/ +/** \ingroup header + */ +/*@-enummemuse -typeuse @*/ +typedef enum rpmSubTagType_e { + RPM_REGION_TYPE = -10, + RPM_BIN_ARRAY_TYPE = -11, + RPM_XREF_TYPE = -12 +} rpmSubTagType; +/*@=enummemuse =typeuse @*/ + +/** \ingroup header + * Identify how to return the header data type. + */ +/*@-enummemuse -typeuse @*/ +typedef enum rpmTagReturnType_e { + RPM_ANY_RETURN_TYPE = 0, + RPM_SCALAR_RETURN_TYPE = 0x00010000, + RPM_ARRAY_RETURN_TYPE = 0x00020000, + RPM_MAPPING_RETURN_TYPE = 0x00040000, + /* 0x00080000 */ + RPM_PROBE_RETURN_TYPE = 0x00100000, + RPM_TREE_RETURN_TYPE = 0x00200000, + RPM_OPENPGP_RETURN_TYPE = 0x00400000, + RPM_X509_RETURN_TYPE = 0x00800000, + RPM_ASN1_RETURN_TYPE = 0x01000000, + RPM_OPAQUE_RETURN_TYPE = 0x10000000, + RPM_MASK_RETURN_TYPE = 0xffff0000 +} rpmTagReturnType; +/*@=enummemuse =typeuse @*/ + +/** + * Header private tags. + * @note General use tags should start at 1000 (RPM's tag space starts there). + */ +#define HEADER_IMAGE 61 +#define HEADER_SIGNATURES 62 +#define HEADER_IMMUTABLE 63 +#define HEADER_REGIONS 64 +#define HEADER_I18NTABLE 100 +#define HEADER_SIGBASE 256 +#define HEADER_TAGBASE 1000 + +/** \ingroup header + */ +typedef /*@abstract@*/ struct headerIterator_s * HeaderIterator; + +/** \ingroup header + */ +typedef /*@abstract@*/ struct headerTagIndices_s * headerTagIndices; + +/** \ingroup header + */ +typedef /*@abstract@*/ const struct headerSprintfExtension_s * headerSprintfExtension; + +/** + * Pseudo-tags used by the rpmdb and rpmgi iterator API's. + */ +#define RPMDBI_PACKAGES 0 /* Installed package headers. */ +#define RPMDBI_DEPENDS 1 /* Dependency resolution cache. */ + /* (obsolete) RPMDBI_LABEL was 2 */ +#define RPMDBI_ADDED 3 /* Added package headers. */ +#define RPMDBI_REMOVED 4 /* Removed package headers. */ +#define RPMDBI_AVAILABLE 5 /* Available package headers. */ +#define RPMDBI_HDLIST 6 /* (rpmgi) Header list. */ +#define RPMDBI_ARGLIST 7 /* (rpmgi) Argument list. */ +#define RPMDBI_FTSWALK 8 /* (rpmgi) File tree walk. */ +#define RPMDBI_SEQNO 9 /* Sequence numbers. */ +#define RPMDBI_BTREE 10 /* (development) Generic DB_BTREE. */ +#define RPMDBI_HASH 11 /* (development) Generic DB_HASH. */ +#define RPMDBI_QUEUE 12 /* (development) Generic DB_QUEUE. */ +#define RPMDBI_RECNO 13 /* (development) Generic DB_RECNO. */ +#define RPMDBI_REPACKAGES 14 /* Re-packaged package paths. */ +#define RPMDBI_REPOSITORY 15 /* Repository URI's. */ + +/** \ingroup header + * Tags identify data in package headers. + * @note tags should not have value 0! + */ +enum rpmTag_e { + + RPMTAG_HEADERIMAGE = HEADER_IMAGE, /*!< internal Current image. */ + RPMTAG_HEADERSIGNATURES = HEADER_SIGNATURES, /*!< internal Signatures. */ + RPMTAG_HEADERIMMUTABLE = HEADER_IMMUTABLE, /*!< x Original image. */ +/*@-enummemuse@*/ + RPMTAG_HEADERREGIONS = HEADER_REGIONS, /*!< internal Regions. */ + + RPMTAG_HEADERI18NTABLE = HEADER_I18NTABLE, /*!< s[] I18N string locales. */ +/*@=enummemuse@*/ + +/* Retrofit (and uniqify) signature tags for use by tagName() and rpmQuery. */ +/* the md5 sum was broken *twice* on big endian machines */ +/* XXX 2nd underscore prevents tagTable generation */ + RPMTAG_SIG_BASE = HEADER_SIGBASE, + RPMTAG_SIGSIZE = RPMTAG_SIG_BASE+1, /* i */ + RPMTAG_SIGLEMD5_1 = RPMTAG_SIG_BASE+2, /* internal - obsolete */ + RPMTAG_SIGPGP = RPMTAG_SIG_BASE+3, /* x */ + RPMTAG_SIGLEMD5_2 = RPMTAG_SIG_BASE+4, /* x internal - obsolete */ + RPMTAG_SIGMD5 = RPMTAG_SIG_BASE+5, /* x */ +#define RPMTAG_PKGID RPMTAG_SIGMD5 /* x */ + RPMTAG_SIGGPG = RPMTAG_SIG_BASE+6, /* x */ + RPMTAG_SIGPGP5 = RPMTAG_SIG_BASE+7, /* internal - obsolete */ + + RPMTAG_BADSHA1_1 = RPMTAG_SIG_BASE+8, /* internal - obsolete */ + RPMTAG_BADSHA1_2 = RPMTAG_SIG_BASE+9, /* internal - obsolete */ + RPMTAG_PUBKEYS = RPMTAG_SIG_BASE+10, /* s[] */ + RPMTAG_DSAHEADER = RPMTAG_SIG_BASE+11, /* x */ + RPMTAG_RSAHEADER = RPMTAG_SIG_BASE+12, /* x */ + RPMTAG_SHA1HEADER = RPMTAG_SIG_BASE+13, /* s */ +#define RPMTAG_HDRID RPMTAG_SHA1HEADER /* s */ + + RPMTAG_NAME = 1000, /* s */ +#define RPMTAG_N RPMTAG_NAME /* s */ + RPMTAG_VERSION = 1001, /* s */ +#define RPMTAG_V RPMTAG_VERSION /* s */ + RPMTAG_RELEASE = 1002, /* s */ +#define RPMTAG_R RPMTAG_RELEASE /* s */ + RPMTAG_EPOCH = 1003, /* i */ +#define RPMTAG_E RPMTAG_EPOCH /* i */ + RPMTAG_SUMMARY = 1004, /* s{} */ + RPMTAG_DESCRIPTION = 1005, /* s{} */ + RPMTAG_BUILDTIME = 1006, /* i */ + RPMTAG_BUILDHOST = 1007, /* s */ + RPMTAG_INSTALLTIME = 1008, /* i[] */ + RPMTAG_SIZE = 1009, /* i */ + RPMTAG_DISTRIBUTION = 1010, /* s */ + RPMTAG_VENDOR = 1011, /* s */ + RPMTAG_GIF = 1012, /* x */ + RPMTAG_XPM = 1013, /* x */ + RPMTAG_LICENSE = 1014, /* s */ + RPMTAG_PACKAGER = 1015, /* s */ + RPMTAG_GROUP = 1016, /* s{} */ +/*@-enummemuse@*/ + RPMTAG_CHANGELOG = 1017, /* s[] internal */ +/*@=enummemuse@*/ + RPMTAG_SOURCE = 1018, /* s[] */ + RPMTAG_PATCH = 1019, /* s[] */ + RPMTAG_URL = 1020, /* s */ + RPMTAG_OS = 1021, /* s legacy used int */ + RPMTAG_ARCH = 1022, /* s legacy used int */ + RPMTAG_PREIN = 1023, /* s */ + RPMTAG_POSTIN = 1024, /* s */ + RPMTAG_PREUN = 1025, /* s */ + RPMTAG_POSTUN = 1026, /* s */ + RPMTAG_OLDFILENAMES = 1027, /* s[] obsolete */ + RPMTAG_FILESIZES = 1028, /* i[] */ + RPMTAG_FILESTATES = 1029, /* c[] */ + RPMTAG_FILEMODES = 1030, /* h[] */ + RPMTAG_FILEUIDS = 1031, /* i[] internal */ + RPMTAG_FILEGIDS = 1032, /* i[] internal */ + RPMTAG_FILERDEVS = 1033, /* h[] */ + RPMTAG_FILEMTIMES = 1034, /* i[] */ + RPMTAG_FILEDIGESTS = 1035, /* s[] */ +#define RPMTAG_FILEMD5S RPMTAG_FILEDIGESTS /* s[] */ + RPMTAG_FILELINKTOS = 1036, /* s[] */ + RPMTAG_FILEFLAGS = 1037, /* i[] */ +/*@-enummemuse@*/ + RPMTAG_ROOT = 1038, /* internal - obsolete */ +/*@=enummemuse@*/ + RPMTAG_FILEUSERNAME = 1039, /* s[] */ + RPMTAG_FILEGROUPNAME = 1040, /* s[] */ +/*@-enummemuse@*/ + RPMTAG_EXCLUDE = 1041, /* internal - obsolete */ + RPMTAG_EXCLUSIVE = 1042, /* internal - obsolete */ +/*@=enummemuse@*/ + RPMTAG_ICON = 1043, /* x */ + RPMTAG_SOURCERPM = 1044, /* s */ + RPMTAG_FILEVERIFYFLAGS = 1045, /* i[] */ + RPMTAG_ARCHIVESIZE = 1046, /* i */ + RPMTAG_PROVIDENAME = 1047, /* s[] */ +#define RPMTAG_PROVIDES RPMTAG_PROVIDENAME /* s[] */ +#define RPMTAG_P RPMTAG_PROVIDENAME /* s[] */ + RPMTAG_REQUIREFLAGS = 1048, /* i[] */ + RPMTAG_REQUIRENAME = 1049, /* s[] */ +#define RPMTAG_REQUIRES RPMTAG_REQUIRENAME /* s[] */ + RPMTAG_REQUIREVERSION = 1050, /* s[] */ + RPMTAG_NOSOURCE = 1051, /* i internal */ + RPMTAG_NOPATCH = 1052, /* i internal */ + RPMTAG_CONFLICTFLAGS = 1053, /* i[] */ + RPMTAG_CONFLICTNAME = 1054, /* s[] */ +#define RPMTAG_CONFLICTS RPMTAG_CONFLICTNAME /* s[] */ +#define RPMTAG_C RPMTAG_CONFLICTNAME /* s[] */ + RPMTAG_CONFLICTVERSION = 1055, /* s[] */ + RPMTAG_DEFAULTPREFIX = 1056, /* s internal - deprecated */ + RPMTAG_BUILDROOT = 1057, /* s internal */ + RPMTAG_INSTALLPREFIX = 1058, /* s internal - deprecated */ + RPMTAG_EXCLUDEARCH = 1059, /* s[] */ + RPMTAG_EXCLUDEOS = 1060, /* s[] */ + RPMTAG_EXCLUSIVEARCH = 1061, /* s[] */ + RPMTAG_EXCLUSIVEOS = 1062, /* s[] */ + RPMTAG_AUTOREQPROV = 1063, /* s internal */ + RPMTAG_RPMVERSION = 1064, /* s */ + RPMTAG_TRIGGERSCRIPTS = 1065, /* s[] */ + RPMTAG_TRIGGERNAME = 1066, /* s[] */ + RPMTAG_TRIGGERVERSION = 1067, /* s[] */ + RPMTAG_TRIGGERFLAGS = 1068, /* i[] */ + RPMTAG_TRIGGERINDEX = 1069, /* i[] */ + RPMTAG_VERIFYSCRIPT = 1079, /* s */ + RPMTAG_CHANGELOGTIME = 1080, /* i[] */ + RPMTAG_CHANGELOGNAME = 1081, /* s[] */ + RPMTAG_CHANGELOGTEXT = 1082, /* s[] */ +/*@-enummemuse@*/ + RPMTAG_BROKENMD5 = 1083, /* internal - obsolete */ +/*@=enummemuse@*/ + RPMTAG_PREREQ = 1084, /* internal */ + RPMTAG_PREINPROG = 1085, /* s */ + RPMTAG_POSTINPROG = 1086, /* s */ + RPMTAG_PREUNPROG = 1087, /* s */ + RPMTAG_POSTUNPROG = 1088, /* s */ + RPMTAG_BUILDARCHS = 1089, /* s[] */ + RPMTAG_OBSOLETENAME = 1090, /* s[] */ +#define RPMTAG_OBSOLETES RPMTAG_OBSOLETENAME /* s[] */ +#define RPMTAG_O RPMTAG_OBSOLETENAME /* s[] */ + RPMTAG_VERIFYSCRIPTPROG = 1091, /* s */ + RPMTAG_TRIGGERSCRIPTPROG = 1092, /* s[] */ + RPMTAG_DOCDIR = 1093, /* internal */ + RPMTAG_COOKIE = 1094, /* s */ + RPMTAG_FILEDEVICES = 1095, /* i[] */ + RPMTAG_FILEINODES = 1096, /* i[] */ + RPMTAG_FILELANGS = 1097, /* s[] */ + RPMTAG_PREFIXES = 1098, /* s[] */ + RPMTAG_INSTPREFIXES = 1099, /* s[] */ + RPMTAG_TRIGGERIN = 1100, /* internal */ + RPMTAG_TRIGGERUN = 1101, /* internal */ + RPMTAG_TRIGGERPOSTUN = 1102, /* internal */ + RPMTAG_AUTOREQ = 1103, /* internal */ + RPMTAG_AUTOPROV = 1104, /* internal */ +/*@-enummemuse@*/ + RPMTAG_CAPABILITY = 1105, /* i legacy - obsolete */ +/*@=enummemuse@*/ + RPMTAG_SOURCEPACKAGE = 1106, /* i legacy - obsolete */ +/*@-enummemuse@*/ + RPMTAG_OLDORIGFILENAMES = 1107, /* internal - obsolete */ +/*@=enummemuse@*/ + RPMTAG_BUILDPREREQ = 1108, /* internal */ + RPMTAG_BUILDREQUIRES = 1109, /* internal */ + RPMTAG_BUILDCONFLICTS = 1110, /* internal */ +/*@-enummemuse@*/ + RPMTAG_BUILDMACROS = 1111, /* s[] srpms only */ +/*@=enummemuse@*/ + RPMTAG_PROVIDEFLAGS = 1112, /* i[] */ + RPMTAG_PROVIDEVERSION = 1113, /* s[] */ + RPMTAG_OBSOLETEFLAGS = 1114, /* i[] */ + RPMTAG_OBSOLETEVERSION = 1115, /* s[] */ + RPMTAG_DIRINDEXES = 1116, /* i[] */ + RPMTAG_BASENAMES = 1117, /* s[] */ + RPMTAG_DIRNAMES = 1118, /* s[] */ + RPMTAG_ORIGDIRINDEXES = 1119, /* i[] relocation */ + RPMTAG_ORIGBASENAMES = 1120, /* s[] relocation */ + RPMTAG_ORIGDIRNAMES = 1121, /* s[] relocation */ + RPMTAG_OPTFLAGS = 1122, /* s */ + RPMTAG_DISTURL = 1123, /* s */ + RPMTAG_PAYLOADFORMAT = 1124, /* s */ + RPMTAG_PAYLOADCOMPRESSOR = 1125, /* s */ + RPMTAG_PAYLOADFLAGS = 1126, /* s */ + RPMTAG_INSTALLCOLOR = 1127, /* i transaction color when installed */ + RPMTAG_INSTALLTID = 1128, /* i[] */ + RPMTAG_REMOVETID = 1129, /* i[] */ +/*@-enummemuse@*/ + RPMTAG_SHA1RHN = 1130, /* internal - obsolete */ +/*@=enummemuse@*/ + RPMTAG_RHNPLATFORM = 1131, /* s deprecated */ + RPMTAG_PLATFORM = 1132, /* s */ + RPMTAG_PATCHESNAME = 1133, /* s[] deprecated placeholder (SuSE) */ + RPMTAG_PATCHESFLAGS = 1134, /* i[] deprecated placeholder (SuSE) */ + RPMTAG_PATCHESVERSION = 1135, /* s[] deprecated placeholder (SuSE) */ + RPMTAG_CACHECTIME = 1136, /* i rpmcache(8) only */ + RPMTAG_CACHEPKGPATH = 1137, /* s rpmcache(8) only */ + RPMTAG_CACHEPKGSIZE = 1138, /* i rpmcache(8) only */ + RPMTAG_CACHEPKGMTIME = 1139, /* i rpmcache(8) only */ + RPMTAG_FILECOLORS = 1140, /* i[] */ + RPMTAG_FILECLASS = 1141, /* i[] */ + RPMTAG_CLASSDICT = 1142, /* s[] */ + RPMTAG_FILEDEPENDSX = 1143, /* i[] */ + RPMTAG_FILEDEPENDSN = 1144, /* i[] */ + RPMTAG_DEPENDSDICT = 1145, /* i[] */ + RPMTAG_SOURCEPKGID = 1146, /* x */ + RPMTAG_FILECONTEXTS = 1147, /* s[] */ + RPMTAG_FSCONTEXTS = 1148, /* s[] extension */ + RPMTAG_RECONTEXTS = 1149, /* s[] extension */ + RPMTAG_POLICIES = 1150, /* s[] selinux *.te policy file. */ + RPMTAG_PRETRANS = 1151, /* s */ + RPMTAG_POSTTRANS = 1152, /* s */ + RPMTAG_PRETRANSPROG = 1153, /* s */ + RPMTAG_POSTTRANSPROG = 1154, /* s */ + RPMTAG_DISTTAG = 1155, /* s */ + RPMTAG_SUGGESTSNAME = 1156, /* s[] extension */ +#define RPMTAG_SUGGESTS RPMTAG_SUGGESTSNAME /* s[] */ + RPMTAG_SUGGESTSVERSION = 1157, /* s[] extension */ + RPMTAG_SUGGESTSFLAGS = 1158, /* i[] extension */ + RPMTAG_ENHANCESNAME = 1159, /* s[] extension placeholder */ +#define RPMTAG_ENHANCES RPMTAG_ENHANCESNAME /* s[] */ + RPMTAG_ENHANCESVERSION = 1160, /* s[] extension placeholder */ + RPMTAG_ENHANCESFLAGS = 1161, /* i[] extension placeholder */ + RPMTAG_PRIORITY = 1162, /* i[] extension placeholder */ + RPMTAG_CVSID = 1163, /* s */ +#define RPMTAG_SVNID RPMTAG_CVSID /* s */ + RPMTAG_BLINKPKGID = 1164, /* s[] */ + RPMTAG_BLINKHDRID = 1165, /* s[] */ + RPMTAG_BLINKNEVRA = 1166, /* s[] */ + RPMTAG_FLINKPKGID = 1167, /* s[] */ + RPMTAG_FLINKHDRID = 1168, /* s[] */ + RPMTAG_FLINKNEVRA = 1169, /* s[] */ + RPMTAG_PACKAGEORIGIN = 1170, /* s */ + RPMTAG_TRIGGERPREIN = 1171, /* internal */ + RPMTAG_BUILDSUGGESTS = 1172, /* internal */ + RPMTAG_BUILDENHANCES = 1173, /* internal */ + RPMTAG_SCRIPTSTATES = 1174, /* i[] scriptlet exit codes */ + RPMTAG_SCRIPTMETRICS = 1175, /* i[] scriptlet execution times */ + RPMTAG_BUILDCPUCLOCK = 1176, /* i */ + RPMTAG_FILEDIGESTALGOS = 1177, /* i[] */ + RPMTAG_VARIANTS = 1178, /* s[] */ + RPMTAG_XMAJOR = 1179, /* i */ + RPMTAG_XMINOR = 1180, /* i */ + RPMTAG_REPOTAG = 1181, /* s */ + RPMTAG_KEYWORDS = 1182, /* s[] */ + RPMTAG_BUILDPLATFORMS = 1183, /* s[] */ + RPMTAG_PACKAGECOLOR = 1184, /* i */ + RPMTAG_PACKAGEPREFCOLOR = 1185, /* i (unimplemented) */ + RPMTAG_XATTRSDICT = 1186, /* s[] (unimplemented) */ + RPMTAG_FILEXATTRSX = 1187, /* i[] (unimplemented) */ + RPMTAG_DEPATTRSDICT = 1188, /* s[] (unimplemented) */ + RPMTAG_CONFLICTATTRSX = 1189, /* i[] (unimplemented) */ + RPMTAG_OBSOLETEATTRSX = 1190, /* i[] (unimplemented) */ + RPMTAG_PROVIDEATTRSX = 1191, /* i[] (unimplemented) */ + RPMTAG_REQUIREATTRSX = 1192, /* i[] (unimplemented) */ + RPMTAG_BUILDPROVIDES = 1193, /* internal */ + RPMTAG_BUILDOBSOLETES = 1194, /* internal */ + RPMTAG_DBINSTANCE = 1195, /* i */ + RPMTAG_NVRA = 1196, /* s */ + RPMTAG_FILEPATHS = 1197, /* s[] */ + RPMTAG_ORIGPATHS = 1198, /* s[] */ + RPMTAG_RPMLIBVERSION = 1199, /* i */ + RPMTAG_RPMLIBTIMESTAMP = 1200, /* i */ + RPMTAG_RPMLIBVENDOR = 1201, /* i */ + RPMTAG_CLASS = 1202, /* s arbitrary */ + RPMTAG_TRACK = 1203, /* s internal arbitrary */ + RPMTAG_TRACKPROG = 1204, /* s internal arbitrary */ + RPMTAG_SANITYCHECK = 1205, /* s */ + RPMTAG_SANITYCHECKPROG = 1206, /* s */ + RPMTAG_FILESTAT = 1207, /* s[] stat(2) from metadata extension*/ + RPMTAG_STAT = 1208, /* s[] stat(2) from disk extension */ + RPMTAG_ORIGINTID = 1209, /* i[] */ + RPMTAG_ORIGINTIME = 1210, /* i[] */ + RPMTAG_HEADERSTARTOFF = 1211, /* l */ + RPMTAG_HEADERENDOFF = 1212, /* l */ + RPMTAG_PACKAGETIME = 1213, /* l */ + RPMTAG_PACKAGESIZE = 1214, /* l */ + RPMTAG_PACKAGEDIGEST = 1215, /* s */ + RPMTAG_PACKAGESTAT = 1216, /* x */ + RPMTAG_PACKAGEBASEURL = 1217, /* s */ + RPMTAG_DISTEPOCH = 1218, /* s */ +#define RPMTAG_D RPMTAG_DISTEPOCH /* s */ + + RPMTAG_CONFLICTYAMLENTRY = 1219, /* s[] */ + RPMTAG_OBSOLETEYAMLENTRY = 1220, /* s[] */ + RPMTAG_PROVIDEYAMLENTRY = 1221, /* s[] */ + RPMTAG_REQUIREYAMLENTRY = 1222, /* s[] */ + + RPMTAG_FILEDIGESTALGO = 5011, /* i file checksum algorithm */ + RPMTAG_BUGURL = 5012, /* s */ + +/*@-enummemuse@*/ + RPMTAG_FIRSTFREE_TAG, /*!< internal */ +/*@=enummemuse@*/ + + RPMTAG_PACKAGETRANSFLAGS = 0x4efaafd9, /* s[] arbitrary */ + RPMTAG_PACKAGEDEPFLAGS = 0x748a8314, /* s[] arbitrary */ + + RPMTAG_BUILDPREPPROG = 0x4ba37c9e, /* s[] arbitrary */ + RPMTAG_BUILDPREP = 0x799c0b4d, /* s[] arbitrary */ + RPMTAG_BUILDBUILDPROG = 0x6fb46014, /* s[] arbitrary */ + RPMTAG_BUILDBUILD = 0x5bae1a5a, /* s[] arbitrary */ + RPMTAG_BUILDINSTALLPROG = 0x70d4ab6f, /* s[] arbitrary */ + RPMTAG_BUILDINSTALL = 0x567f5983, /* s[] arbitrary */ + RPMTAG_BUILDCHECKPROG = 0x488a60ce, /* s[] arbitrary */ + RPMTAG_BUILDCHECK = 0x7f3b97b5, /* s[] arbitrary */ + RPMTAG_BUILDCLEANPROG = 0x42c93d41, /* s[] arbitrary */ + RPMTAG_BUILDCLEAN = 0x566042bf, /* s[] arbitrary */ + + RPMTAG_LASTARBITRARY_TAG = 0x80000000 /*!< internal */ +}; + +#define RPMTAG_EXTERNAL_TAG 1000000 + +/** \ingroup signature + * Tags found in signature header from package. + */ +enum rpmSigTag_e { + RPMSIGTAG_SIZE = 1000, /*!< internal Header+Payload size in bytes. */ + RPMSIGTAG_LEMD5_1 = 1001, /*!< internal Broken MD5, take 1 @deprecated legacy. */ + RPMSIGTAG_PGP = 1002, /*!< internal PGP 2.6.3 signature. */ + RPMSIGTAG_LEMD5_2 = 1003, /*!< internal Broken MD5, take 2 @deprecated legacy. */ + RPMSIGTAG_MD5 = 1004, /*!< internal MD5 signature. */ + RPMSIGTAG_GPG = 1005, /*!< internal GnuPG signature. */ + RPMSIGTAG_PGP5 = 1006, /*!< internal PGP5 signature @deprecated legacy. */ + RPMSIGTAG_PAYLOADSIZE = 1007,/*!< internal uncompressed payload size in bytes. */ + RPMSIGTAG_BADSHA1_1 = RPMTAG_BADSHA1_1, /*!< internal Broken SHA1, take 1. */ + RPMSIGTAG_BADSHA1_2 = RPMTAG_BADSHA1_2, /*!< internal Broken SHA1, take 2. */ + RPMSIGTAG_SHA1 = RPMTAG_SHA1HEADER, /*!< internal sha1 header digest. */ + RPMSIGTAG_DSA = RPMTAG_DSAHEADER, /*!< internal DSA header signature. */ + RPMSIGTAG_RSA = RPMTAG_RSAHEADER, /*!< internal RSA header signature. */ + RPMSIGTAG_PADDING = 0x3fffffff /*!< signature header padding */ +}; + +/** \ingroup header + */ +typedef enum rpmTag_e rpmTag; + +/** \ingroup header + */ +typedef enum rpmSigTag_e rpmSigTag; + +/** \ingroup header + */ +/*@-typeuse -fielduse@*/ +#if !defined(SWIG) +struct _HE_s { + rpmTag tag; + rpmTagType t; +/*@owned@*/ /*@null@*/ + rpmTagData p; + rpmTagCount c; + int ix; + unsigned int freeData : 1; + unsigned int avail : 1; + unsigned int append : 1; +}; +#endif + +/** + */ +typedef struct _HE_s HE_s; + +/** \ingroup rpmdb + */ +typedef struct tagStore_s * tagStore_t; + +/** + */ +typedef /*@abstract@*/ const struct headerTagTableEntry_s * headerTagTableEntry; + +#if defined(_RPMTAG_INTERNAL) +/** + */ +/** \ingroup header + * Associate tag names with numeric values. + */ +#if !defined(SWIG) +struct headerTagTableEntry_s { +/*@observer@*/ /*@relnull@*/ + const char * name; /*!< Tag name. */ + rpmTag val; /*!< Tag numeric value. */ + rpmTagType type; /*!< Tag type. */ +}; +#endif + +/** + */ +struct tagStore_s { +/*@only@*/ + const char * str; /*!< Tag string (might be arbitrary). */ + rpmTag tag; /*!< Tag number. */ + rpmiob iob; /*!< Tag contents. */ +}; +#endif /* _RPMTAG_INTERNAL */ + +/** + * Automatically generated table of tag name/value pairs. + */ +/*@-redecl@*/ +/*@observer@*/ /*@unchecked@*/ +extern headerTagTableEntry rpmTagTable; +/*@=redecl@*/ + +/** + * Number of entries in rpmTagTable. + */ +/*@-redecl@*/ +/*@unchecked@*/ +extern int rpmTagTableSize; + +/*@unchecked@*/ +extern headerTagIndices rpmTags; +/*@=redecl@*/ + +#if defined(_RPMTAG_INTERNAL) +/** + */ +#if !defined(SWIG) +struct headerTagIndices_s { +/*@relnull@*/ + int (*loadIndex) (headerTagTableEntry ** ipp, size_t * np, + int (*cmp) (const void * avp, const void * bvp)) + /*@ modifies *ipp, *np */; /*!< Load sorted tag index. */ +/*@relnull@*/ + headerTagTableEntry * byName; /*!< rpmTag's sorted by name. */ + size_t byNameSize; /*!< No. of entries. */ + int (*byNameCmp) (const void * avp, const void * bvp) + /*@*/; /*!< Compare entries by name. */ + rpmTag (*tagValue) (const char * name) + /*@*/; /*!< Return value from name. */ +/*@relnull@*/ + headerTagTableEntry * byValue; /*!< rpmTag's sorted by value. */ + size_t byValueSize; /*!< No. of entries. */ + int (*byValueCmp) (const void * avp, const void * bvp) + /*@*/; /*!< Compare entries by value. */ + const char * (*tagName) (rpmTag value) + /*@*/; /*!< Return name from value. */ + rpmTag (*tagType) (rpmTag value) + /*@*/; /*!< Return type from value. */ + size_t nameBufLen; /*!< No. bytes allocated for nameBuf. */ +/*@relnull@*/ + const char ** aTags; /*!< Arbitrary tags array (ARGV_t) */ +/*@owned@*/ /*@null@*/ + char * nameBuf; /* Name buffer. */ +/*@only@*/ + char * (*tagCanonicalize) (const char * s) + /*@*/; /*!< Canonicalize arbitrary string. */ + rpmTag (*tagGenerate) (const char * s) + /*@*/; /*!< Generate tag from string. */ +}; +#endif +#endif /* _RPMTAG_INTERNAL */ + +/** + * Return tag name from value. + * @param tag tag value + * @return tag name, "(unknown)" on not found + */ +/*@observer@*/ +const char * tagName(rpmTag tag) + /*@*/; + +/** + * Return tag data type from value. + * @todo Return rpmTagType-like, not unsigned int. There's no clear typedef yet. + * @param tag tag value + * @return tag data type, 0 on not found. + */ +unsigned int tagType(rpmTag tag) + /*@*/; + +/** + * Return tag value from name. + * @param tagstr name of tag + * @return tag value, 0xffffffff on not found + */ +rpmTag tagValue(const char * tagstr) + /*@*/; + +/** + * Canonicalize a rpmTag string. + * @param s string + * @return canonicalized string + */ +/*@only@*/ +char * tagCanonicalize(const char * s) + /*@*/; + +/** + * Generate a tag from arbitrary string. + * @param s string + * @return generated tag value + */ +rpmTag tagGenerate(const char * s) + /*@*/; + +/** + * Free memory in header tag indices. + * @param _rpmTags header tag indices (NULL uses rpmTags) + */ +void tagClean(/*@null@*/ headerTagIndices _rpmTags) + /*@globals rpmTags @*/ + /*@modifies _rpmTags, rpmTags @*/; + +/** + * Destroy tagStore array. + * @param dbiTags dbi tag storage + * @param dbiNTags no. of dbi tags + * @return NULL always + */ +/*@null@*/ +tagStore_t tagStoreFree(/*@only@*//*@null@*/tagStore_t dbiTags, size_t dbiNTags) + /*@modifies dbiTags @*/; + +#if defined(_RPMTAG_INTERNAL) +/** \ingroup header + */ +typedef enum headerSprintfExtensionType_e { + HEADER_EXT_LAST = 0, /*!< End of extension chain. */ + HEADER_EXT_FORMAT, /*!< headerTagFormatFunction() extension */ + HEADER_EXT_MORE, /*!< Chain to next table. */ + HEADER_EXT_TAG /*!< headerTagTagFunction() extension */ +} headerSprintfExtensionType; + +/** \ingroup header + * HEADER_EXT_TAG format function prototype. + * + * @param he tag container + * @param av parameter array (or NULL) + * @return formatted string + */ +typedef /*only@*/ char * (*headerTagFormatFunction) (HE_t he, /*@null@*/ const char ** av) + /*@modifies he @*/; + +/** \ingroup header + * HEADER_EXT_FORMAT format function prototype. + * This is allowed to fail, which indicates the tag doesn't exist. + * + * @param h header + * @retval he tag container + * @return 0 on success + */ +typedef int (*headerTagTagFunction) (Header h, HE_t he) + /*@modifies he @*/; + +/** \ingroup header + * Define header tag output formats. + */ +#if !defined(SWIG) +struct headerSprintfExtension_s { + headerSprintfExtensionType type; /*!< Type of extension. */ +/*@observer@*/ /*@null@*/ + const char * name; /*!< Name of extension. */ + union { +/*@observer@*/ /*@null@*/ + void * generic; /*!< Private extension. */ + headerTagFormatFunction fmtFunction; /*!< HEADER_EXT_TAG extension. */ + headerTagTagFunction tagFunction; /*!< HEADER_EXT_FORMAT extension. */ + headerSprintfExtension * more; /*!< Chained table extension. */ + } u; +}; +#endif +#endif /* _RPMTAG_INTERNAL */ + +/** \ingroup header + * Supported default header tag output formats. + */ +/*@unchecked@*/ /*@observer@*/ +extern headerSprintfExtension headerDefaultFormats; + +/** \ingroup header + * Supported default header extension/tag output formats. + */ +/*@unchecked@*/ /*@observer@*/ +extern headerSprintfExtension headerCompoundFormats; + +/** + * Display list of tags that can be used in --queryformat. + * @param fp file handle to use for display (NULL uses stdout) + * @param _rpmTagTable rpm tag table (NULL uses rpmTagTable) + * @param _rpmHeaderFormats rpm tag extensions & formats (NULL uses headerCompoundFormats) + */ +void rpmDisplayQueryTags(/*@null@*/ FILE * fp, + /*@null@*/ headerTagTableEntry _rpmTagTable, + /*@null@*/ headerSprintfExtension _rpmHeaderFormats) + /*@globals fileSystem, internalState @*/ + /*@modifies *fp, fileSystem, internalState @*/; + +/** \ingroup header + * Return formatted output string from header tags. + * The returned string must be free()d. + * + * @param h header + * @param fmt format to use + * @param tags array of tag name/value/type triples (NULL uses default) + * @param exts formatting extensions chained table (NULL uses default) + * @retval errmsg error message (if any) + * @return formatted output string (malloc'ed) + */ +/*@only@*/ /*@null@*/ +char * headerSprintf(Header h, const char * fmt, + /*@null@*/ headerTagTableEntry tags, + /*@null@*/ headerSprintfExtension exts, + /*@null@*/ /*@out@*/ errmsg_t * errmsg) + /*@globals headerCompoundFormats, fileSystem, internalState @*/ + /*@modifies h, *errmsg, fileSystem, internalState @*/; + +/** \ingroup header + * Retrieve extension or tag value from a header. + * + * @param h header + * @param he tag container + * @param flags tag retrieval flags + * @return 1 on success, 0 on failure + */ +int headerGet(Header h, HE_t he, unsigned int flags) + /*@globals internalState @*/ + /*@modifies he, internalState @*/; +#define HEADERGET_NOEXTENSION (1 << 0) /*!< Extension search disabler. */ +#define HEADERGET_NOI18NSTRING (1 << 1) /*!< Return i18n strings as argv. */ + +/** \ingroup header + * Add or append tag container to header. + * + * @param h header + * @param he tag container + * @param flags (unused) + * @return 1 on success, 0 on failure + */ +/*@mayexit@*/ +int headerPut(Header h, HE_t he, /*@unused@*/ unsigned int flags) + /*@modifies h @*/; + +/** \ingroup header + * Remove tag container from header. + * + * @param h header + * @param he tag container + * @param flags (unused) + * @return 1 on success, 0 on failure + */ +/*@mayexit@*/ +int headerDel(Header h, HE_t he, /*@unused@*/ unsigned int flags) + /*@modifies h @*/; + +/** \ingroup header + * Modify tag container in header. + * If there are multiple entries with this tag, the first one gets replaced. + * @param h header + * @param he tag container + * @param flags (unused) + * @return 1 on success, 0 on failure + */ +int headerMod(Header h, HE_t he, /*@unused@*/ unsigned int flags) + /*@modifies h @*/; + +/** \ingroup header + * Destroy header tag container iterator. + * @param hi header tag container iterator + * @return NULL always + */ +/*@null@*/ +HeaderIterator headerFini(/*@only@*/ HeaderIterator hi) + /*@globals fileSystem @*/ + /*@modifies hi, fileSystem */; + +/** \ingroup header + * Create header tag iterator. + * @param h header + * @return header tag iterator + */ +HeaderIterator headerInit(Header h) + /*@globals fileSystem @*/ + /*@modifies h, fileSystem */; + +/** \ingroup header + * Return next tag from header. + * @param hi header tag iterator + * @param he tag container + * @param flags (unused) + * @return 1 on success, 0 on failure + */ +int headerNext(HeaderIterator hi, HE_t he, /*@unused@*/ unsigned int flags) + /*@globals internalState @*/ + /*@modifies hi, he, internalState @*/; + +/** \ingroup header + * Reference a header instance. + * @param h header + * @return referenced header instance + */ +Header headerLink(Header h) + /*@modifies h @*/; +#define headerLink(_h) \ + ((Header)rpmioLinkPoolItem((rpmioItem)(_h), __FUNCTION__, __FILE__, __LINE__)) + +/** \ingroup header + * Dereference a header instance. + * @param h header + * @return NULL on last dereference + */ +/*@null@*/ +Header headerUnlink(/*@killref@*/ /*@null@*/ Header h) + /*@modifies h @*/; +#define headerUnlink(_h) \ + ((Header)rpmioUnlinkPoolItem((rpmioItem)(_h), __FUNCTION__, __FILE__, __LINE__)) + +/** \ingroup header + * Dereference a header instance. + * @param h header + * @return NULL on last dereference + */ +/*@null@*/ +Header headerFree(/*@killref@*/ /*@null@*/ Header h) + /*@modifies h @*/; +#define headerFree(_h) \ + ((Header)rpmioFreePoolItem((rpmioItem)(_h), __FUNCTION__, __FILE__, __LINE__)) + +/** \ingroup header + * Create new (empty) header instance. + * @return header + */ +Header headerNew(void) + /*@globals fileSystem @*/ + /*@modifies fileSystem @*/; + +/** \ingroup header + * Return size of on-disk header representation in bytes. + * @param h header + * @return size of on-disk header + */ +size_t headerSizeof(/*@null@*/ Header h) + /*@modifies h @*/; + +/** \ingroup header + * headerUnload. + * @param h header + * @retval *lenp no. bytes in unloaded header blob + * @return unloaded header blob (NULL on error) + */ +/*@only@*/ /*@null@*/ +void * headerUnload(Header h, /*@out@*/ /*@null@*/ size_t * lenp) + /*@globals internalState @*/ + /*@modifies h, *lenp, internalState @*/; + +/** \ingroup header + * Convert header to on-disk representation, and then reload. + * This is used to insure that all header data is in a single + * contiguous memory allocation. + * @param h header (with pointers) + * @param tag region tag + * @return on-disk header (with offsets) + */ +/*@null@*/ +Header headerReload(/*@only@*/ Header h, int tag) + /*@globals fileSystem, internalState @*/ + /*@modifies h, fileSystem, internalState @*/; + +/** \ingroup header + * Duplicate a header. + * @param h header + * @return new header instance + */ +/*@null@*/ +Header headerCopy(Header h) + /*@globals fileSystem, internalState @*/ + /*@modifies h, fileSystem, internalState @*/; + +/** \ingroup header + * Convert header to in-memory representation. + * @param uh on-disk header blob (i.e. with offsets) + * @return header + */ +/*@null@*/ +Header headerLoad(/*@kept@*/ void * uh) + /*@globals fileSystem, internalState @*/ + /*@modifies uh, fileSystem, internalState @*/; + +/** \ingroup header + * Make a copy and convert header to in-memory representation. + * @param uh on-disk header blob (i.e. with offsets) + * @return header + */ +/*@null@*/ +Header headerCopyLoad(const void * uh) + /*@globals fileSystem, internalState @*/ + /*@modifies fileSystem, internalState @*/; + +/** \ingroup header + * Check if tag is in header. + * @param h header + * @param tag tag + * @return 1 on success, 0 on failure + */ +int headerIsEntry(/*@null@*/ Header h, rpmTag tag) + /*@*/; + +/** \ingroup header + * Add locale specific tag to header. + * A NULL lang is interpreted as the C locale. Here are the rules: + * \verbatim + * - If the tag isn't in the header, it's added with the passed string + * as new value. + * - If the tag occurs multiple times in entry, which tag is affected + * by the operation is undefined. + * - If the tag is in the header w/ this language, the entry is + * *replaced* (like headerModifyEntry()). + * \endverbatim + * This function is intended to just "do the right thing". If you need + * more fine grained control use headerAddEntry() and headerModifyEntry(). + * + * @param h header + * @param tag tag + * @param string tag value + * @param lang locale + * @return 1 on success, 0 on failure + */ +int headerAddI18NString(Header h, rpmTag tag, const char * string, + const char * lang) + /*@modifies h @*/; + +/** \ingroup header + * Duplicate tag values from one header into another. + * @param headerFrom source header + * @param headerTo destination header + * @param tagstocopy array of tags that are copied + */ +void headerCopyTags(Header headerFrom, Header headerTo, rpmTag * tagstocopy) + /*@globals internalState @*/ + /*@modifies headerTo, internalState @*/; + +/** \ingroup header + * Return header magic. + * @param h header + * @param *magicp magic array + * @param *nmagicp no. bytes of magic + * @return 0 always + */ +int headerGetMagic(/*@null@*/ Header h, unsigned char **magicp, size_t *nmagicp) + /*@modifies *magicp, *nmagicp @*/; + +/** \ingroup header + * Store header magic. + * @param h header + * @param magic magic array + * @param nmagic no. bytes of magic + * @return 0 always + */ +int headerSetMagic(/*@null@*/ Header h, unsigned char * magic, size_t nmagic) + /*@modifies h @*/; + +/** \ingroup header + * Return header origin (e.g path or URL). + * @param h header + * @return header origin + */ +/*@observer@*/ /*@null@*/ +const char * headerGetOrigin(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header origin (e.g path or URL). + * @param h header + * @param origin new header origin + * @return 0 always + */ +int headerSetOrigin(/*@null@*/ Header h, const char * origin) + /*@modifies h @*/; + +/** \ingroup header + * Return header parent identifier (e.g parent's NVRA). + * @param h header + * @return header parent + */ +/*@observer@*/ /*@null@*/ +const char * headerGetParent(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header parent (e.g parent's NVRA). + * @param h header + * @param parent new header parent + * @return 0 always + */ +int headerSetParent(/*@null@*/ Header h, const char * parent) + /*@modifies h @*/; + +/** \ingroup header + * Return header base URL (e.g path or URL). + * @param h header + * @return header origin + */ +/*@observer@*/ /*@null@*/ +const char * headerGetBaseURL(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header base URL (e.g path or URL). + * @param h header + * @param baseurl new header baseurl + * @return 0 always + */ +int headerSetBaseURL(/*@null@*/ Header h, const char * baseurl) + /*@modifies h @*/; + +/** \ingroup header + * Return header stat(2) buffer (of origin *.rpm file). + * @param h header + * @return header stat(2) buffer + */ +struct stat * headerGetStatbuf(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Copy into header stat(2) buffer (of origin *.rpm file). + * @param h header + * @param st new header stat(2) buffer + * @return 0 always + */ +int headerSetStatbuf(/*@null@*/ Header h, struct stat * st) + /*@modifies h @*/; + +/** \ingroup header + * Return digest of origin *.rpm file. + * @param h header + * @return header digest + */ +/*@null@*/ +const char * headerGetDigest(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store digest of origin *.rpm file. + * @param h header + * @param st new header digest + * @return 0 always + */ +int headerSetDigest(/*@null@*/ Header h, const char * digest) + /*@modifies h @*/; + +/** \ingroup header + * Return rpmdb pointer. + * @param h header + * @return rpmdb pointer + */ +/*@null@*/ +void * headerGetRpmdb(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store rpmdb pointer. + * @param h header + * @param rpmdb new rpmdb pointer (or NULL to unset) + * @return NULL always + */ +/*@null@*/ +void * headerSetRpmdb(/*@null@*/ Header h, /*@null@*/ void * rpmdb) + /*@modifies h @*/; + +/** \ingroup header + * Return header instance (if from rpmdb). + * @param h header + * @return header instance + */ +uint32_t headerGetInstance(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header instance (e.g path or URL). + * @param h header + * @param instance new header instance + * @return 0 always + */ +uint32_t headerSetInstance(/*@null@*/ Header h, uint32_t instance) + /*@modifies h @*/; + +/** \ingroup header + * Return header starting byte offset. + * @param h header + * @return header starting byte offset + */ +rpmuint32_t headerGetStartOff(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header starting byte offset. + * @param h header + * @param startoff new header starting byte offset + * @return 0 always + */ +rpmuint32_t headerSetStartOff(/*@null@*/ Header h, rpmuint32_t startoff) + /*@modifies h @*/; + +/** \ingroup header + * Return header ending byte offset. + * @param h header + * @return header ending byte offset + */ +rpmuint32_t headerGetEndOff(/*@null@*/ Header h) + /*@*/; + +/** \ingroup header + * Store header ending byte offset. + * @param h header + * @param startoff new header ending byte offset + * @return 0 always + */ +rpmuint32_t headerSetEndOff(/*@null@*/ Header h, rpmuint32_t endoff) + /*@modifies h @*/; + +/** \ingroup header + * Return header stats accumulator structure. + * @param h header + * @param opx per-header accumulator index (aka rpmtsOpX) + * @return per-header accumulator pointer + */ +/*@null@*/ +void * headerGetStats(Header h, int opx) + /*@*/; + +/** + * Define per-header macros. + * @param h header + * @return 0 always + */ +int headerMacrosLoad(Header h) + /*@globals internalState @*/ + /*@modifies internalState @*/; + +/** + * Define per-header macros. + * @param h header + * @return 0 always + */ +int headerMacrosUnload(Header h) + /*@globals internalState @*/ + /*@modifies internalState @*/; + +/** \ingroup header + * Return name, epoch, version, release, arch strings from header. + * @param h header + * @retval *np name pointer (or NULL) + * @retval *ep epoch pointer (or NULL) + * @retval *vp version pointer (or NULL) + * @retval *rp release pointer (or NULL) + * @retval *ap arch pointer (or NULL) + * @return 0 always + */ +int headerNEVRA(Header h, + /*@null@*/ /*@out@*/ const char ** np, + /*@null@*/ /*@out@*/ /*@unused@*/ const char ** ep, + /*@null@*/ /*@out@*/ const char ** vp, + /*@null@*/ /*@out@*/ const char ** rp, + /*@null@*/ /*@out@*/ const char ** ap) + /*@globals internalState @*/ + /*@modifies h, *np, *vp, *rp, *ap, internalState @*/; + +/** + * Return header color. + * @param h header + * @return header color + */ +rpmuint32_t hGetColor(Header h) + /*@globals internalState @*/ + /*@modifies h, internalState @*/; + +/** \ingroup header + * Translate and merge legacy signature tags into header. + * @todo Remove headerSort() through headerInitIterator() modifies sig. + * @param h header + * @param sigh signature header + */ +void headerMergeLegacySigs(Header h, const Header sigh) + /*@globals fileSystem, internalState @*/ + /*@modifies h, sigh, fileSystem, internalState @*/; + +/** \ingroup header + * Regenerate signature header. + * @todo Remove headerSort() through headerInitIterator() modifies h. + * @param h header + * @param noArchiveSize don't copy archive size tag (pre rpm-4.1) + * @return regenerated signature header + */ +Header headerRegenSigHeader(const Header h, int noArchiveSize) + /*@globals fileSystem, internalState @*/ + /*@modifies h, fileSystem, internalState @*/; + +#ifdef __cplusplus +} +#endif + +#endif /* H_RPMTAG */ -- 2.39.5