Blame src/daemon/abrt-action-save-package-data.c

Packit 8ea169
/*
Packit 8ea169
    Copyright (C) 2009  Zdenek Prikryl (zprikryl@redhat.com)
Packit 8ea169
    Copyright (C) 2009  RedHat inc.
Packit 8ea169
Packit 8ea169
    This program is free software; you can redistribute it and/or modify
Packit 8ea169
    it under the terms of the GNU General Public License as published by
Packit 8ea169
    the Free Software Foundation; either version 2 of the License, or
Packit 8ea169
    (at your option) any later version.
Packit 8ea169
Packit 8ea169
    This program is distributed in the hope that it will be useful,
Packit 8ea169
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8ea169
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8ea169
    GNU General Public License for more details.
Packit 8ea169
Packit 8ea169
    You should have received a copy of the GNU General Public License along
Packit 8ea169
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit 8ea169
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 8ea169
*/
Packit 8ea169
#include <fnmatch.h>
Packit 8ea169
#include <glib.h>
Packit 8ea169
#include "libabrt.h"
Packit 8ea169
#include "rpm.h"
Packit 8ea169
Packit 8ea169
#define GPG_CONF "gpg_keys.conf"
Packit 8ea169
Packit 8ea169
/**
Packit 8ea169
    "python3.4, python3.5, python3.6, python3.7, perl, perl5.16.2"
Packit 8ea169
  * The regexes should cover interpreters with basename:
Packit 8ea169
  * Python:
Packit 8ea169
  *   python
Packit 8ea169
  *   python2
Packit 8ea169
  *   python3
Packit 8ea169
  *   python2.7
Packit 8ea169
  *   python3.8
Packit 8ea169
  *   platform-python
Packit 8ea169
  *   platform-python3
Packit 8ea169
  *   platform-python3.8
Packit 8ea169
  *
Packit 8ea169
  * Perl:
Packit 8ea169
  *   perl
Packit 8ea169
  *   perl5.30.1
Packit 8ea169
  *
Packit 8ea169
  * PHP:
Packit 8ea169
  *   php
Packit 8ea169
  *   php-cgi
Packit 8ea169
  *
Packit 8ea169
  * R:
Packit 8ea169
  *   R
Packit 8ea169
  *
Packit 8ea169
  * tcl:
Packit 8ea169
  *   tclsh
Packit 8ea169
  *   tclsh8.6
Packit 8ea169
  **/
Packit 8ea169
#define DEFAULT_INTERPRETERS_REGEX \
Packit 8ea169
    "^(perl ([[:digit:]][.][[:digit:]]+[.][[:digit:]])? |" \
Packit 8ea169
    "php (-cgi)? |" \
Packit 8ea169
    "(platform-)? python ([[:digit:]]([.][[:digit:]])?)? |" \
Packit 8ea169
    "R |" \
Packit 8ea169
    "tclsh ([[:digit:]][.][[:digit:]])?)$"
Packit 8ea169
Packit 8ea169
static bool   settings_bOpenGPGCheck = false;
Packit 8ea169
static GList *settings_setOpenGPGPublicKeys = NULL;
Packit 8ea169
static GList *settings_setBlackListedPkgs = NULL;
Packit 8ea169
static GList *settings_setBlackListedPaths = NULL;
Packit 8ea169
static bool   settings_bProcessUnpackaged = false;
Packit 8ea169
static GList *settings_Interpreters = NULL;
Packit 8ea169
Packit 8ea169
static void ParseCommon(map_string_t *settings, const char *conf_filename)
Packit 8ea169
{
Packit 8ea169
    const char *value;
Packit 8ea169
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "OpenGPGCheck");
Packit 8ea169
    if (value)
Packit 8ea169
    {
Packit 8ea169
        settings_bOpenGPGCheck = string_to_bool(value);
Packit 8ea169
        remove_map_string_item(settings, "OpenGPGCheck");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "BlackList");
Packit 8ea169
    if (value)
Packit 8ea169
    {
Packit 8ea169
        settings_setBlackListedPkgs = parse_list(value);
Packit 8ea169
        remove_map_string_item(settings, "BlackList");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "BlackListedPaths");
Packit 8ea169
    if (value)
Packit 8ea169
    {
Packit 8ea169
        settings_setBlackListedPaths = parse_list(value);
Packit 8ea169
        remove_map_string_item(settings, "BlackListedPaths");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "ProcessUnpackaged");
Packit 8ea169
    if (value)
Packit 8ea169
    {
Packit 8ea169
        settings_bProcessUnpackaged = string_to_bool(value);
Packit 8ea169
        remove_map_string_item(settings, "ProcessUnpackaged");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "Interpreters");
Packit 8ea169
    if (value)
Packit 8ea169
    {
Packit 8ea169
        settings_Interpreters = parse_list(value);
Packit 8ea169
        remove_map_string_item(settings, "Interpreters");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    map_string_iter_t iter;
Packit 8ea169
    const char *name;
Packit 8ea169
    /*char *value; - already declared */
Packit 8ea169
    init_map_string_iter(&iter, settings);
Packit 8ea169
    while (next_map_string_iter(&iter, &name, &value))
Packit 8ea169
    {
Packit 8ea169
        error_msg("Unrecognized variable '%s' in '%s'", name, conf_filename);
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void load_gpg_keys(void)
Packit 8ea169
{
Packit 8ea169
    map_string_t *settings = new_map_string();
Packit 8ea169
    if (!load_abrt_conf_file(GPG_CONF, settings))
Packit 8ea169
    {
Packit 8ea169
        error_msg("Can't load '%s'", GPG_CONF);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    const char *gpg_keys_dir = get_map_string_item_or_NULL(settings, "GPGKeysDir");
Packit 8ea169
    if (gpg_keys_dir != NULL && strcmp(gpg_keys_dir, "") != 0)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Reading gpg keys from '%s'", gpg_keys_dir);
Packit 8ea169
        GHashTable *done_set = g_hash_table_new(g_str_hash, g_str_equal);
Packit 8ea169
        GList *gpg_files = get_file_list(gpg_keys_dir, NULL /* we don't care about the file ext */);
Packit 8ea169
        for (GList *iter = gpg_files; iter; iter = g_list_next(iter))
Packit 8ea169
        {
Packit 8ea169
            const char *key_path = fo_get_fullpath((file_obj_t *)iter->data);
Packit 8ea169
Packit 8ea169
            if (g_hash_table_contains(done_set, key_path))
Packit 8ea169
                continue;
Packit 8ea169
Packit 8ea169
            g_hash_table_insert(done_set, (gpointer)key_path, NULL);
Packit 8ea169
            log_debug("Loading gpg key '%s'", key_path);
Packit 8ea169
            settings_setOpenGPGPublicKeys = g_list_append(settings_setOpenGPGPublicKeys, xstrdup(key_path));
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        g_list_free_full(gpg_files, (GDestroyNotify)free_file_obj);
Packit 8ea169
        g_hash_table_destroy(done_set);
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static int load_conf(const char *conf_filename)
Packit 8ea169
{
Packit 8ea169
    map_string_t *settings = new_map_string();
Packit 8ea169
    if (conf_filename != NULL)
Packit 8ea169
    {
Packit 8ea169
        if (!load_conf_file(conf_filename, settings, false))
Packit 8ea169
            error_msg("Can't open '%s'", conf_filename);
Packit 8ea169
    }
Packit 8ea169
    else
Packit 8ea169
    {
Packit 8ea169
        conf_filename = "abrt-action-save-package-data.conf";
Packit 8ea169
        if (!load_abrt_conf_file(conf_filename, settings))
Packit 8ea169
            error_msg("Can't load '%s'", conf_filename);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    ParseCommon(settings, conf_filename);
Packit 8ea169
    free_map_string(settings);
Packit 8ea169
Packit 8ea169
    load_gpg_keys();
Packit 8ea169
Packit 8ea169
    return 0;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/**
Packit 8ea169
 * Returns the first full path argument in the command line or NULL.
Packit 8ea169
 * Skips options (params of the form "-XXX").
Packit 8ea169
 * Returns malloc'ed string.
Packit 8ea169
 * NB: the cmdline is delimited by (single, not multiple) spaces, not tabs!
Packit 8ea169
 * "abc def\t123" means there are two params: "abc", "def\t123".
Packit 8ea169
 * "abc  def" means there are three params: "abc", "", "def".
Packit 8ea169
 */
Packit 8ea169
static char *get_argv1_if_full_path(const char* cmdline)
Packit 8ea169
{
Packit 8ea169
    const char *argv1 = strchr(cmdline, ' ');
Packit 8ea169
    while (argv1 != NULL)
Packit 8ea169
    {
Packit 8ea169
        /* we found space in cmdline, so it might contain
Packit 8ea169
         * path to some script like:
Packit 8ea169
         * /usr/bin/python [-XXX] /usr/bin/system-control-network
Packit 8ea169
         */
Packit 8ea169
        argv1++; /* skip the space */
Packit 8ea169
        if (*argv1 != '-')
Packit 8ea169
            break;
Packit 8ea169
        /* looks like -XXX in "perl -XXX /usr/bin/script.pl", skipping */
Packit 8ea169
        argv1 = strchr(argv1, ' ');
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* if the string following the space doesn't start
Packit 8ea169
     * with '/', it is not a full path to script
Packit 8ea169
     * and we can't use it to determine the package name
Packit 8ea169
     */
Packit 8ea169
    if (argv1 == NULL || *argv1 != '/')
Packit 8ea169
        return NULL;
Packit 8ea169
Packit 8ea169
    /* good, it has "/foo/bar" form, return it */
Packit 8ea169
    int len = strchrnul(argv1, ' ') - argv1;
Packit 8ea169
    return xstrndup(argv1, len);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static bool is_path_blacklisted(const char *path)
Packit 8ea169
{
Packit 8ea169
    GList *li;
Packit 8ea169
    for (li = settings_setBlackListedPaths; li != NULL; li = g_list_next(li))
Packit 8ea169
    {
Packit 8ea169
        if (fnmatch((char*)li->data, path, /*flags:*/ 0) == 0)
Packit 8ea169
        {
Packit 8ea169
            return true;
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
    return false;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static struct pkg_envra *get_script_name(const char *cmdline, char **executable, const char *chroot)
Packit 8ea169
{
Packit 8ea169
// TODO: we don't verify that python executable is not modified
Packit 8ea169
// or that python package is properly signed
Packit 8ea169
// (see CheckFingerprint/CheckHash below)
Packit 8ea169
    /* Try to find package for the script by looking at argv[1].
Packit 8ea169
     * This will work only if the cmdline contains the whole path.
Packit 8ea169
     * Example: python /usr/bin/system-control-network
Packit 8ea169
     */
Packit 8ea169
    struct pkg_envra *script_pkg = NULL;
Packit 8ea169
    char *script_name = get_argv1_if_full_path(cmdline);
Packit 8ea169
    if (script_name)
Packit 8ea169
    {
Packit 8ea169
        script_pkg = rpm_get_package_nvr(script_name, chroot);
Packit 8ea169
        if (script_pkg)
Packit 8ea169
        {
Packit 8ea169
            /* There is a well-formed script name in argv[1],
Packit 8ea169
             * and it does belong to some package.
Packit 8ea169
             * Replace executable
Packit 8ea169
             * with data pertaining to the script.
Packit 8ea169
             */
Packit 8ea169
            *executable = script_name;
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return script_pkg;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static int SavePackageDescriptionToDebugDump(const char *dump_dir_name, const char *chroot)
Packit 8ea169
{
Packit 8ea169
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
Packit 8ea169
    if (!dd)
Packit 8ea169
        return 1;
Packit 8ea169
Packit 8ea169
    char *type = dd_load_text(dd, FILENAME_TYPE);
Packit 8ea169
    bool kernel_oops = !strcmp(type, "Kerneloops") || !strcmp(type, "vmcore");
Packit 8ea169
    free(type);
Packit 8ea169
Packit 8ea169
    char *cmdline = NULL;
Packit 8ea169
    char *executable = NULL;
Packit 8ea169
    char *rootdir = NULL;
Packit 8ea169
    char *package_short_name = NULL;
Packit 8ea169
    char *fingerprint = NULL;
Packit 8ea169
    struct pkg_envra *pkg_name = NULL;
Packit 8ea169
    char *component = NULL;
Packit 8ea169
    char *kernel = NULL;
Packit 8ea169
    int error = 1;
Packit 8ea169
    /* note: "goto ret" statements below free all the above variables,
Packit 8ea169
     * but they don't dd_close(dd) */
Packit 8ea169
Packit 8ea169
    if (kernel_oops)
Packit 8ea169
    {
Packit 8ea169
        kernel = dd_load_text(dd, FILENAME_KERNEL);
Packit 8ea169
        if (!kernel)
Packit 8ea169
        {
Packit 8ea169
            log_warning("File 'kernel' containing kernel version not "
Packit 8ea169
                "found in current directory");
Packit 8ea169
            goto ret;
Packit 8ea169
        }
Packit 8ea169
        /* Trim trailing white-spaces. */
Packit 8ea169
        strchrnul(kernel, ' ')[0] = '\0';
Packit 8ea169
Packit 8ea169
        log_info("Looking for kernel package");
Packit 8ea169
        executable = xasprintf("/boot/vmlinuz-%s", kernel);
Packit 8ea169
    }
Packit 8ea169
    else
Packit 8ea169
    {
Packit 8ea169
        cmdline = dd_load_text_ext(dd, FILENAME_CMDLINE, DD_FAIL_QUIETLY_ENOENT);
Packit 8ea169
        executable = dd_load_text(dd, FILENAME_EXECUTABLE);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
Packit 8ea169
    /* Do not implicitly query rpm database in process's root dir, if
Packit 8ea169
     * ExploreChroots is disabled. */
Packit 8ea169
    if (g_settings_explorechroots && chroot == NULL)
Packit 8ea169
        chroot = rootdir = dd_load_text_ext(dd, FILENAME_ROOTDIR,
Packit 8ea169
                               DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
Packit 8ea169
Packit 8ea169
    /* Close dd while we query package database. It can take some time,
Packit 8ea169
     * don't want to keep dd locked longer than necessary */
Packit 8ea169
    dd_close(dd);
Packit 8ea169
    dd = NULL;
Packit 8ea169
Packit 8ea169
    /* The check for kernel_oops is there because it could be an unexpected
Packit 8ea169
     * behaviour. If one wants to ignore kernel oops, she/he should disable
Packit 8ea169
     * the corresponding services. */
Packit 8ea169
    if (!kernel_oops && is_path_blacklisted(executable))
Packit 8ea169
    {
Packit 8ea169
        log_warning("Blacklisted executable '%s'", executable);
Packit 8ea169
        goto ret; /* return 1 (failure) */
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    pkg_name = rpm_get_package_nvr(executable, chroot);
Packit 8ea169
    if (!pkg_name)
Packit 8ea169
    {
Packit 8ea169
        if (settings_bProcessUnpackaged)
Packit 8ea169
        {
Packit 8ea169
            log_info("Crash in unpackaged executable '%s', "
Packit 8ea169
                      "proceeding without packaging information", executable);
Packit 8ea169
            goto ret0; /* no error */
Packit 8ea169
        }
Packit 8ea169
        if (kernel_oops)
Packit 8ea169
            log_warning("Can't find kernel package corresponding to '%s'", kernel);
Packit 8ea169
        else
Packit 8ea169
            log_warning("Executable '%s' doesn't belong to any package"
Packit 8ea169
                " and ProcessUnpackaged is set to 'no'", executable);
Packit 8ea169
        goto ret; /* return 1 (failure) */
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (kernel_oops)
Packit 8ea169
        goto skip_interpreter;
Packit 8ea169
Packit 8ea169
    /* Check well-known interpreter names */
Packit 8ea169
    const char *basename = strrchr(executable, '/');
Packit 8ea169
    if (basename)
Packit 8ea169
        basename++;
Packit 8ea169
    else
Packit 8ea169
        basename = executable;
Packit 8ea169
Packit 8ea169
    /* if basename is known interpreter, we want to blame the running script
Packit 8ea169
     * not the interpreter
Packit 8ea169
     */
Packit 8ea169
    if (g_regex_match_simple(DEFAULT_INTERPRETERS_REGEX, basename, G_REGEX_EXTENDED, /*MatchFlags*/0) ||
Packit 8ea169
        g_list_find_custom(settings_Interpreters, basename, (GCompareFunc)g_strcmp0))
Packit 8ea169
    {
Packit 8ea169
        struct pkg_envra *script_pkg = get_script_name(cmdline, &executable, chroot);
Packit 8ea169
        /* executable may have changed, check it again */
Packit 8ea169
        if (is_path_blacklisted(executable))
Packit 8ea169
        {
Packit 8ea169
            log_warning("Blacklisted executable '%s'", executable);
Packit 8ea169
            goto ret; /* return 1 (failure) */
Packit 8ea169
        }
Packit 8ea169
        if (!script_pkg)
Packit 8ea169
        {
Packit 8ea169
            /* Script name is not absolute, or it doesn't
Packit 8ea169
             * belong to any installed package.
Packit 8ea169
             */
Packit 8ea169
            if (!settings_bProcessUnpackaged)
Packit 8ea169
            {
Packit 8ea169
                log_warning("Interpreter crashed, but no packaged script detected: '%s'", cmdline);
Packit 8ea169
                goto ret; /* return 1 (failure) */
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            /* Unpackaged script, but the settings says we want to keep it.
Packit 8ea169
             * BZ plugin wont allow to report this anyway, because component
Packit 8ea169
             * is missing, so there is no reason to mark it as not_reportable.
Packit 8ea169
             * Someone might want to use abrt to report it using ftp.
Packit 8ea169
             */
Packit 8ea169
            goto ret0;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        free_pkg_envra(pkg_name);
Packit 8ea169
        pkg_name = script_pkg;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
skip_interpreter:
Packit 8ea169
    package_short_name = xasprintf("%s", pkg_name->p_name);
Packit 8ea169
    log_info("Package:'%s' short:'%s'", pkg_name->p_nvr, package_short_name);
Packit 8ea169
Packit 8ea169
    /* The check for kernel_oops is there because it could be an unexpected
Packit 8ea169
     * behaviour. If one wants to ignore kernel oops, she/he should disable
Packit 8ea169
     * the corresponding services. */
Packit 8ea169
    if (!kernel_oops && g_list_find_custom(settings_setBlackListedPkgs, package_short_name, (GCompareFunc)g_strcmp0))
Packit 8ea169
    {
Packit 8ea169
        log_warning("Blacklisted package '%s'", package_short_name);
Packit 8ea169
        goto ret; /* return 1 (failure) */
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    fingerprint = rpm_get_fingerprint(package_short_name);
Packit 8ea169
    if (!(fingerprint != NULL && rpm_fingerprint_is_imported(fingerprint))
Packit 8ea169
         && settings_bOpenGPGCheck)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Package '%s' isn't signed with proper key", package_short_name);
Packit 8ea169
        goto ret; /* return 1 (failure) */
Packit 8ea169
        /* We used to also check the integrity of the executable here:
Packit 8ea169
         *  if (!CheckHash(package_short_name.c_str(), executable)) BOOM();
Packit 8ea169
         * Checking the MD5 sum requires to run prelink to "un-prelink" the
Packit 8ea169
         * binaries - this is considered potential security risk so we don't
Packit 8ea169
         * do it now, until we find some non-intrusive way.
Packit 8ea169
         */
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    component = rpm_get_component(executable, chroot);
Packit 8ea169
Packit 8ea169
    dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
Packit 8ea169
    if (!dd)
Packit 8ea169
        goto ret; /* return 1 (failure) */
Packit 8ea169
Packit 8ea169
    if (pkg_name)
Packit 8ea169
    {
Packit 8ea169
        dd_save_text(dd, FILENAME_PACKAGE, pkg_name->p_nvr);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_EPOCH, pkg_name->p_epoch);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_NAME, pkg_name->p_name);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_VERSION, pkg_name->p_version);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_RELEASE, pkg_name->p_release);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_ARCH, pkg_name->p_arch);
Packit 8ea169
        dd_save_text(dd, FILENAME_PKG_VENDOR, pkg_name->p_vendor);
Packit 8ea169
Packit 8ea169
        if (fingerprint)
Packit 8ea169
        {
Packit 8ea169
            /* 16 character + 3 spaces + 1 '\0' + 2 Bytes for errors :) */
Packit 8ea169
            char key_fingerprint[22] = {0};
Packit 8ea169
Packit 8ea169
            /* The condition is just a defense against errors */
Packit 8ea169
            for (size_t i = 0, j = 0; j < sizeof(key_fingerprint) - 2; )
Packit 8ea169
            {
Packit 8ea169
                key_fingerprint[j++] = toupper(fingerprint[i++]);
Packit 8ea169
Packit 8ea169
                if (fingerprint[i] == '\0')
Packit 8ea169
                    break;
Packit 8ea169
Packit 8ea169
                if (!(i & (0x3)))
Packit 8ea169
                    key_fingerprint[j++] = ' ';
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            dd_save_text(dd, FILENAME_PKG_FINGERPRINT, key_fingerprint);
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (component)
Packit 8ea169
        dd_save_text(dd, FILENAME_COMPONENT, component);
Packit 8ea169
Packit 8ea169
 ret0:
Packit 8ea169
    error = 0;
Packit 8ea169
 ret:
Packit 8ea169
    if (dd)
Packit 8ea169
        dd_close(dd);
Packit 8ea169
Packit 8ea169
    free(cmdline);
Packit 8ea169
    free(executable);
Packit 8ea169
    free(rootdir);
Packit 8ea169
    free(package_short_name);
Packit 8ea169
    free_pkg_envra(pkg_name);
Packit 8ea169
    free(component);
Packit 8ea169
    free(fingerprint);
Packit 8ea169
Packit 8ea169
    return error;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int main(int argc, char **argv)
Packit 8ea169
{
Packit 8ea169
    /* I18n */
Packit 8ea169
    setlocale(LC_ALL, "");
Packit 8ea169
#if ENABLE_NLS
Packit 8ea169
    bindtextdomain(PACKAGE, LOCALEDIR);
Packit 8ea169
    textdomain(PACKAGE);
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
    abrt_init(argv);
Packit 8ea169
Packit 8ea169
    const char *dump_dir_name = ".";
Packit 8ea169
    const char *conf_filename = NULL;
Packit 8ea169
    const char *chroot = NULL;
Packit 8ea169
Packit 8ea169
    /* Can't keep these strings/structs static: _() doesn't support that */
Packit 8ea169
    const char *program_usage_string = _(
Packit 8ea169
        "& [-v] [-c CONFFILE] [-r CHROOT] -d DIR\n"
Packit 8ea169
        "\n"
Packit 8ea169
        "Query package database and save package and component name"
Packit 8ea169
    );
Packit 8ea169
    enum {
Packit 8ea169
        OPT_v = 1 << 0,
Packit 8ea169
        OPT_d = 1 << 1,
Packit 8ea169
        OPT_c = 1 << 2,
Packit 8ea169
        OPT_r = 1 << 2,
Packit 8ea169
    };
Packit 8ea169
    /* Keep enum above and order of options below in sync! */
Packit 8ea169
    struct options program_options[] = {
Packit 8ea169
        OPT__VERBOSE(&g_verbose),
Packit 8ea169
        OPT_STRING('d', NULL, &dump_dir_name, "DIR"     , _("Problem directory")),
Packit 8ea169
        OPT_STRING('c', NULL, &conf_filename, "CONFFILE", _("Configuration file")),
Packit 8ea169
        OPT_STRING('r', "chroot", &chroot,    "CHROOT"  , _("Use this directory as RPM root")),
Packit 8ea169
        OPT_END()
Packit 8ea169
    };
Packit 8ea169
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
Packit 8ea169
Packit 8ea169
    export_abrt_envvars(0);
Packit 8ea169
Packit 8ea169
    log_notice("Loading settings");
Packit 8ea169
    if (load_conf(conf_filename) != 0)
Packit 8ea169
        return 1; /* syntax error (logged already by load_conf) */
Packit 8ea169
Packit 8ea169
    log_notice("Initializing rpm library");
Packit 8ea169
    rpm_init();
Packit 8ea169
Packit 8ea169
    GList *li;
Packit 8ea169
    for (li = settings_setOpenGPGPublicKeys; li != NULL; li = g_list_next(li))
Packit 8ea169
    {
Packit 8ea169
        log_notice("Loading GPG key '%s'", (char*)li->data);
Packit 8ea169
        rpm_load_gpgkey((char*)li->data);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    int r = SavePackageDescriptionToDebugDump(dump_dir_name, chroot);
Packit 8ea169
Packit 8ea169
    /* Close RPM database */
Packit 8ea169
    rpm_destroy();
Packit 8ea169
Packit 8ea169
    return r;
Packit 8ea169
}