Пример #1
0
void problem_data_add_current_process_data(problem_data_t *pd)
{
    const char *executable = problem_data_get_content_or_NULL(pd, FILENAME_EXECUTABLE);
    if (executable == NULL)
    {
        char buf[PATH_MAX + 1];
        char exe[sizeof("/proc/%u/exe") + sizeof(int)*3];
        sprintf(exe, "/proc/%u/exe", (int)getpid());
        ssize_t read = readlink(exe, buf, PATH_MAX);
        if (read > 0)
        {
            buf[read] = '\0';
            VERB2 log("reporting initiated from: %s", buf);
            problem_data_add_text_noteditable(pd, FILENAME_EXECUTABLE, buf);
        }

//#ifdef WITH_RPM
        /* FIXME: component should be taken from rpm using librpm
         * which means we need to link against it :(
         * or run rpm -qf executable ??
         */
        /* Fedora/RHEL rpm specific piece of code */
        const char *component = problem_data_get_content_or_NULL(pd, FILENAME_COMPONENT);
        //FIXME: this REALLY needs to go away, or every report will be assigned to abrt
        if (component == NULL) // application didn't specify component
            problem_data_add_text_noteditable(pd, FILENAME_COMPONENT, "abrt");
//#endif
    }
}
Пример #2
0
problem_data_t *get_problem_data_dbus(const char *problem_dir_path)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return NULL;

    GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
    g_variant_builder_add(builder, "s", FILENAME_TIME          );
    g_variant_builder_add(builder, "s", FILENAME_REASON        );
    g_variant_builder_add(builder, "s", FILENAME_NOT_REPORTABLE);
    g_variant_builder_add(builder, "s", FILENAME_COMPONENT     );
    g_variant_builder_add(builder, "s", FILENAME_EXECUTABLE    );
    g_variant_builder_add(builder, "s", FILENAME_REPORTED_TO   );
    GVariant *params = g_variant_new("(sas)", problem_dir_path, builder);
    g_variant_builder_unref(builder);

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "GetInfo",
                                            params,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("Can't get problem data from abrt-dbus: %s"), error->message);
        g_error_free(error);
        return NULL;
    }

    problem_data_t *pd = problem_data_new();
    char *key, *val;
    GVariantIter *iter;
    g_variant_get(result, "(a{ss})", &iter);
    while (g_variant_iter_loop(iter, "{ss}", &key, &val))
    {
        problem_data_add_text_noteditable(pd, key, val);
    }
    g_variant_unref(result);
    return pd;
}
Пример #3
0
int fill_problem_data_over_dbus(const char *problem_id, const char **elements, problem_data_t *problem_data)
{
    INITIALIZE_LIBABRT();

    GDBusProxy *proxy = get_dbus_proxy();
    if (!proxy)
        return -1;

    GVariantBuilder *args_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));

    for (const char **iter = elements; *iter; ++iter)
        g_variant_builder_add(args_builder, "s", *iter);

    GVariant *params = g_variant_new("(sas)", problem_id, args_builder);
    g_variant_builder_unref(args_builder);

    GError *error = NULL;
    GVariant *result = g_dbus_proxy_call_sync(proxy,
                                            "GetInfo",
                                            params,
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1,
                                            NULL,
                                            &error);

    if (error)
    {
        error_msg(_("D-Bus GetInfo method call failed: %s"), error->message);
        g_error_free(error);
        return -2;
    }


    char *key, *val;
    GVariantIter *iter;
    g_variant_get(result, "(a{ss})", &iter);
    while (g_variant_iter_loop(iter, "{ss}", &key, &val))
        problem_data_add_text_noteditable(problem_data, key, val);

    g_variant_unref(result);

    return 0;
}
Пример #4
0
void problem_data_reload_from_dump_dir(void)
{
    free(g_events);

    struct dump_dir *dd = dd_opendir(g_dump_dir_name, DD_OPEN_READONLY);
    if (!dd)
        xfunc_die(); /* dd_opendir already logged error msg */

    problem_data_t *new_cd = create_problem_data_from_dump_dir(dd);
    problem_data_add_text_noteditable(new_cd, CD_DUMPDIR, g_dump_dir_name);

    g_events = list_possible_events(dd, NULL, "");
    dd_close(dd);

    /* Copy "selected for reporting" flags */
    GHashTableIter iter;
    char *name;
    struct problem_item *new_item;
    g_hash_table_iter_init(&iter, new_cd);
    while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&new_item))
    {
        struct problem_item *old_item = g_cd ? problem_data_get_item_or_NULL(g_cd, name) : NULL;
        if (old_item)
        {
            new_item->selected_by_user = old_item->selected_by_user;
            new_item->allowed_by_reporter = old_item->allowed_by_reporter;
            new_item->default_by_reporter = old_item->default_by_reporter;
            new_item->required_by_reporter = old_item->required_by_reporter;
        }
        else
        {
            new_item->selected_by_user = 0;
            new_item->allowed_by_reporter = 0;
            new_item->default_by_reporter = 0;
            new_item->required_by_reporter = 0;
        }
        //log("%s: was ->selected_by_user=%d", __func__, new_item->selected_by_user);
    }
    problem_data_free(g_cd);
    g_cd = new_cd;
}
Пример #5
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 = _(
        "& [-v] [-d DIR] [-m MESSAGEID] [-F FMTFILE] [-p NONE|ESSENTIAL|FULL] [-s SYSLOGID]\n"
        "\n"
        "Reports problem information into systemd journal.\n"
        "\n"
        "The tool reads problem directory DIR and sends its details\n"
        "into systemd journal as a message. If MESSAGEID is defined, the tool\n"
        "creates a catalog message as well.\n"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_m = 1 << 2,
        OPT_F = 1 << 3,
        OPT_p = 1 << 4,
        OPT_s = 1 << 5,
        OPT_D = 1 << 6,
    };
    const char *dump_dir_name = ".";
    const char *message_id = NULL;
    const char *fmt_file = NULL;
    const char *dump = NULL;
    const char *syslog_id = 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_STRING('m', "message-id"  , &message_id,    "STR"   , _("Catalog message id")),
        OPT_STRING('F', NULL          , &fmt_file     , "FILE"  , _("Formatting file for catalog message")),
        OPT_STRING('p', "dump"        , &dump         , "STR"   , _("Dump problem dir into systemd journal fields")),
        OPT_STRING('s', "syslog-id"   , &syslog_id    , "STR"   , _("Define SYSLOG_IDENTIFIER systemd journal field")),
        OPT_BOOL(  'D', NULL          , NULL                    , _("Debug")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    unsigned dump_opt = DUMP_NONE;
    if (opts & OPT_p)
    {
        if (dump && strcmp(dump, "NONE") == 0)
            /* PASS */;
        else if (dump && strcmp(dump, "ESSENTIAL") == 0)
            dump_opt = DUMP_ESSENTIAL;
        else if (dump && strcmp(dump, "FULL") == 0)
            dump_opt = DUMP_FULL;
        else
        {
            error_msg("Parameter --dump takes NONE|ESSENTIAL|FULL values");
            show_usage_and_die(program_usage_string, program_options);
        }
    }

    export_abrt_envvars(0);

    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 */

    problem_formatter_t *pf = problem_formatter_new();

    if (fmt_file)
    {
        if (problem_formatter_load_file(pf, fmt_file))
            error_msg_and_die("Invalid format file: %s", fmt_file);
    }
    else
    {
        if (problem_formatter_load_string(pf, PROBLEM_REPORT_DEFAULT_TEMPLATE))
            error_msg_and_die("BUG: Invalid default problem report format string");
    }

    problem_report_settings_t report_settings = problem_formatter_get_settings(pf);
    report_settings.prs_shortbt_max_frames = 5;
    report_settings.prs_shortbt_max_text_size = 0; /* always short bt */
    problem_formatter_set_settings(pf, report_settings);

    /* Modify problem_data to meet reporter's needs */
    /* We want to have only binary name in problem report assigned to executable element */
    const char *exe = problem_data_get_content_or_NULL(problem_data, FILENAME_EXECUTABLE);
    char *binary_name = NULL;
    if (exe)
        binary_name = strrchr(exe, '/') + 1;

    if (binary_name)
        problem_data_add_text_noteditable(problem_data, BINARY_NAME, binary_name);

    /* crash_function element is neeeded by systemd journal messages, save ??, if it doesn't exist */
    const char *crash_function = problem_data_get_content_or_NULL(problem_data, FILENAME_CRASH_FUNCTION);
    if (!crash_function)
        problem_data_add_text_noteditable(problem_data, "crash_function", "??");

    /* Add SYSLOG_IDENTIFIER into problem data */
    if (syslog_id || (syslog_id = getenv("REPORTER_JOURNAL_SYSLOG_ID")))
        problem_data_add_text_noteditable(problem_data, SYSLOG_ID, syslog_id);

    /* Add MESSAGE_ID into problem data */
    if (message_id)
        problem_data_add_text_noteditable(problem_data, MESSAGE_ID, message_id);

    /* Generating of problem report */
    problem_report_t *pr = NULL;
    if (problem_formatter_generate_report(pf, problem_data, &pr))
        error_msg_and_die("Failed to format bug report from problem data");

    /* Debug */
    if (opts & OPT_D)
    {
        log("Message: %s\n"
                "\n"
                "%s"
                "\n"
                , problem_report_get_summary(pr)
                , problem_report_get_description(pr)
        );

        problem_data_free(problem_data);
        problem_report_free(pr);
        problem_formatter_free(pf);
        return 0;
    }

    msg_content_t *msg_c = create_journal_message(problem_data, pr, dump_opt);

    /* post journal message */
    sd_journal_sendv(msg_content_get_data(msg_c), msg_content_get_size(msg_c));

    msg_content_free(msg_c);

    problem_data_free(problem_data);
    problem_formatter_free(pf);
    problem_report_free(pr);

    return 0;
}
Пример #6
0
void problem_data_add_basics(problem_data_t *pd)
{
    const char *analyzer = problem_data_get_content_or_NULL(pd, FILENAME_ANALYZER);
    const char *type = problem_data_get_content_or_NULL(pd, FILENAME_TYPE);
    if (analyzer == NULL)
    {
        analyzer = type ? type : "libreport";
        problem_data_add_text_noteditable(pd, FILENAME_ANALYZER, analyzer);
    }

    if (type == NULL)
        problem_data_add_text_noteditable(pd, FILENAME_TYPE, analyzer);

    /* If application didn't provide dupe hash, we generate it
     * from all components, so we at least eliminate the exact same
     * reports
     *
     * We don't want to generate DUPHASH file because it is usually generated
     * later in some "analyze_*" event. DUPHASH was originally designed as
     * global problem identifier and generating of global identifier requires
     * more space and data. On the contrary UUID was originally designed as
     * local problem identifier. It means that this identifier is weaker (e.g.
     * a hash generated from a coredump without debuginfo - there can be many
     * similar backtraces without line numbers and function names).
     */
    if (problem_data_get_content_or_NULL(pd, FILENAME_UUID) == NULL)
    {
        /* If application provided DUPHASH, we should use it in UUID as well.
         * Otherwise we compute hash from all problem's data.
         */
        const char *const duphash = problem_data_get_content_or_NULL(pd, FILENAME_DUPHASH);
        if (duphash != NULL)
            problem_data_add_text_noteditable(pd, FILENAME_UUID, duphash);
        else
        {
            /* start hash */
            sha1_ctx_t sha1ctx;
            sha1_begin(&sha1ctx);

            /*
             * To avoid spurious hash differences, sort keys so that elements are
             * always processed in the same order:
             */
            GList *list = g_hash_table_get_keys(pd);
            list = g_list_sort(list, (GCompareFunc)strcmp);
            GList *l = list;
            while (l)
            {
                const char *key = l->data;
                l = l->next;
                struct problem_item *item = g_hash_table_lookup(pd, key);
                /* do not hash items which are binary (item->flags & CD_FLAG_BIN).
                 * Their ->content is full file name, with path. Path is always
                 * different and will make hash differ even if files are the same.
                 */
                if (item->flags & CD_FLAG_BIN)
                    continue;
                sha1_hash(&sha1ctx, item->content, strlen(item->content));
            }
            g_list_free(list);

            /* end hash */
            char hash_bytes[SHA1_RESULT_LEN];
            sha1_end(&sha1ctx, hash_bytes);
            char hash_str[SHA1_RESULT_LEN*2 + 1];
            bin2hex(hash_str, hash_bytes, SHA1_RESULT_LEN)[0] = '\0';

            problem_data_add_text_noteditable(pd, FILENAME_UUID, hash_str);
        }
    }
}
Пример #7
0
static void problem_info_set_dir(problem_info_t *pi, const char *dir)
{
    problem_data_add_text_noteditable(pi->problem_data, CD_DUMPDIR, dir);
}