void free_global_configuration(void)
{
    if (s_global_settings != NULL)
    {
        free_map_string(s_global_settings);
        s_global_settings = NULL;
    }
}
Exemple #2
0
void
ureport_server_config_load_basic_auth(struct ureport_server_config *config,
                                      const char *http_auth_pref)
{
    if (http_auth_pref == NULL)
        return;

    map_string_t *settings = NULL;

    char *tmp_password = NULL;
    char *tmp_username = NULL;
    const char *username = NULL;
    const char *password = NULL;

    if (strcmp(http_auth_pref, "rhts-credentials") == 0)
    {
        settings = new_map_string();

        char *local_conf = xasprintf("%s"USER_HOME_CONFIG_PATH"/rhtsupport.conf", getenv("HOME"));

        if (!load_plugin_conf_file("rhtsupport.conf", settings, /*skip key w/o values:*/ false) &&
            !load_conf_file(local_conf, settings, /*skip key w/o values:*/ false))
            error_msg_and_die("Could not get RHTSupport credentials");
        free(local_conf);

        username = get_map_string_item_or_NULL(settings, "Login");
        password = get_map_string_item_or_NULL(settings, "Password");

        if (config->ur_url == NULL)
            ureport_server_config_set_url(config, xstrdup(RHSM_WEB_SERVICE_URL));
    }
    else
    {
        username = tmp_username = xstrdup(http_auth_pref);
        password = strchr(tmp_username, ':');

        if (password != NULL)
            /* It is "char *", see strchr() few lines above. */
            *((char *)(password++)) = '\0';
    }

    if (password == NULL)
    {
        char *message = xasprintf("Please provide uReport server password for user '%s':", username);
        password = tmp_password = ask_password(message);
        free(message);

        if (strcmp(password, "") == 0)
            error_msg_and_die("Cannot continue without uReport server password!");
    }

    ureport_server_config_set_basic_auth(config, username, password);

    free(tmp_password);
    free(tmp_username);
    free_map_string(settings);
}
Exemple #3
0
bool load_user_settings(const char *application_name)
{
    if (conf_path)
        free(conf_path);
    conf_path = get_conf_path(application_name);

    if (user_settings)
        free_map_string(user_settings);
    user_settings = new_map_string();

    return load_conf_file(conf_path, user_settings, false);
}
Exemple #4
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    map_string_h *settings = new_map_string();
    const char *dump_dir_name = ".";
    GList *conf_file = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [-v] -c CONFFILE -d DIR\n"
        "\n"
        "Reports problem to Bugzilla"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Dump directory")),
        OPT_LIST(  'c', NULL, &conf_file    , "FILE", _("Configuration file (may be given many times)")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    while (conf_file)
    {
        char *fn = (char *)conf_file->data;
        VERB1 log("Loading settings from '%s'", fn);
        load_conf_file(fn, settings, /*skip key w/o values:*/ true);
        VERB3 log("Loaded '%s'", fn);
        conf_file = g_list_remove(conf_file, fn);
    }

    VERB1 log("Initializing XML-RPC library");
    xmlrpc_env env;
    xmlrpc_env_init(&env);
    xmlrpc_client_setup_global_const(&env);
    if (env.fault_occurred)
        error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
    xmlrpc_env_clean(&env);

    report_to_bugzilla(dump_dir_name, settings);

    free_map_string(settings);
    return 0;
}
Exemple #5
0
int load_abrt_conf()
{
    free_abrt_conf_data();

    map_string_t *settings = new_map_string();
    if (!load_abrt_conf_file(ABRT_CONF, settings))
        perror_msg("Can't load '%s'", ABRT_CONF);

    ParseCommon(settings, ABRT_CONF);
    free_map_string(settings);

    return 0;
}
Exemple #6
0
char *abrt_oops_string_filter_regex(void)
{
    map_string_t *settings = new_map_string();

    load_abrt_plugin_conf_file("oops.conf", settings);

    int only_fatal_mce = 1;
    try_get_map_string_item_as_bool(settings, "OnlyFatalMCE", &only_fatal_mce);

    free_map_string(settings);

    if (only_fatal_mce)
        return xstrdup("^Machine .*$");

    return NULL;
}
Exemple #7
0
static void migrate_auto_reporting_to_gsettings(void)
{
#define OPT_NAME "AutoreportingEnabled"
    map_string_t *settings = new_map_string();
    if (!load_app_conf_file(APP_NAME, settings))
        goto finito;

    /* Silently ignore not configured options */
    int sv_logmode = logmode;
    /* but only if we run in silent mode (no -v on command line) */
    logmode = g_verbose == 0 ? 0 : sv_logmode;

    int auto_reporting = 0;
    int configured = try_get_map_string_item_as_bool(settings, OPT_NAME, &auto_reporting);

    logmode = sv_logmode;

    if (!configured)
        goto finito;

    /* Enable the GS option if AutoreportingEnabled is true because the user
     * turned the Autoreporting in abrt-applet in a before GS.
     *
     * Do not disable the GS option if AutoreportingEvent is false because the
     * GS option is false by default, thus disabling would revert the user's
     * decision to  automatically report technical problems.
     */
    if (auto_reporting)
    {
        GSettings *settings = g_settings_new(GS_SCHEMA_ID_PRIVACY);
        g_settings_set_boolean(settings, GS_PRIVACY_OPT_AUTO_REPORTING, TRUE);
        g_object_unref(settings);
    }

    remove_map_string_item(settings, OPT_NAME);
    save_app_conf_file(APP_NAME, settings);

    log("Successfully migrated "APP_NAME":"OPT_NAME" to "GS_SCHEMA_ID_PRIVACY":"GS_PRIVACY_OPT_AUTO_REPORTING);

#undef OPT_NAME
finito:
    free_map_string(settings);
    return;
}
static int load_conf(const char *conf_filename)
{
    map_string_t *settings = new_map_string();
    if (conf_filename != NULL)
    {
        if (!load_conf_file(conf_filename, settings, false))
            error_msg("Can't open '%s'", conf_filename);
    }
    else
    {
        conf_filename = "abrt-action-save-package-data.conf";
        if (!load_abrt_conf_file(conf_filename, settings))
            error_msg("Can't load '%s'", conf_filename);
    }

    ParseCommon(settings, conf_filename);
    free_map_string(settings);

    load_gpg_keys();

    return 0;
}
Exemple #9
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    const char *dump_dir_name = ".";
    const char *conf_file = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [-v] -d DIR [-c CONFFILE]\n"
        "\n"
        "Sends contents of a dump directory DIR via email"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR"     , _("Dump directory")),
        OPT_STRING('c', NULL, &conf_file    , "CONFFILE", _("Config file")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    map_string_h *settings = new_map_string();
    if (conf_file)
        load_conf_file(conf_file, settings, /*skip key w/o values:*/ true);

    create_and_send_email(dump_dir_name, settings);

    free_map_string(settings);
    return 0;
}
static void report_to_kerneloops(
                const char *dump_dir_name,
                map_string_t *settings)
{
    problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
    if (!problem_data)
        xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

    const char *backtrace = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
    if (!backtrace)
        error_msg_and_die("Error sending kernel oops due to missing backtrace");

    const char *env = getenv("KerneloopsReporter_SubmitURL");
    const char *submitURL = (env ? env : get_map_string_item_or_empty(settings, "SubmitURL"));
    if (!submitURL[0])
        submitURL = "http://oops.kernel.org/submitoops.php";

    log(_("Submitting oops report to %s"), submitURL);

    CURLcode ret = http_post_to_kerneloops_site(submitURL, backtrace);
    if (ret != CURLE_OK)
        error_msg_and_die("Kernel oops has not been sent due to %s", curl_easy_strerror(ret));

    problem_data_free(problem_data);

    /* Server replies with:
     * 200 thank you for submitting the kernel oops information
     * RemoteIP: 34192fd15e34bf60fac6a5f01bba04ddbd3f0558
     * - no URL or bug ID apparently...
     */
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (dd)
    {
        report_result_t rr = { .label = (char *)"kerneloops" };
        rr.url = (char *)submitURL;
        add_reported_to_entry(dd, &rr);
        dd_close(dd);
    }

    log("Kernel oops report was uploaded");
}

int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    map_string_t *settings = new_map_string();
    const char *dump_dir_name = ".";
    GList *conf_file = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-v] [-c CONFFILE]... -d DIR\n"
        "\n"
        "Reports kernel oops to kerneloops.org (or similar) site.\n"
        "\n"
        "Files with names listed in $EXCLUDE_FROM_REPORT are not included\n"
        "into the tarball.\n"
        "\n"
        "CONFFILE lines should have 'PARAM = VALUE' format.\n"
        "Recognized string parameter: SubmitURL.\n"
        "Parameter can be overridden via $KerneloopsReporter_SubmitURL."
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Problem directory")),
        OPT_LIST(  'c', NULL, &conf_file    , "FILE", _("Configuration file")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    while (conf_file)
    {
        char *fn = (char *)conf_file->data;
        log_notice("Loading settings from '%s'", fn);
        load_conf_file(fn, settings, /*skip key w/o values:*/ false);
        log_debug("Loaded '%s'", fn);
        conf_file = g_list_remove(conf_file, fn);
    }

    report_to_kerneloops(dump_dir_name, settings);

    free_map_string(settings);
    return 0;
}
Exemple #11
0
static void load_config_files(const char *dir_path)
{
    DIR *dir;
    struct dirent *dent;

    /* Load .conf files */
    dir = opendir(dir_path);
    if (!dir)
        return;
    while ((dent = readdir(dir)) != NULL)
    {
        char *ext = strrchr(dent->d_name, '.');
        if (!ext)
            continue;
        if (strcmp(ext + 1, "conf") != 0)
            continue;

        char *fullname = concat_path_file(dir_path, dent->d_name);

        *ext = '\0';
        event_config_t *event_config = get_event_config(dent->d_name);
        bool new_config = (!event_config);
        if (new_config)
            event_config = new_event_config();

        map_string_h *keys_and_values = new_map_string();

        load_conf_file(fullname, keys_and_values, /*skipKeysWithoutValue:*/ false);
        free(fullname);

        /* Insert or replace every key/value from keys_and_values to event_config->option */
        GHashTableIter iter;
        char *name;
        char *value;
        g_hash_table_iter_init(&iter, keys_and_values);
        while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
        {
            event_option_t *opt;
            GList *elem = g_list_find_custom(event_config->options, name,
                                            cmp_event_option_name_with_string);
            if (elem)
            {
                opt = elem->data;
                // log("conf: replacing '%s' value:'%s'->'%s'", name, opt->value, value);
                free(opt->eo_value);
            }
            else
            {
                // log("conf: new value %s='%s'", name, value);
                opt = new_event_option();
                opt->eo_name = xstrdup(name);
            }
            opt->eo_value = xstrdup(value);
            if (!elem)
                event_config->options = g_list_append(event_config->options, opt);
        }

        free_map_string(keys_and_values);

        if (new_config)
            g_hash_table_replace(g_event_config_list, xstrdup(dent->d_name), event_config);
    }
    closedir(dir);
}
Exemple #12
0
int main(int argc, char **argv)
{
    abrt_init(argv);
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_g = 1 << 2,
        OPT_b = 1 << 3,
        OPT_u = 1 << 4,
        OPT_r = 1 << 5,
    };

    const char *bugs = NULL, *release = NULL, *dump_dir_path = ".";
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT__DUMP_DIR(&dump_dir_path),
        OPT_GROUP(""),
        OPT_STRING('b', "bugs", &bugs, "ID1[,ID2,...]" , _("List of bug ids")),
        OPT_STRING('u', "url", &bodhi_url, "URL", _("Specify a bodhi server url")),
        OPT_OPTSTRING('r', "release", &release, "RELEASE", _("Specify a release")),
        OPT_END()
    };

    const char *program_usage_string = _(
        "& [-v] [-r[RELEASE]] (-b ID1[,ID2,...] | PKG-NAME) [PKG-NAME]... \n"
        "\n"
        "Search for updates on bodhi server"
    );

    unsigned opts =  parse_opts(argc, argv, program_options, program_usage_string);

    if (!bugs && !argv[optind])
        show_usage_and_die(program_usage_string, program_options);

    struct strbuf *query = strbuf_new();
    if (bugs)
        query = strbuf_append_strf(query, "bugs=%s&", bugs);

    if (opts & OPT_r)
    {
        if (release)
        {
            query = strbuf_append_strf(query, "release=%s&", release);
        }
        else
        {
            struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
            if (!dd)
                xfunc_die();

            problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
            dd_close(dd);
            if (!problem_data)
                xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

            char *product, *version;
            map_string_t *osinfo = new_map_string();
            problem_data_get_osinfo(problem_data, osinfo);
            parse_osinfo_for_rhts(osinfo, &product, &version);
            query = strbuf_append_strf(query, "release=f%s&", version);
            free(product);
            free(version);
            free_map_string(osinfo);
        }
    }

    if (argv[optind])
    {
        char *escaped = g_uri_escape_string(argv[optind], NULL, 0);
        query = strbuf_append_strf(query, "package=%s&", escaped);
        free(escaped);
    }

    if (query->buf[query->len - 1] == '&')
        query->buf[query->len - 1] = '\0';

    log(_("Searching for updates"));
    GHashTable *update_hash_tbl = bodhi_query_list(query->buf, release);
    strbuf_free(query);

    if (!update_hash_tbl || !g_hash_table_size(update_hash_tbl))
    {
        log(_("No updates for this package found"));
        /*if (update_hash_tbl) g_hash_table_unref(update_hash_tbl);*/
        return 0;
    }

    GHashTableIter iter;
    char *name;
    struct bodhi *b;
    struct strbuf *q = strbuf_new();
    g_hash_table_iter_init(&iter, update_hash_tbl);
    while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &b))
    {
        char *installed_pkg_nvr = rpm_get_nvr_by_pkg_name(name);
        if (installed_pkg_nvr && rpmvercmp(installed_pkg_nvr, b->nvr) >= 0)
        {
            log_info("Update %s is older or same as local version %s, skipping", b->nvr, installed_pkg_nvr);
            free(installed_pkg_nvr);
            continue;
        }
        free(installed_pkg_nvr);

        strbuf_append_strf(q, " %s", b->nvr);
    }

    /*g_hash_table_unref(update_hash_tbl);*/

    if (!q->len)
    {
        /*strbuf_free(q);*/
        log(_("Local version of the package is newer than available updates"));
        return 0;
    }

    /* Message is split into text and command in order to make
     * translator's job easier
     */

    /* We suggest the command which is most likely to exist on user's system,
     * and which is familiar to the largest population of users.
     * There are other tools (pkcon et al) which might be somewhat more
     * convenient (for example, they might be usable from non-root), but they
     * might be not present on the system, may evolve or be superseded,
     * while yum is unlikely to do so.
     */
    strbuf_prepend_str(q, "yum update --enablerepo=fedora --enablerepo=updates-testing");

    char *msg = xasprintf(_("An update exists which might fix your problem. "
                "You can install it by running: %s. "
                "Do you want to continue with reporting the bug?"),
                q->buf
    );
    /*strbuf_free(q);*/

    return !ask_yes_no(msg);
}
Exemple #13
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    const char *dump_dir_name = ".";
    const char *conf_file = CONF_DIR"/plugins/upload.conf";
    const char *url = NULL;
    const char *ssh_public_key = NULL;
    const char *ssh_private_key = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-v] -d DIR [-c CONFFILE] [-u URL] [-b FILE] [-r FILE]\n"
        "\n"
        "Uploads compressed tarball of problem directory DIR to URL.\n"
        "If URL is not specified, creates tarball in "LARGE_DATA_TMP_DIR" and exits.\n"
        "\n"
        "URL should have form 'protocol://[user[:pass]@]host/dir/[file.tar.gz]'\n"
        "where protocol can be http(s), ftp, scp, or file.\n"
        "File protocol can't have user and host parts: 'file:///dir/[file.tar.gz].'\n"
        "If URL ends with a slash, the archive name will be generated and appended\n"
        "to URL; otherwise, URL will be used as full file name.\n"
        "\n"
        "Files with names listed in $EXCLUDE_FROM_REPORT are not included\n"
        "into the tarball.\n"
        "\n"
        "\n""If not specified, CONFFILE defaults to "CONF_DIR"/plugins/upload.conf"
        "\n""Its lines should have 'PARAM = VALUE' format."
        "Recognized string parameter: URL.\n"
        "Parameter can be overridden via $Upload_URL."
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
        OPT_u = 1 << 3,
        OPT_b = 1 << 4,
        OPT_r = 1 << 5,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR"     , _("Problem directory")),
        OPT_STRING('c', NULL, &conf_file    , "CONFFILE", _("Config file")),
        OPT_STRING('u', NULL, &url          , "URL"     , _("Base URL to upload to")),
        OPT_STRING('b', "pubkey",  &ssh_public_key , "FILE" , _("SSH public key file")),
        OPT_STRING('r', "key",     &ssh_private_key, "FILE" , _("SSH private key file")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    // 2015-10-16 (jfilak):
    //   It looks like there is no demand for encryption and other archive
    //   types. Configurable ExcludeFiles sounds reasonable to me, I am
    //   not sure about globbing though.
    //
    //Encrypt = yes
    //ArchiveType = .tar.bz2
    //
    //TODO:
    //ExcludeFiles = foo,bar*,b*z

    map_string_t *settings = new_map_string();
    if (conf_file)
        load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);

    char *input_url = NULL;
    const char *conf_url = getenv("Upload_URL");
    if (!conf_url || conf_url[0] == '\0')
        conf_url = url;
    if (!conf_url || conf_url[0] == '\0')
        conf_url = get_map_string_item_or_empty(settings, "URL");
    if (!conf_url || conf_url[0] == '\0')
        conf_url = input_url = ask_url(_("Please enter a URL (scp, ftp, etc.) where the problem data is to be exported:"));

    set_map_string_item_from_string(settings, "UploadUsername", getenv("Upload_Username"));
    set_map_string_item_from_string(settings, "UploadPassword", getenv("Upload_Password"));

    /* set SSH keys */
    if (ssh_public_key)
        set_map_string_item_from_string(settings, "SSHPublicKey", ssh_public_key);
    else if (getenv("Upload_SSHPublicKey") != NULL)
        set_map_string_item_from_string(settings, "SSHPublicKey", getenv("Upload_SSHPublicKey"));

    if (ssh_private_key)
        set_map_string_item_from_string(settings, "SSHPrivateKey", ssh_private_key);
    else if (getenv("Upload_SSHPrivateKey") != NULL)
        set_map_string_item_from_string(settings, "SSHPrivateKey", getenv("Upload_SSHPrivateKey"));

    char *remote_name = NULL;
    const int result = create_and_upload_archive(dump_dir_name, conf_url, settings, &remote_name);
    if (result != 0)
        goto finito;

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (dd)
    {
        report_result_t *result;

        result = report_result_new_with_label_from_env("upload");

        report_result_set_url(result, remote_name);

        add_reported_to_entry(dd, result);

        report_result_free(result);

        dd_close(dd);
    }
    free(remote_name);

finito:
    free(input_url);
    free_map_string(settings);
    return result;
}
int main(int argc, char *argv[])
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */

    const char *program_usage_string_template = _(
        "& [-vsoxtf] [-e]/[-c CURSOR] [-d DIR]/[-D]\n"
        "\n"
        "Extract Xorg crash from systemd-journal\n"
        "\n"
        "-c and -e options conflicts because both specifies the first read message.\n"
        "\n"
        "-e is useful only for -f because the following of journal starts by reading \n"
        "the entire journal if the last seen possition is not available.\n"
        "\n"
        "The last seen position is saved in %s\n"
        "\n"
        "Journal filter is required parameter and must be specified either by parameter\n"
        "-j or in %s conf file.\n"
    );

    char program_usage_string[strlen(program_usage_string_template)
                            + strlen(ABRT_JOURNAL_XORG_WATCH_STATE_FILE)
                            + strlen(XORG_CONF_PATH)];
    sprintf(program_usage_string, program_usage_string_template,
            ABRT_JOURNAL_XORG_WATCH_STATE_FILE, XORG_CONF_PATH);

    enum {
        OPT_v = 1 << 0,
        OPT_s = 1 << 1,
        OPT_o = 1 << 2,
        OPT_d = 1 << 3,
        OPT_D = 1 << 4,
        OPT_x = 1 << 5,
        OPT_t = 1 << 6,
        OPT_c = 1 << 7,
        OPT_e = 1 << 8,
        OPT_f = 1 << 9,
        OPT_a = 1 << 10,
        OPT_J = 1 << 11,
        OPT_j = 1 << 12,
    };

    char *cursor = NULL;
    char *dump_location = NULL;
    char *journal_dir = NULL;
    GList *journal_filters = NULL;

    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_BOOL(  's', NULL, NULL, _("Log to syslog")),
        OPT_BOOL(  'o', NULL, NULL, _("Print found crashes on standard output")),
        OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every crash found")),
        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
        OPT_BOOL(  't', NULL, NULL, _("Throttle problem directory creation to 1 per second")),
        OPT_STRING('c', NULL, &cursor, "CURSOR", _("Start reading systemd-journal from the CURSOR position")),
        OPT_BOOL(  'e', NULL, NULL, _("Start reading systemd-journal from the end")),
        OPT_BOOL(  'f', NULL, NULL, _("Follow systemd-journal from the last seen position (if available)")),
        OPT_BOOL(  'a', NULL, NULL, _("Read journal files from all machines")),
        OPT_STRING('J', NULL, &journal_dir,  "PATH", _("Read all journal files from directory at PATH")),
        OPT_LIST(  'j', NULL, &journal_filters,  "FILTER", _("Journal filter e.g. '_COMM=gdm-x-session' (may be given many times)")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    msg_prefix = g_progname;
    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
    {
        logmode = LOGMODE_JOURNAL;
    }

    if ((opts & OPT_c) && (opts & OPT_e))
        error_msg_and_die(_("You need to specify either -c CURSOR or -e"));

    if (opts & OPT_D)
    {
        if (opts & OPT_d)
            show_usage_and_die(program_usage_string, program_options);
        load_abrt_conf();
        dump_location = g_settings_dump_location;
        g_settings_dump_location = NULL;
        free_abrt_conf_data();
    }

    int xorg_utils_flags = 0;
    if ((opts & OPT_x))
        xorg_utils_flags |= ABRT_XORG_WORLD_READABLE;

    if ((opts & OPT_t))
        xorg_utils_flags |= ABRT_XORG_THROTTLE_CREATION;

    if ((opts & OPT_o))
        xorg_utils_flags |= ABRT_XORG_PRINT_STDOUT;

    /* get journal filters */
    const char *const env_journal_filter = getenv("ABRT_DUMP_JOURNAL_XORG_DEBUG_FILTER");
    bool free_filter_list_data = false;
    GList *xorg_journal_filter = NULL;
    if (env_journal_filter != NULL)
    {
        xorg_journal_filter = g_list_append(xorg_journal_filter, (gpointer)env_journal_filter);
        log_debug("Using journal filter from environment variable");
    }
    else if (journal_filters != NULL)
    {
        xorg_journal_filter = journal_filters;
        log_debug("Using journal filter passed by parameter -j");
    }
    else
    {
        map_string_t *settings = new_map_string();
        log_notice("Loading settings from '%s'", XORG_CONF);
        load_abrt_plugin_conf_file(XORG_CONF, settings);
        log_debug("Loaded '%s'", XORG_CONF);
        const char *conf_journal_filters = get_map_string_item_or_NULL(settings, "JournalFilters");
        xorg_journal_filter = parse_list(conf_journal_filters);
        /* list data will be free by g_list_free_full */
        free_filter_list_data = true;
        free_map_string(settings);
        if (xorg_journal_filter)
            log_debug("Using journal filter from conf file %s", XORG_CONF);
    }

    if (xorg_journal_filter == NULL)
        error_msg_and_die(_("Journal filter must be specified either by parameter -j or stored in /etc/abrt/plugins/xorg.conf file"));

    abrt_journal_t *journal = NULL;
    if ((opts & OPT_J))
    {
        log_debug("Using journal files from directory '%s'", journal_dir);

        if (abrt_journal_open_directory(&journal, journal_dir))
            error_msg_and_die(_("Cannot initialize systemd-journal in directory '%s'"), journal_dir);
    }
    else
    {
        if (((opts & OPT_a) ? abrt_journal_new_merged : abrt_journal_new)(&journal))
            error_msg_and_die(_("Cannot open systemd-journal"));
    }

    if (abrt_journal_set_journal_filter(journal, xorg_journal_filter) < 0)
        error_msg_and_die(_("Cannot filter systemd-journal to Xorg data only"));

    /* free filter list */
    if (free_filter_list_data)
        g_list_free_full(xorg_journal_filter, free);
    else
        g_list_free(xorg_journal_filter);

    if ((opts & OPT_e) && abrt_journal_seek_tail(journal) < 0)
        error_msg_and_die(_("Cannot seek to the end of journal"));

    if ((opts & OPT_f))
    {
        if (!cursor)
            abrt_journal_restore_position(journal, ABRT_JOURNAL_XORG_WATCH_STATE_FILE);
        else if(abrt_journal_set_cursor(journal, cursor))
            error_msg_and_die(_("Failed to start watch from cursor '%s'"), cursor);

        watch_journald(journal, dump_location, xorg_utils_flags);

        abrt_journal_save_current_position(journal, ABRT_JOURNAL_XORG_WATCH_STATE_FILE);
    }
    else
    {
        if (cursor && abrt_journal_set_cursor(journal, cursor))
            error_msg_and_die(_("Failed to set systemd-journal cursor '%s'"), cursor);

        /* Compatibility hack, a watch's callback gets the journal already moved
         * to a next message.*/
        abrt_journal_next(journal);

        GList *crashes = abrt_journal_extract_xorg_crashes(journal);
        abrt_xorg_process_list_of_crashes(crashes, dump_location, xorg_utils_flags);
        g_list_free_full(crashes, (GDestroyNotify)xorg_crash_info_free);
    }

    abrt_journal_free(journal);

    return EXIT_SUCCESS;
}
Exemple #15
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\n& [-vbf] [-g GROUP-NAME]... [-c CONFFILE]... [-F FMTFILE] [-A FMTFILE2] -d DIR"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] FILE..."
        "\nor:"
        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] -w"
        "\nor:"
        "\n& [-v] [-c CONFFILE]... -h DUPHASH"
        "\n"
        "\nReports problem to Bugzilla."
        "\n"
        "\nThe tool reads DIR. Then it logs in to Bugzilla and tries to find a bug"
        "\nwith the same abrt_hash:HEXSTRING in 'Whiteboard'."
        "\n"
        "\nIf such bug is not found, then a new bug is created. Elements of DIR"
        "\nare stored in the bug as part of bug description or as attachments,"
        "\ndepending on their type and size."
        "\n"
        "\nOtherwise, if such bug is found and it is marked as CLOSED DUPLICATE,"
        "\nthe tool follows the chain of duplicates until it finds a non-DUPLICATE bug."
        "\nThe tool adds a new comment to found bug."
        "\n"
        "\nThe URL to new or modified bug is printed to stdout and recorded in"
        "\n'reported_to' element."
        "\n"
        "\nOption -t uploads FILEs to the already created bug on Bugzilla site."
        "\nThe bug ID is retrieved from directory specified by -d DIR."
        "\nIf problem data in DIR was never reported to Bugzilla, upload will fail."
        "\n"
        "\nOption -tID uploads FILEs to the bug with specified ID on Bugzilla site."
        "\n-d DIR is ignored."
        "\n"
        "\nOption -w adds bugzilla user to bug's CC list."
        "\n"
        "\nIf not specified, CONFFILE defaults to "CONF_DIR"/plugins/bugzilla.conf"
        "\nIts lines should have 'PARAM = VALUE' format."
        "\nRecognized string parameters: BugzillaURL, Login, Password, OSRelease."
        "\nRecognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify."
        "\nParameters can be overridden via $Bugzilla_PARAM environment variables."
        "\n"
        "\nFMTFILE and FMTFILE2 default to "CONF_DIR"/plugins/bugzilla_format.conf"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
        OPT_F = 1 << 3,
        OPT_A = 1 << 4,
        OPT_t = 1 << 5,
        OPT_b = 1 << 6,
        OPT_f = 1 << 7,
        OPT_w = 1 << 8,
        OPT_h = 1 << 9,
        OPT_g = 1 << 10,
        OPT_D = 1 << 11,
    };
    const char *dump_dir_name = ".";
    GList *conf_file = NULL;
    const char *fmt_file = CONF_DIR"/plugins/bugzilla_format.conf";
    const char *fmt_file2 = fmt_file;
    char *abrt_hash = NULL;
    char *ticket_no = NULL;
    char *debug_str = NULL;
    GList *group = NULL;
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING(   'd', NULL, &dump_dir_name , "DIR"    , _("Problem directory")),
        OPT_LIST(     'c', NULL, &conf_file     , "FILE"   , _("Configuration file (may be given many times)")),
        OPT_STRING(   'F', NULL, &fmt_file      , "FILE"   , _("Formatting file for initial comment")),
        OPT_STRING(   'A', NULL, &fmt_file2     , "FILE"   , _("Formatting file for duplicates")),
        OPT_OPTSTRING('t', "ticket", &ticket_no , "ID"     , _("Attach FILEs [to bug with this ID]")),
        OPT_BOOL(     'b', NULL, NULL,                       _("When creating bug, attach binary files too")),
        OPT_BOOL(     'f', NULL, NULL,                       _("Force reporting even if this problem is already reported")),
        OPT_BOOL(     'w', NULL, NULL,                       _("Add bugzilla user to CC list [of bug with this ID]")),
        OPT_STRING(   'h', "duphash", &abrt_hash, "DUPHASH", _("Print BUG_ID which has given DUPHASH")),
        OPT_LIST(     'g', "group", &group      , "GROUP"  , _("Restrict access to this group only")),
        OPT_OPTSTRING('D', "debug", &debug_str  , "STR"    , _("Debug")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
    argv += optind;

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    struct bugzilla_struct rhbz = { 0 };
    {
        if (!conf_file)
            conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/bugzilla.conf");
        while (conf_file)
        {
            char *fn = (char *)conf_file->data;
            VERB1 log("Loading settings from '%s'", fn);
            load_conf_file(fn, settings, /*skip key w/o values:*/ false);
            VERB3 log("Loaded '%s'", fn);
            conf_file = g_list_delete_link(conf_file, conf_file);
        }
        set_settings(&rhbz, settings);
        /* WRONG! set_settings() does not copy the strings, it merely sets up pointers
         * to settings[] dictionary:
         */
        /*free_map_string(settings);*/
    }

    VERB1 log("Initializing XML-RPC library");
    xmlrpc_env env;
    xmlrpc_env_init(&env);
    xmlrpc_client_setup_global_const(&env);
    if (env.fault_occurred)
        abrt_xmlrpc_die(&env);
    xmlrpc_env_clean(&env);

    struct abrt_xmlrpc *client;
    client = abrt_xmlrpc_new_client(rhbz.b_bugzilla_xmlrpc, rhbz.b_ssl_verify);
    unsigned rhbz_ver = rhbz_version(client);

    if (abrt_hash)
    {
        log(_("Looking for similar problems in bugzilla"));
        char *hash;
        if (prefixcmp(abrt_hash, "abrt_hash:"))
            hash = xasprintf("abrt_hash:%s", abrt_hash);
        else
            hash = xstrdup(abrt_hash);

        /* it's Fedora specific */
        xmlrpc_value *all_bugs = rhbz_search_duphash(client,
                                /*product:*/ "Fedora",
                                /*version:*/ NULL,
                                /*component:*/ NULL,
                                hash);
        free(hash);
        unsigned all_bugs_size = rhbz_array_size(all_bugs);
        if (all_bugs_size > 0)
        {
            int bug_id = rhbz_get_bug_id_from_array0(all_bugs, rhbz_ver);
            printf("%i\n", bug_id);
        }

        return EXIT_SUCCESS;
    }

    if (rhbz.b_login[0] == '\0')
    {
        free(rhbz.b_login);
        rhbz.b_login = ask_bz_login(_("Login is not provided by configuration. Please enter your BZ login:"******"Password is not provided by configuration. Please enter the password for '%s':"), rhbz.b_login);
        rhbz.b_password = ask_bz_password(question);
        free(question);
    }

    if (opts & OPT_t)
    {
        if ((!argv[0] && !(opts & OPT_w)) || (argv[0] && (opts & OPT_w)))
            show_usage_and_die(program_usage_string, program_options);

        if (!ticket_no)
        {
            struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
            if (!dd)
                xfunc_die();
            report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
            dd_close(dd);

            if (!reported_to || !reported_to->url)
                error_msg_and_die(_("Can't get Bugzilla ID because this problem has not yet been reported to Bugzilla."));

            char *url = reported_to->url;
            reported_to->url = NULL;
            free_report_result(reported_to);

            if (prefixcmp(url, rhbz.b_bugzilla_url) != 0)
                error_msg_and_die(_("This problem has been reported to Bugzilla '%s' which differs from the configured Bugzilla '%s'."), url, rhbz.b_bugzilla_url);

            ticket_no = strrchr(url, '=');
            if (!ticket_no)
                error_msg_and_die(_("Malformed url to Bugzilla '%s'."), url);

            /* won't ever call free on it - it simplifies the code a lot */
            ticket_no = xstrdup(ticket_no + 1);
            log(_("Using Bugzilla ID '%s'"), ticket_no);
        }

        login(client, &rhbz);

        if (opts & OPT_w)
            rhbz_mail_to_cc(client, xatoi_positive(ticket_no), rhbz.b_login, /* require mail notify */ 0);
        else
        {   /* Attach files to existing BZ */
            while (*argv)
            {
                const char *filename = *argv++;
                VERB1 log("Attaching file '%s' to bug %s", filename, ticket_no);

                int fd = open(filename, O_RDONLY);
                if (fd < 0)
                {
                    perror_msg("Can't open '%s'", filename);
                    continue;
                }

                struct stat st;
                if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode))
                {
                    error_msg("'%s': not a regular file", filename);
                    close(fd);
                    continue;
                }

                rhbz_attach_fd(client, ticket_no, filename, fd, /*flags*/ 0);
                close(fd);
            }
        }

        log(_("Logging out"));
        rhbz_logout(client);

#if 0  /* enable if you search for leaks (valgrind etc) */
        abrt_xmlrpc_free_client(client);
#endif
        return 0;
    }

    /* Create new bug in Bugzilla */

    if (!(opts & OPT_f))
    {
        struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
        if (!dd)
            xfunc_die();
        report_result_t *reported_to = find_in_reported_to(dd, "Bugzilla:");
        dd_close(dd);

        if (reported_to && reported_to->url)
        {
            char *msg = xasprintf("This problem was already reported to Bugzilla (see '%s')."
                            " Do you still want to create a new bug?",
                            reported_to->url);
            int yes = ask_yes_no(msg);
            free(msg);
            if (!yes)
                return 0;
        }
        free_report_result(reported_to);
    }

    problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
    if (!problem_data)
        xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */

    const char *component = problem_data_get_content_or_die(problem_data, FILENAME_COMPONENT);
    const char *duphash   = problem_data_get_content_or_NULL(problem_data, FILENAME_DUPHASH);
//COMPAT, remove after 2.1 release
    if (!duphash) duphash = problem_data_get_content_or_die(problem_data, "global_uuid");

    if (!rhbz.b_product || !*rhbz.b_product) /* if not overridden or empty... */
    {
        free(rhbz.b_product);
        free(rhbz.b_product_version);
        map_string_t *osinfo = new_map_string();
        problem_data_get_osinfo(problem_data, osinfo);
        parse_osinfo_for_bz(osinfo, &rhbz.b_product, &rhbz.b_product_version);
        free_map_string(osinfo);

        if (!rhbz.b_product)
            error_msg_and_die(_("Can't determine Bugzilla Product from problem data."));
    }

    if (opts & OPT_D)
    {
        GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);
        struct strbuf *bzcomment_buf = strbuf_new();
        generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
        char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
        char *summary = create_summary_string(problem_data, comment_fmt_spec);
        printf("summary: %s\n"
                "\n"
                "%s"
                , summary, bzcomment
        );
        free(bzcomment);
        free(summary);
        exit(0);
    }

    login(client, &rhbz);


    int bug_id = 0;

    /* If REMOTE_RESULT contains "DUPLICATE 12345", we consider it a dup of 12345
     * and won't search on bz server.
     */
    char *remote_result;
    remote_result = problem_data_get_content_or_NULL(problem_data, FILENAME_REMOTE_RESULT);
    if (remote_result)
    {
        char *cmd = strtok(remote_result, " \n");
        char *id = strtok(NULL, " \n");

        if (!prefixcmp(cmd, "DUPLICATE"))
        {
            errno = 0;
            char *e;
            bug_id = strtoul(id, &e, 10);
            if (errno || id == e || *e != '\0' || bug_id > INT_MAX)
            {
                /* error / no digits / illegal trailing chars / too big a number */
                bug_id = 0;
            }
        }
    }

    struct bug_info *bz = NULL;
    if (!bug_id)
    {
        log(_("Checking for duplicates"));

        int existing_id = -1;
        int crossver_id = -1;
        {
            /* Figure out whether we want to match component
             * when doing dup search.
             */
            const char *component_substitute = is_in_comma_separated_list(component, rhbz.b_DontMatchComponents) ? NULL : component;

            /* We don't do dup detection across versions (see below why),
             * but we do add a note if cross-version potential dup exists.
             * For that, we search for cross version dups first:
             */
            xmlrpc_value *crossver_bugs = rhbz_search_duphash(client, rhbz.b_product, /*version:*/ NULL,
                            component_substitute, duphash);
            unsigned crossver_bugs_count = rhbz_array_size(crossver_bugs);
            VERB3 log("Bugzilla has %i reports with duphash '%s' including cross-version ones",
                    crossver_bugs_count, duphash);
            if (crossver_bugs_count > 0)
                crossver_id = rhbz_get_bug_id_from_array0(crossver_bugs, rhbz_ver);
            xmlrpc_DECREF(crossver_bugs);

            if (crossver_bugs_count > 0)
            {
                /* In dup detection we require match in product *and version*.
                 * Otherwise we sometimes have bugs in e.g. Fedora 17
                 * considered to be dups of Fedora 16 bugs.
                 * Imagine that F16 is "end-of-lifed" - allowing cross-version
                 * match will make all newly detected crashes DUPed
                 * to a bug in a dead release.
                 */
                xmlrpc_value *dup_bugs = rhbz_search_duphash(client, rhbz.b_product,
                                rhbz.b_product_version, component_substitute, duphash);
                unsigned dup_bugs_count = rhbz_array_size(dup_bugs);
                VERB3 log("Bugzilla has %i reports with duphash '%s'",
                        dup_bugs_count, duphash);
                if (dup_bugs_count > 0)
                    existing_id = rhbz_get_bug_id_from_array0(dup_bugs, rhbz_ver);
                xmlrpc_DECREF(dup_bugs);
            }
        }

        if (existing_id < 0)
        {
            /* Create new bug */
            log(_("Creating a new bug"));

            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);

            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            if (crossver_id >= 0)
                strbuf_append_strf(bzcomment_buf, "\nPotential duplicate: bug %u\n", crossver_id);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
            char *summary = create_summary_string(problem_data, comment_fmt_spec);
            int new_id = rhbz_new_bug(client, problem_data, rhbz.b_product, rhbz.b_product_version,
                    summary, bzcomment,
                    group
            );
            free(bzcomment);
            free(summary);

            if (new_id == -1)
            {
                error_msg_and_die(_("Failed to create a new bug."));
            }

            log(_("Adding attachments to bug %i"), new_id);
            char new_id_str[sizeof(int)*3 + 2];
            sprintf(new_id_str, "%i", new_id);

            attach_files(client, new_id_str, problem_data, comment_fmt_spec);

//TODO: free_comment_fmt_spec(comment_fmt_spec);

            bz = new_bug_info();
            bz->bi_status = xstrdup("NEW");
            bz->bi_id = new_id;
            goto log_out;
        }

        bug_id = existing_id;
    }

    bz = rhbz_bug_info(client, bug_id);

    log(_("Bug is already reported: %i"), bz->bi_id);

    /* Follow duplicates */
    if ((strcmp(bz->bi_status, "CLOSED") == 0)
     && (strcmp(bz->bi_resolution, "DUPLICATE") == 0)
    ) {
        struct bug_info *origin;
        origin = rhbz_find_origin_bug_closed_duplicate(client, bz);
        if (origin)
        {
            free_bug_info(bz);
            bz = origin;
        }
    }

    if (strcmp(bz->bi_status, "CLOSED") != 0)
    {
        /* Add user's login to CC if not there already */
        if (strcmp(bz->bi_reporter, rhbz.b_login) != 0
         && !g_list_find_custom(bz->bi_cc_list, rhbz.b_login, (GCompareFunc)g_strcmp0)
        ) {
            log(_("Adding %s to CC list"), rhbz.b_login);
            rhbz_mail_to_cc(client, bz->bi_id, rhbz.b_login, RHBZ_NOMAIL_NOTIFY);
        }

        /* Add comment and bt */
        const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
        if (comment && comment[0])
        {
            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file2);
            struct strbuf *bzcomment_buf = strbuf_new();
            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
//TODO: free_comment_fmt_spec(comment_fmt_spec);

            int dup_comment = is_comment_dup(bz->bi_comments, bzcomment);
            if (!dup_comment)
            {
                log(_("Adding new comment to bug %d"), bz->bi_id);
                rhbz_add_comment(client, bz->bi_id, bzcomment, 0);
                free(bzcomment);

                const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
                unsigned rating = 0;
                const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
                /* python doesn't have rating file */
                if (rating_str)
                    rating = xatou(rating_str);
                if (bt && rating > bz->bi_best_bt_rating)
                {
                    char bug_id_str[sizeof(int)*3 + 2];
                    sprintf(bug_id_str, "%i", bz->bi_id);
                    log(_("Attaching better backtrace"));
                    rhbz_attach_blob(client, bug_id_str, FILENAME_BACKTRACE, bt, strlen(bt),
                                     RHBZ_NOMAIL_NOTIFY);
                }
            }
            else
            {
                free(bzcomment);
                log(_("Found the same comment in the bug history, not adding a new one"));
            }
        }
    }

 log_out:
    log(_("Logging out"));
    rhbz_logout(client);

    log(_("Status: %s%s%s %s/show_bug.cgi?id=%u"),
                bz->bi_status,
                bz->bi_resolution ? " " : "",
                bz->bi_resolution ? bz->bi_resolution : "",
                rhbz.b_bugzilla_url,
                bz->bi_id);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (dd)
    {
        char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", rhbz.b_bugzilla_url, bz->bi_id);
        add_reported_to(dd, msg);
        free(msg);
        dd_close(dd);
    }

#if 0  /* enable if you search for leaks (valgrind etc) */
    free(rhbz.b_product);
    free(rhbz.b_product_version);
    problem_data_free(problem_data);
    free_bug_info(bz);
    abrt_xmlrpc_free_client(client);
#endif
    return 0;
}
int main(int argc, char **argv)
{
    abrt_init(argv);

    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    const char *dump_dir_name = ".";
    const char *conf_file = CONF_DIR"/plugins/upload.conf";
    const char *url = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-v] -d DIR [-c CONFFILE] [-u URL]\n"
        "\n"
        "Uploads compressed tarball of problem directory DIR to URL.\n"
        "If URL is not specified, creates tarball in "LARGE_DATA_TMP_DIR" and exits.\n"
        "\n"
        "URL should have form 'protocol://[user[:pass]@]host/dir/[file.tar.gz]'\n"
        "where protocol can be http(s), ftp, scp, or file.\n"
        "File protocol can't have user and host parts: 'file:///dir/[file.tar.gz].'\n"
        "If URL ends with a slash, the archive name will be generated and appended\n"
        "to URL; otherwise, URL will be used as full file name.\n"
        "\n"
        "Files with names listed in $EXCLUDE_FROM_REPORT are not included\n"
        "into the tarball.\n"
        "\n"
        "\n""If not specified, CONFFILE defaults to "CONF_DIR"/plugins/upload.conf"
        "\n""Its lines should have 'PARAM = VALUE' format."
        "Recognized string parameter: URL.\n"
        "Parameter can be overridden via $Upload_URL."
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_c = 1 << 2,
        OPT_u = 1 << 3,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR"     , _("Problem directory")),
        OPT_STRING('c', NULL, &conf_file    , "CONFFILE", _("Config file")),
        OPT_STRING('u', NULL, &url          , "URL"     , _("Base URL to upload to")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    if (url)
        replace_map_string_item(settings, xstrdup("URL"), xstrdup(url));
    if (conf_file)
        load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);

    int result = create_and_upload_archive(dump_dir_name, settings);

    free_map_string(settings);
    return result;
}
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    char *i_opt = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [options] -d DIR\n"
        "\n"
        "Analyzes coredump in problem directory DIR, generates and saves backtrace"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_i = 1 << 2,
        OPT_t = 1 << 3,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING( 'd', NULL, &dump_dir_name   , "DIR"           , _("Problem directory")),
        OPT_STRING( 'i', NULL, &i_opt           , "DIR1[:DIR2]...", _("Additional debuginfo directories")),
        OPT_INTEGER('t', NULL, &exec_timeout_sec,                   _("Kill gdb if it runs for more than NUM seconds")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    if (!load_abrt_plugin_conf_file(CCPP_CONF, settings))
        error_msg("Can't load '%s'", CCPP_CONF);

    const char *value = get_map_string_item_or_NULL(settings, "DebuginfoLocation");
    char *debuginfo_location;
    if (value)
        debuginfo_location = xstrdup(value);
    else
        debuginfo_location = xstrdup(LOCALSTATEDIR"/cache/abrt-di");

    free_map_string(settings);
    char *debuginfo_dirs = NULL;
    if (i_opt)
        debuginfo_dirs = xasprintf("%s:%s", debuginfo_location, i_opt);

    /* Create gdb backtrace */
    char *backtrace = get_backtrace(dump_dir_name, exec_timeout_sec,
            (debuginfo_dirs) ? debuginfo_dirs : debuginfo_location);
    free(debuginfo_location);
    if (!backtrace)
    {
        backtrace = xstrdup("");
        log_warning("get_backtrace() returns NULL, broken core/gdb?");
    }
    free(debuginfo_dirs);
    free_abrt_conf_data();

    /* Store gdb backtrace */

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;
    dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
    dd_close(dd);

    /* Don't be completely silent. gdb run takes a few seconds,
     * it is useful to let user know it (maybe) worked.
     */
    log_warning(_("Backtrace is generated and saved, %u bytes"), (int)strlen(backtrace));
    free(backtrace);

    return 0;
}
Exemple #18
0
static void
set_settings(mantisbt_settings_t *m, map_string_t *settings, struct dump_dir *dd)
{
    const char *environ;

    environ = getenv("Mantisbt_Login");
    m->m_login = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Login"));

    environ = getenv("Mantisbt_Password");
    m->m_password = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Password"));

    environ = getenv("Mantisbt_MantisbtURL");
    m->m_mantisbt_url = environ ? environ : get_map_string_item_or_empty(settings, "MantisbtURL");
    if (!m->m_mantisbt_url[0])
        m->m_mantisbt_url = "http://localhost/mantisbt";
    else
    {
        /* We don't want trailing '/': "https://host/dir/" -> "https://host/dir" */
        char *last_slash = strrchr(m->m_mantisbt_url, '/');
        if (last_slash && last_slash[1] == '\0')
            *last_slash = '\0';
    }
    m->m_mantisbt_soap_url = concat_path_file(m->m_mantisbt_url, "api/soap/mantisconnect.php");

    environ = getenv("Mantisbt_Project");
    if (environ)
    {
        m->m_project = xstrdup(environ);
        environ = getenv("Mantisbt_ProjectVersion");
        if (environ)
            m->m_project_version = xstrdup(environ);
    }
    else
    {
        const char *option = get_map_string_item_or_NULL(settings, "Project");
        if (option)
            m->m_project = xstrdup(option);
        option = get_map_string_item_or_NULL(settings, "ProjectVersion");
        if (option)
            m->m_project_version = xstrdup(option);
    }

    if (!m->m_project || !*m->m_project) /* if not overridden or empty... */
    {
        free(m->m_project);
        free(m->m_project_version);

        if (dd != NULL)
        {
            map_string_t *osinfo = new_map_string();

            char *os_info_data = dd_load_text(dd, FILENAME_OS_INFO);
            parse_osinfo(os_info_data, osinfo);
            free(os_info_data);

            parse_osinfo_for_mantisbt(osinfo, &m->m_project, &m->m_project_version);
            free_map_string(osinfo);
        }
    }

    environ = getenv("Mantisbt_SSLVerify");
    m->m_ssl_verify = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "SSLVerify"));

    environ = getenv("Mantisbt_DontMatchComponents");
    m->m_DontMatchComponents = environ ? environ : get_map_string_item_or_empty(settings, "DontMatchComponents");

    m->m_create_private = get_global_create_private_ticket();

    if (!m->m_create_private)
    {
        environ = getenv("Mantisbt_CreatePrivate");
        m->m_create_private = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "CreatePrivate"));
    }
    log_notice("create private MantisBT ticket: '%s'", m->m_create_private ? "YES": "NO");
}
Exemple #19
0
int main(int argc, char **argv)
{
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    struct ureport_server_config config;
    ureport_server_config_init(&config);

    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_u = 1 << 2,
        OPT_k = 1 << 3,
        OPT_t = 1 << 4,
        OPT_h = 1 << 5,
        OPT_i = 1 << 6,
    };

    int ret = 1; /* "failure" (for now) */
    int insecure = !config.ur_ssl_verify;
    const char *conf_file = UREPORT_CONF_FILE_PATH;
    const char *arg_server_url = NULL;
    const char *client_auth = NULL;
    const char *http_auth = NULL;
    GList *auth_items = NULL;
    const char *dump_dir_path = ".";
    const char *ureport_hash = NULL;
    int ureport_hash_from_rt = 0;
    int rhbz_bug = -1;
    int rhbz_bug_from_rt = 0;
    const char *email_address = NULL;
    int email_address_from_env = 0;
    char *comment = NULL;
    int comment_file = 0;
    char *attach_value = NULL;
    char *attach_value_from_rt = NULL;
    char *attach_value_from_rt_data = NULL;
    char *report_result_type = NULL;
    char *attach_type = NULL;
    struct dump_dir *dd = NULL;
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT__DUMP_DIR(&dump_dir_path),
        OPT_STRING('u', "url", &arg_server_url, "URL", _("Specify server URL")),
        OPT_BOOL('k', "insecure", &insecure,
                          _("Allow insecure connection to ureport server")),
        OPT_STRING('t', "auth", &client_auth, "SOURCE", _("Use client authentication")),
        OPT_STRING('h', "http-auth", &http_auth, "CREDENTIALS", _("Use HTTP Authentication")),
        OPT_LIST('i', "auth_items", &auth_items, "AUTH_ITEMS", _("Additional files included in 'auth' key")),
        OPT_STRING('c', NULL, &conf_file, "FILE", _("Configuration file")),
        OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
                          _("bthash of uReport to attach (conflicts with -A)")),
        OPT_BOOL('A', "attach-rt", &ureport_hash_from_rt,
                          _("attach to a bthash from reported_to (conflicts with -a)")),
        OPT_STRING('e', "email", &email_address, "EMAIL",
                          _("contact e-mail address (requires -a|-A, conflicts with -E)")),
        OPT_BOOL('E', "email-env", &email_address_from_env,
                          _("contact e-mail address from environment or configuration file (requires -a|-A, conflicts with -e)")),
        OPT_INTEGER('b', "bug-id", &rhbz_bug,
                          _("attach RHBZ bug (requires -a|-A, conflicts with -B)")),
        OPT_BOOL('B', "bug-id-rt", &rhbz_bug_from_rt,
                          _("attach last RHBZ bug from reported_to (requires -a|-A, conflicts with -b)")),
        OPT_STRING('o', "comment", &comment, "DESCRIPTION",
                          _("attach short text (requires -a|-A, conflicts with -D)")),
        OPT_BOOL('O', "comment-file", &comment_file,
                          _("attach short text from comment (requires -a|-A, conflicts with -d)")),

        /* va l ue */
        OPT_STRING('l', "value", &attach_value, "DATA",
                          _("attach value (requires -a|-A and -T, conflicts with -L)")),
        OPT_STRING('L', "value-rt", &attach_value_from_rt, "FIELD",
                          _("attach data of FIELD [URL] of the last report result (requires -a|-A, -r and -T, conflicts with -l)")),

        OPT_STRING('r', "report-result-type", &report_result_type, "REPORT_RESULT_TYPE",
                          _("use REPORT_RESULT_TYPE when looking for FIELD in reported_to (used only with -L)")),
        OPT_STRING('T', "type", &attach_type, "ATTACHMENT_TYPE",
                          _("attach DATA as ureport attachment ATTACHMENT_TYPE (used only with -l|-L)")),
        OPT_END(),
    };

    const char *program_usage_string = _(
        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-h CREDENTIALS]\n"
        "  [-A -a bthash -B -b bug-id -E -e email -O -o comment] [-d DIR]\n"
        "  [-A -a bthash -T ATTACHMENT_TYPE -r REPORT_RESULT_TYPE -L RESULT_FIELD] [-d DIR]\n"
        "  [-A -a bthash -T ATTACHMENT_TYPE -l DATA] [-d DIR]\n"
        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-h CREDENTIALS] [-i AUTH_ITEMS] [-d DIR]\n"
        "\n"
        "Upload micro report or add an attachment to a micro report\n"
        "\n"
        "Reads the default configuration from "UREPORT_CONF_FILE_PATH
    );

    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    map_string_t *settings = new_map_string();
    load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);

    ureport_server_config_load(&config, settings);

    if (opts & OPT_u)
        ureport_server_config_set_url(&config, xstrdup(arg_server_url));
    if (opts & OPT_k)
        config.ur_ssl_verify = !insecure;
    if (opts & OPT_t)
        ureport_server_config_set_client_auth(&config, client_auth);
    if (opts & OPT_h)
        ureport_server_config_load_basic_auth(&config, http_auth);
    if (opts & OPT_i)
    {
        g_list_free_full(config.ur_prefs.urp_auth_items, free);
        config.ur_prefs.urp_auth_items = auth_items;
    }

    if (!config.ur_url)
        ureport_server_config_set_url(&config, xstrdup(DEFAULT_WEB_SERVICE_URL));

    if (ureport_hash && ureport_hash_from_rt)
        error_msg_and_die("You need to pass either -a bthash or -A");

    if (rhbz_bug >= 0 && rhbz_bug_from_rt)
        error_msg_and_die("You need to pass either -b bug-id or -B");

    if (email_address && email_address_from_env)
        error_msg_and_die("You need to pass either -e bthash or -E");

    if (comment && comment_file)
        error_msg_and_die("You need to pass either -o comment or -O");

    if (attach_value && attach_value_from_rt)
        error_msg_and_die("You need to pass either -l url or -L");

    if ((attach_value || attach_value_from_rt) && attach_type == NULL)
        error_msg_and_die("You need to pass -T together with -l and -L");

    if (attach_value_from_rt)
    {
        if (report_result_type == NULL)
            error_msg_and_die("You need to pass -r together with -L");

        /* If you introduce a new recognized value, don't forget to update
         * the documentation and the conditions below. */
        if (strcmp(attach_value_from_rt, "URL") != 0)
            error_msg_and_die("-L accepts only 'URL'");
    }

    if (ureport_hash_from_rt || rhbz_bug_from_rt || comment_file || attach_value_from_rt)
    {
        dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
        if (!dd)
            xfunc_die();

        if (ureport_hash_from_rt)
        {
            report_result_t *ureport_result = find_in_reported_to(dd, "uReport");

            if (!ureport_result || !ureport_result->bthash)
                error_msg_and_die(_("This problem does not have an uReport assigned."));

            /* sorry, this will be leaked */
            ureport_hash = xstrdup(ureport_result->bthash);

            free_report_result(ureport_result);
        }

        if (rhbz_bug_from_rt)
        {
            report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");

            if (!bz_result || !bz_result->url)
                error_msg_and_die(_("This problem has not been reported to Bugzilla."));

            char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
            if (!bugid_ptr)
                error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
            bugid_ptr += strlen("show_bug.cgi?id=");

            /* we're just reading int, sscanf works fine */
            if (sscanf(bugid_ptr, "%d", &rhbz_bug) != 1)
                error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);

            free_report_result(bz_result);
        }

        if (comment_file)
        {
            comment = dd_load_text(dd, FILENAME_COMMENT);
            if (comment == NULL)
                error_msg_and_die(_("Cannot attach comment from 'comment' file"));
            if (comment[0] == '\0')
                error_msg_and_die(_("'comment' file is empty"));
        }

        if (attach_value_from_rt)
        {
            report_result_t *result = find_in_reported_to(dd, report_result_type);

            if (!result)
                error_msg_and_die(_("This problem has not been reported to '%s'."), report_result_type);

            /* If you introduce a new attach_value_from_rt recognized value,
             * this condition will become invalid. */
            if (!result->url)
                error_msg_and_die(_("The report result '%s' is missing URL."), report_result_type);

            /* Avoid the need to duplicate the string. */
            attach_value = attach_value_from_rt_data = result->url;
            result->url = NULL;

            free_report_result(result);
        }

        dd_close(dd);
    }

    if (email_address_from_env)
    {
        UREPORT_OPTION_VALUE_FROM_CONF(settings, "ContactEmail", email_address, (const char *));

        if (!email_address)
            error_msg_and_die(_("Neither environment variable 'uReport_ContactEmail' nor configuration option 'ContactEmail' is set"));
    }

    if (ureport_hash)
    {
        if (rhbz_bug < 0 && !email_address && !comment && !attach_value)
            error_msg_and_die(_("You need to specify bug ID, contact email, comment or all of them"));

        if (rhbz_bug >= 0)
        {
            if (ureport_attach_int(ureport_hash, "RHBZ", rhbz_bug, &config))
                goto finalize;
        }

        if (email_address)
        {
            if (ureport_attach_string(ureport_hash, "email", email_address, &config))
                goto finalize;
        }

        if (comment)
        {
            if (ureport_attach_string(ureport_hash, "comment", comment, &config))
                goto finalize;
        }

        if (attach_value)
        {
            if (ureport_attach_string(ureport_hash, attach_type, attach_value, &config))
                goto finalize;
        }

        ret = 0;
        goto finalize;
    }
    if (!ureport_hash && (rhbz_bug >= 0 || email_address))
        error_msg_and_die(_("You need to specify bthash of the uReport to attach."));

    struct ureport_preferences *prefs = &(config.ur_prefs);
    prefs->urp_flags |= UREPORT_PREF_FLAG_RETURN_ON_FAILURE;

    char *json_ureport = ureport_from_dump_dir_ext(dump_dir_path, prefs);
    if (!json_ureport)
    {
        error_msg(_("Failed to generate microreport from the problem data"));
        goto finalize;
    }

    struct ureport_server_response *response = ureport_submit(json_ureport, &config);
    free(json_ureport);

    if (!response)
        goto finalize;

    if (!response->urr_is_error)
    {
        log_notice("is known: %s", response->urr_value);
        ret = 0; /* "success" */

        if (!ureport_server_response_save_in_dump_dir(response, dump_dir_path, &config))
            xfunc_die();

        /* If a reported problem is not known then emit NEEDMORE */
        if (strcmp("true", response->urr_value) == 0)
        {
            log(_("This problem has already been reported."));
            if (response->urr_message)
                log("%s", response->urr_message);

            ret = EXIT_STOP_EVENT_RUN;
        }
    }
    else
        error_msg(_("Server responded with an error: '%s'"), response->urr_value);

    ureport_server_response_free(response);

finalize:
    free(attach_value_from_rt_data);

    if (config.ur_prefs.urp_auth_items == auth_items)
        config.ur_prefs.urp_auth_items = NULL;

    free_map_string(settings);
    ureport_server_config_destroy(&config);

    return ret;
}