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 } }
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; }
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; }
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; }
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; }
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); } } }
static void problem_info_set_dir(problem_info_t *pi, const char *dir) { problem_data_add_text_noteditable(pi->problem_data, CD_DUMPDIR, dir); }