static int create_and_upload_archive( const char *dump_dir_name, const char *url, map_string_t *settings, char **remote_name) { int result = 1; /* error */ char* tempfile = NULL; /* Create a child gzip which will compress the data */ /* SELinux guys are not happy with /tmp, using /var/run/abrt */ /* Reverted back to /tmp for ABRT2 */ /* Changed again to /var/tmp because of Fedora feature tmp-on-tmpfs */ tempfile = concat_path_basename(LARGE_DATA_TMP_DIR, dump_dir_name); tempfile = append_to_malloced_string(tempfile, ".tar.gz"); string_vector_ptr_t exclude_from_report = get_global_always_excluded_elements(); struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) xfunc_die(); /* error msg is already logged by dd_opendir */ /* Compressing e.g. 0.5gig coredump takes a while. Let client know what we are doing */ log_warning(_("Compressing data")); if (dd_create_archive(dd, tempfile, (const_string_vector_const_ptr_t)exclude_from_report, 0) != 0) { log_error("Can't create temporary file in %s", LARGE_DATA_TMP_DIR); goto ret; } dd_close(dd); dd = NULL; /* Upload the archive */ /* Upload from /tmp to /tmp + deletion -> BAD, exclude this possibility */ if (url && url[0] && strcmp(url, "file://"LARGE_DATA_TMP_DIR"/") != 0) result = interactive_upload_file(url, tempfile, settings, remote_name); else { result = 0; /* success */ log_warning(_("Archive is created: '%s'"), tempfile); *remote_name = tempfile; tempfile = NULL; } ret: dd_close(dd); if (tempfile) { unlink(tempfile); free(tempfile); } return result; }
int main(int argc, char *argv[]) { int ch; setprogname(argv[0]); (void)setlocale(LC_ALL, ""); while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: errx(EXIT_FAILURE, "usage: dd [operand ...]"); /* NOTREACHED */ } } argc -= (optind - 1); argv += (optind - 1); jcl(argv); setup(); (void)signal(SIGINFO, summaryx); (void)signal(SIGINT, terminate); (void)sigemptyset(&infoset); (void)sigaddset(&infoset, SIGINFO); (void)atexit(summary); while (files_cnt--) dd_in(); dd_close(); exit(0); /* NOTREACHED */ }
int report_problem_in_memory(problem_data_t *pd, int flags) { int result = 0; struct dump_dir *dd = create_dump_dir_from_problem_data(pd, "/tmp"/* /var/tmp ?? */); if (!dd) return -1; char *dir_name = xstrdup(dd->dd_dirname); dd_close(dd); VERB2 log("Temp problem dir: '%s'", dir_name); if (!(flags & LIBREPORT_WAIT)) flags |= LIBREPORT_DEL_DIR; result = report_problem_in_dir(dir_name, flags); /* If we waited for reporter to finish, we should clean up the tmp dir * (if we didn't, cleaning up will be done by reporting child process later). * We can also reload the problem data if requested. */ if (flags & LIBREPORT_WAIT) { if (flags & LIBREPORT_RELOAD_DATA) g_hash_table_remove_all(pd); dd = dd_opendir(dir_name, 0); if (dd) { if (flags & LIBREPORT_RELOAD_DATA) problem_data_load_from_dump_dir(pd, dd, NULL); dd_delete(dd); } } free(dir_name); return result; }
static bool problem_info_ensure_writable(problem_info_t *pi) { if (pi->is_writable) return true; /* chown the directory in any case, because kernel oopses are not foreign */ /* but their dump directories are not writable without chowning them or */ /* stealing them. The stealing is deprecated as it breaks the local */ /* duplicate search and root cannot see them */ const int res = chown_dir_over_dbus(problem_info_get_dir(pi)); if (pi->foreign && res != 0) { error_msg(_("Can't take ownership of '%s'"), problem_info_get_dir(pi)); return false; } pi->foreign = false; struct dump_dir *dd = open_directory_for_writing(problem_info_get_dir(pi), /* don't ask */ NULL); if (!dd) { error_msg(_("Can't open directory for writing '%s'"), problem_info_get_dir(pi)); return false; } problem_info_set_dir(pi, dd->dd_dirname); pi->is_writable = true; dd_close(dd); return true; }
int dd_main(int argc, char *argv[]) { int ch; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: fprintf(stderr, "usage: dd [operand ...]\n"); exit(1); /* NOTREACHED */ } } argc -= (optind - 1); argv += (optind - 1); jcl(argv); setup(); // (void)signal(SIGINFO, summaryx); (void)signal(SIGINT, terminate); (void)sigemptyset(&infoset); // (void)sigaddset(&infoset, SIGINFO); (void)atexit(summary); while (files_cnt--) dd_in(); dd_close(); exit(0); /* NOTREACHED */ }
bool ignored_problems_contains(ignored_problems_t *set, const char *problem_id) { struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS); if (!dd) { /* We do not consider this as an error because the directory can be * deleted by other programs. This code expects that dd_opendir() * already emitted good and explanatory message. This message attempts * to explain what the previous failure causes. */ VERB1 error_msg("Can't open '%s'." " Won't try to check whether it belongs to ignored problems", problem_id); return false; } char *uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS); char *duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS); dd_close(dd); log_notice("Going to check if problem '%s' is in ignored problems '%s'", problem_id, set->ign_set_file_path); bool found = ignored_problems_file_contains(set, problem_id, uuid, duphash, /* (FILE **) */NULL, "r"); free(duphash); free(uuid); return found; }
void ignored_problems_remove(ignored_problems_t *set, const char *problem_id) { char *uuid = NULL; char *duphash = NULL; struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS); if (dd) { uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS); duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS); dd_close(dd); } else { /* We do not consider this as an error because the directory can be * deleted by other programs. This code expects that dd_opendir() * already emitted good explanatory message. This message * explains what the previous failure causes. */ VERB1 error_msg("Can't get UUID/DUPHASH from" " '%s' to remove it from the ignored problems:" " can't open the problem", problem_id); } ignored_problems_remove_row(set, problem_id, uuid, duphash); free(duphash); free(uuid); }
/* *************************************************************************** ********[ The Main ]******************************************************** *************************************************************************** */ int main(int argv, char *argc[]) { if (argv == 1) { printf("need to run from DayDream!\n"); exit(1); } d = dd_initdoor(argc[1]); dd_getstrval(d, username, USER_HANDLE); dd_getstrval(d, buf, DOOR_PARAMS); Unzipper(); /* unzip & get filesize */ DataBitch(); /* open fastest database */ Me_Search(); /* search for user record */ if (newuser == 1) WriteNewbie(); /* if we are newbie */ if (newuser == 0) My_Bytes(); /* if we do have bytes */ fclose(datafile); /* close files */ unlink(DizzyBuf); unlink(DizzyBuf); dd_close(d); return 0; }
/* unzip and get filesize */ int Unzipper() { FILE *FileName; /* uploaded filename */ FILE *checkDiz; /* file_id.diz temp'o */ sprintf(cmdline, "unzip -o %s FILE_ID.DIZ file_id.diz -d /home/bbs/doors >/dev/null", buf); system(cmdline); strcpy(DizzyBuf, "/home/bbs/doors/file_id.diz"); checkDiz = fopen("/home/bbs/doors/file_id.diz", "rt"); if (!checkDiz) { checkDiz = fopen("/home/bbs/doors/FILE_ID.DIZ", "rt"); if (!checkDiz) { printf("no f*****g DIZZY here, lame zip :)\n"); dd_close(d); exit(1); } strcpy(DizzyBuf, "/home/bbs/doors/FILE_ID.DIZ"); } DizzyCompute(); /* dizzy date calculation */ FileName = fopen(buf, "r"); /* open the parameter filename */ fseek(FileName, 0, SEEK_END); /* zoom to end */ FileSize = 0; /* make sure the size is zero */ FileSize = ftell(FileName); /* grab the position (filesize) */ fclose(FileName); /* close the filen */ return 0; }
/* Remove dump dir */ static int delete_path(const char *dump_dir_name) { /* If doesn't start with "g_settings_dump_location/"... */ if (!dir_is_in_dump_location(dump_dir_name)) { /* Then refuse to operate on it (someone is attacking us??) */ error_msg("Bad problem directory name '%s', should start with: '%s'", dump_dir_name, g_settings_dump_location); return 400; /* Bad Request */ } if (!dir_has_correct_permissions(dump_dir_name, DD_PERM_DAEMONS)) { error_msg("Problem directory '%s' has wrong owner or group", dump_dir_name); return 400; /* */ } struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_FD_ONLY); if (dd == NULL) { perror_msg("Can't open problem directory '%s'", dump_dir_name); return 400; } if (!dd_accessible_by_uid(dd, client_uid)) { dd_close(dd); if (errno == ENOTDIR) { error_msg("Path '%s' isn't problem directory", dump_dir_name); return 404; /* Not Found */ } error_msg("Problem directory '%s' can't be accessed by user with uid %ld", dump_dir_name, (long)client_uid); return 403; /* Forbidden */ } dd = dd_fdopendir(dd, /*flags:*/ 0); if (dd) { if (dd_delete(dd) != 0) { error_msg("Failed to delete problem directory '%s'", dump_dir_name); dd_close(dd); return 400; } } return 0; /* success */ }
/* The function expects that FILENAME_COUNT dump dir element is created by * abrtd after all post-create events are successfully done. Thus if * FILENAME_COUNT element doesn't exist abrtd can consider the dump directory * as unprocessed. * * Relying on content of dump directory has one problem. If a hook provides * FILENAME_COUNT abrtd will consider the dump directory as processed. */ static void mark_unprocessed_dump_dirs_not_reportable(const char *path) { log_notice("Searching for unprocessed dump directories"); DIR *dp = opendir(path); if (!dp) { perror_msg("Can't open directory '%s'", path); return; } struct dirent *dent; while ((dent = readdir(dp)) != NULL) { if (dot_or_dotdot(dent->d_name)) continue; /* skip "." and ".." */ char *full_name = concat_path_file(path, dent->d_name); struct stat stat_buf; if (stat(full_name, &stat_buf) != 0) { perror_msg("Can't access path '%s'", full_name); goto next_dd; } if (S_ISDIR(stat_buf.st_mode) == 0) /* This is expected. The dump location contains some aux files */ goto next_dd; struct dump_dir *dd = dd_opendir(full_name, /*flags*/0); if (dd) { if (!problem_dump_dir_is_complete(dd) && !dd_exist(dd, FILENAME_NOT_REPORTABLE)) { log_warning("Marking '%s' not reportable (no '"FILENAME_COUNT"' item)", full_name); dd_save_text(dd, FILENAME_NOT_REPORTABLE, _("The problem data are " "incomplete. This usually happens when a problem " "is detected while computer is shutting down or " "user is logging out. In order to provide " "valuable problem reports, ABRT will not allow " "you to submit this problem. If you have time and " "want to help the developers in their effort to " "sort out this problem, please contact them directly.")); } dd_close(dd); } next_dd: free(full_name); } closedir(dp); }
int main(int argc, char **argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); const char *dump_dir_name = "."; const char *root_dir = NULL; /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [-v] -d DIR\n" "\n" "Save container metadata" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, }; /* 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('r', NULL, &root_dir, "ROOTDIR" , _("Root directory for running container commands")), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); struct dump_dir *dd = dd_opendir(dump_dir_name, /* for writing */0); if (dd == NULL) xfunc_die(); char *container_cmdline = dd_load_text_ext(dd, FILENAME_CONTAINER_CMDLINE, DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); if (container_cmdline == NULL) error_msg_and_die("The crash didn't occur in container"); if (strstr("/docker ", container_cmdline) == 0) dump_docker_info(dd, root_dir); else if (strstr("/lxc-", container_cmdline) == 0) dump_lxc_info(dd, container_cmdline); else error_msg_and_die("Unsupported container technology"); free(container_cmdline); dd_close(dd); return 0; }
problem_data_t *create_problem_data_for_reporting(const char *dump_dir_name) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return NULL; /* dd_opendir already emitted error msg */ char **exclude_items = build_exclude_vector(getenv("EXCLUDE_FROM_REPORT")); problem_data_t *problem_data = problem_data_new(); problem_data_load_from_dump_dir(problem_data, dd, exclude_items); dd_close(dd); free(exclude_items); return problem_data; }
char* problem_data_save(problem_data_t *pd) { load_abrt_conf(); struct dump_dir *dd = create_dump_dir_from_problem_data_ext(pd, g_settings_dump_location, /*fs owner*/0); char *problem_id = NULL; if (dd) { problem_id = xstrdup(dd->dd_dirname); dd_close(dd); } log_info("problem id: '%s'", problem_id); return problem_id; }
static bool this_is_a_dd(const char *dirname) { /* Prevent get_dirsize_find_largest_dir() from flooding log * with "is not a problem directory" messages * if there are stray dirs in /var/spool/abrt: */ int sv_logmode = logmode; logmode = 0; struct dump_dir *dd = dd_opendir(dirname, /*flags:*/ DD_OPEN_READONLY | DD_FAIL_QUIETLY_ENOENT | DD_FAIL_QUIETLY_EACCES ); dd_close(dd); logmode = sv_logmode; return dd != NULL; }
int main(int argc, char *argv[]) { (void)setlocale(LC_CTYPE, ""); jcl(argv); setup(); (void)signal(SIGINFO, summaryx); (void)signal(SIGINT, terminate); atexit(summary); while (files_cnt--) dd_in(); dd_close(); exit(0); }
int main(int argc, char *argv[]) { jcl(argv); setup(); (void)signal(SIGINFO, summaryx); (void)signal(SIGINT, terminate); atexit(summary); if (cpy_cnt != (size_t)-1) { while (files_cnt--) dd_in(); } dd_close(); exit(0); }
/* Remove dump dir */ int DeleteDebugDump(const char *dump_dir_name, long caller_uid) { /* If doesn't start with "DEBUG_DUMPS_DIR/"... */ if (strncmp(dump_dir_name, DEBUG_DUMPS_DIR"/", strlen(DEBUG_DUMPS_DIR"/")) != 0 /* or contains "/." anywhere (-> might contain ".." component) */ || strstr(dump_dir_name + strlen(DEBUG_DUMPS_DIR), "/.") ) { /* Then refuse to operate on it (someone is attacking us??) */ error_msg("Bad dump directory name '%s', not deleting", dump_dir_name); return MW_ERROR; } struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return MW_NOENT_ERROR; if (caller_uid != 0) /* not called by root */ { char caller_uid_str[sizeof(long) * 3 + 2]; sprintf(caller_uid_str, "%ld", caller_uid); char *uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); /* we assume that the dump_dir can be handled by everyone if uid == NULL * e.g: kerneloops */ if (uid != NULL) { bool uid_matches = (strcmp(uid, caller_uid_str) == 0); free(uid); if (!uid_matches) { dd_close(dd); error_msg("Dump directory '%s' can't be accessed by user with uid %ld", dump_dir_name, caller_uid); return 1; } } } dd_delete(dd); return 0; /* success */ }
static problem_data_t *FillCrashInfo(const char *dump_dir_name) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return NULL; problem_data_t *problem_data = create_problem_data_from_dump_dir(dd); //Not needed anymore? // char *events = list_possible_events(dd, NULL, ""); dd_close(dd); // // add_to_problem_data_ext(problem_data, CD_EVENTS, events, // CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); // free(events); add_to_problem_data_ext(problem_data, CD_DUMPDIR, dump_dir_name, CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); return problem_data; }
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; }
static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *reason) { time_t t = time(NULL); const char *iso_date = iso_date_string(&t); pid_t my_pid = getpid(); char base[sizeof("xorg-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3]; sprintf(base, "xorg-%s-%lu-%u", iso_date, (long)my_pid, g_bt_count); char *path = concat_path_file(debug_dumps_dir, base); struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE); if (dd) { dd_create_basic_files(dd, /*no uid*/(uid_t)-1L, NULL); dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION); dd_save_text(dd, FILENAME_ANALYZER, "abrt-xorg"); dd_save_text(dd, FILENAME_TYPE, "xorg"); dd_save_text(dd, FILENAME_REASON, reason); dd_save_text(dd, FILENAME_BACKTRACE, bt); /* * Reporters usually need component name to file a bug. * It is usually derived from executable. * We _guess_ X server's executable name as a last resort. * Better ideas? */ if (!exe) { exe = "/usr/bin/X"; if (access("/usr/bin/Xorg", X_OK) == 0) exe = "/usr/bin/Xorg"; } dd_save_text(dd, FILENAME_EXECUTABLE, exe); if (!(g_opts & OPT_x)) dd_set_no_owner(dd); dd_close(dd); notify_new_path(path); } free(path); }
GList *list_possible_events_glist(const char *problem_dir_name, const char *pfx) { struct dump_dir *dd = dd_opendir(problem_dir_name, DD_OPEN_READONLY); GList *l = NULL; char *events = list_possible_events(dd, problem_dir_name, pfx); char *start = events; char *end = strchr(events, '\n'); while(end) { *end = '\0'; l = g_list_append(l, xstrdup(start)); start = end + 1; end = strchr(start, '\n'); } dd_close(dd); free(events); return l; }
int run_event_on_problem_data(struct run_event_state *state, problem_data_t *data, const char *event) { state->children_count = 0; struct dump_dir *dd = create_dump_dir_from_problem_data(data, NULL); if (!dd) return -1; char *dir_name = xstrdup(dd->dd_dirname); dd_close(dd); int r = run_event_on_dir_name(state, dir_name, event); g_hash_table_remove_all(data); dd = dd_opendir(dir_name, /*flags:*/ 0); free(dir_name); if (dd) { problem_data_load_from_dump_dir(data, dd, NULL); dd_delete(dd); } return r; }
void ignored_problems_add(ignored_problems_t *set, const char *problem_id) { struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS); if (!dd) { /* We do not consider this as an error because the directory can be * deleted by other programs. This code expects that dd_opendir() * already emitted good explanatory message. This message * explains what the previous failure causes. */ VERB1 log("Can't add problem '%s' to ignored problems:" " can't open the problem", problem_id); return; } char *uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS); char *duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS); dd_close(dd); ignored_problems_add_row(set, problem_id, uuid, duphash); free(duphash); free(uuid); }
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 = _( "& [options] -d DIR\n" "\n" "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating,\n" "and identifies crash function in problem directory DIR" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1 }; /* 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_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; char *component = dd_load_text(dd, FILENAME_COMPONENT); /* Read backtrace */ char *backtrace_str = dd_load_text_ext(dd, FILENAME_BACKTRACE, DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE); if (!backtrace_str) { dd_close(dd); return 1; } /* Compute backtrace hash */ struct sr_location location; sr_location_init(&location); const char *backtrace_str_ptr = backtrace_str; struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_parse(&backtrace_str_ptr, &location); free(backtrace_str); /* Store backtrace hash */ if (!backtrace) { /* * The parser failed. Compute the duphash from the executable * instead of a backtrace. * and component only. This is not supposed to happen often. */ log(_("Backtrace parsing failed for %s"), dump_dir_name); log("%d:%d: %s", location.line, location.column, location.message); struct strbuf *emptybt = strbuf_new(); char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); strbuf_prepend_str(emptybt, executable); free(executable); strbuf_prepend_str(emptybt, component); log_debug("Generating duphash: %s", emptybt->buf); char hash_str[SHA1_RESULT_LEN*2 + 1]; str_to_sha1str(hash_str, emptybt->buf); dd_save_text(dd, FILENAME_DUPHASH, hash_str); /* * Other parts of ABRT assume that if no rating is available, * it is ok to allow reporting of the bug. To be sure no bad * backtrace is reported, rate the backtrace with the lowest * rating. */ dd_save_text(dd, FILENAME_RATING, "0"); strbuf_free(emptybt); free(component); dd_close(dd); /* Report success even if the parser failed, as the backtrace * has been created and rated. The failure is caused by a flaw * in the parser, not in the backtrace. */ return 0; } /* Compute duplication hash. */ struct sr_thread *crash_thread = (struct sr_thread *)sr_gdb_stacktrace_find_crash_thread(backtrace); if (crash_thread) { char *hash_str; if (g_verbose >= 3) { hash_str = sr_thread_get_duphash(crash_thread, 3, component, SR_DUPHASH_NOHASH); log("Generating duphash: %s", hash_str); free(hash_str); } hash_str = sr_thread_get_duphash(crash_thread, 3, component, SR_DUPHASH_NORMAL); dd_save_text(dd, FILENAME_DUPHASH, hash_str); free(hash_str); } else log(_("Crash thread not found")); /* Compute the backtrace rating. */ float quality = sr_gdb_stacktrace_quality_complex(backtrace); const char *rating; if (quality < 0.6f) rating = "0"; else if (quality < 0.7f) rating = "1"; else if (quality < 0.8f) rating = "2"; else if (quality < 0.9f) rating = "3"; else rating = "4"; dd_save_text(dd, FILENAME_RATING, rating); /* Get the function name from the crash frame. */ struct sr_gdb_frame *crash_frame = sr_gdb_stacktrace_get_crash_frame(backtrace); if (crash_frame) { if (crash_frame->function_name && 0 != strcmp(crash_frame->function_name, "??")) { dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name); } sr_gdb_frame_free(crash_frame); } sr_gdb_stacktrace_free(backtrace); dd_close(dd); free(component); return 0; }
static void report_to_bugzilla(const char *dump_dir_name, map_string_h *settings) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) xfunc_die(); /* dd_opendir already emitted error msg */ problem_data_t *problem_data = create_problem_data_from_dump_dir(dd); dd_close(dd); const char *env; const char *login; const char *password; const char *bugzilla_xmlrpc; const char *bugzilla_url; bool ssl_verify; env = getenv("Bugzilla_Login"); login = env ? env : get_map_string_item_or_empty(settings, "Login"); env = getenv("Bugzilla_Password"); password = env ? env : get_map_string_item_or_empty(settings, "Password"); if (!login[0] || !password[0]) error_msg_and_die(_("Empty login or password, please check your configuration")); env = getenv("Bugzilla_BugzillaURL"); bugzilla_url = env ? env : get_map_string_item_or_empty(settings, "BugzillaURL"); if (!bugzilla_url[0]) bugzilla_url = "https://bugzilla.redhat.com"; bugzilla_xmlrpc = xasprintf("%s"XML_RPC_SUFFIX, bugzilla_url); env = getenv("Bugzilla_SSLVerify"); ssl_verify = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SSLVerify")); const char *component = get_problem_item_content_or_NULL(problem_data, FILENAME_COMPONENT); const char *duphash = get_problem_item_content_or_NULL(problem_data, FILENAME_DUPHASH); if (!duphash) error_msg_and_die(_("Essential file '%s' is missing, can't continue.."), FILENAME_DUPHASH); if (!*duphash) error_msg_and_die(_("Essential file '%s' is empty, can't continue.."), FILENAME_DUPHASH); const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE); if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */ release = get_problem_item_content_or_NULL(problem_data, "release"); struct abrt_xmlrpc *client = abrt_xmlrpc_new_client(bugzilla_xmlrpc, ssl_verify); log(_("Logging into Bugzilla at %s"), bugzilla_url); rhbz_login(client, login, password); log(_("Checking for duplicates")); char *product = NULL; char *version = NULL; parse_release_for_bz(release, &product, &version); free(version); xmlrpc_value *result; if (strcmp(product, "Fedora") == 0) result = rhbz_search_duphash(client, component, product, duphash); else result = rhbz_search_duphash(client, component, NULL, duphash); xmlrpc_value *all_bugs = rhbz_get_member("bugs", result); xmlrpc_DECREF(result); if (!all_bugs) error_msg_and_die(_("Missing mandatory member 'bugs'")); int all_bugs_size = rhbz_array_size(all_bugs); // When someone clones bug it has same duphash, so we can find more than 1. // Need to be checked if component is same. VERB3 log("Bugzilla has %i reports with same duphash '%s'", all_bugs_size, duphash); int bug_id = -1, dependent_bug = -1; struct bug_info *bz = NULL; if (all_bugs_size > 0) { bug_id = rhbz_bug_id(all_bugs); xmlrpc_DECREF(all_bugs); bz = rhbz_bug_info(client, bug_id); if (strcmp(bz->bi_product, product) != 0) { dependent_bug = bug_id; /* found something, but its a different product */ free_bug_info(bz); xmlrpc_value *result = rhbz_search_duphash(client, component, product, duphash); xmlrpc_value *all_bugs = rhbz_get_member("bugs", result); xmlrpc_DECREF(result); all_bugs_size = rhbz_array_size(all_bugs); if (all_bugs_size > 0) { bug_id = rhbz_bug_id(all_bugs); bz = rhbz_bug_info(client, bug_id); } xmlrpc_DECREF(all_bugs); } } free(product); if (all_bugs_size == 0) // Create new bug { log(_("Creating a new bug")); bug_id = rhbz_new_bug(client, problem_data, bug_id); log("Adding attachments to bug %i", bug_id); char bug_id_str[sizeof(int)*3 + 2]; sprintf(bug_id_str, "%i", bug_id); rhbz_attachments(client, bug_id_str, problem_data); log(_("Logging out")); rhbz_logout(client); log("Status: NEW %s/show_bug.cgi?id=%u", bugzilla_url, bug_id); abrt_xmlrpc_free_client(client); return; } // decision based on state log(_("Bug is already reported: %i"), bz->bi_id); 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) { if ((strcmp(bz->bi_reporter, login) != 0) && (!g_list_find_custom(bz->bi_cc_list, login, (GCompareFunc)g_strcmp0))) { log(_("Add %s to CC list"), login); rhbz_mail_to_cc(client, bz->bi_id, login); } char *dsc = make_description_comment(problem_data); if (dsc) { const char *package = get_problem_item_content_or_NULL(problem_data, FILENAME_PACKAGE); const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE); if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */ release = get_problem_item_content_or_NULL(problem_data, "release"); const char *arch = get_problem_item_content_or_NULL(problem_data, FILENAME_ARCHITECTURE); const char *is_private = get_problem_item_content_or_NULL(problem_data, "is_private"); char *full_dsc = xasprintf("Package: %s\n" "Architecture: %s\n" "OS Release: %s\n" "%s", package, arch, release, dsc); log(_("Adding new comment to bug %d"), bz->bi_id); free(dsc); int is_priv = is_private && string_to_bool(is_private); rhbz_add_comment(client, bz->bi_id, full_dsc, is_priv); free(full_dsc); } } 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 : "", bugzilla_url, bz->bi_id); dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (dd) { char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", bugzilla_url, bz->bi_id); add_reported_to(dd, msg); free(msg); dd_close(dd); } free_problem_data(problem_data); free_bug_info(bz); abrt_xmlrpc_free_client(client); }
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); }
int main(int argc, char **argv) { abrt_init(argv); const char *dump_dir_name = "."; /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "\b [-v] -d DIR\n" "\n" "Calculates and saves UUID and DUPHASH of python crash dumps" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, }; /* 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_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; char *bt = dd_load_text(dd, FILENAME_BACKTRACE); /* Hash 1st line of backtrace and save it as UUID and DUPHASH */ /* "example.py:1:<module>:ZeroDivisionError: integer division or modulo by zero" */ unsigned char hash_bytes[SHA1_RESULT_LEN]; sha1_ctx_t sha1ctx; sha1_begin(&sha1ctx); const char *bt_end = strchrnul(bt, '\n'); sha1_hash(&sha1ctx, bt, bt_end - bt); sha1_end(&sha1ctx, hash_bytes); free(bt); char hash_str[SHA1_RESULT_LEN*2 + 1]; unsigned len = SHA1_RESULT_LEN; unsigned char *s = hash_bytes; char *d = hash_str; while (len) { *d++ = "0123456789abcdef"[*s >> 4]; *d++ = "0123456789abcdef"[*s & 0xf]; s++; len--; } *d = '\0'; dd_save_text(dd, FILENAME_UUID, hash_str); dd_save_text(dd, FILENAME_DUPHASH, hash_str); dd_close(dd); return 0; }
/* Create a new problem directory from client session. * Caller must ensure that all fields in struct client * are properly filled. */ static int create_problem_dir(GHashTable *problem_info, unsigned pid) { /* Exit if free space is less than 1/4 of MaxCrashReportsSize */ if (g_settings_nMaxCrashReportsSize > 0) { if (low_free_space(g_settings_nMaxCrashReportsSize, g_settings_dump_location)) exit(1); } /* Create temp directory with the problem data. * This directory is renamed to final directory name after * all files have been stored into it. */ gchar *dir_basename = g_hash_table_lookup(problem_info, "basename"); if (!dir_basename) dir_basename = g_hash_table_lookup(problem_info, FILENAME_TYPE); char *path = xasprintf("%s/%s-%s-%u.new", g_settings_dump_location, dir_basename, iso_date_string(NULL), pid); /* This item is useless, don't save it */ g_hash_table_remove(problem_info, "basename"); /* No need to check the path length, as all variables used are limited, * and dd_create() fails if the path is too long. */ struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE); if (!dd) { error_msg_and_die("Error creating problem directory '%s'", path); } dd_create_basic_files(dd, client_uid, NULL); dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION); gpointer gpkey = g_hash_table_lookup(problem_info, FILENAME_CMDLINE); if (!gpkey) { /* Obtain and save the command line. */ char *cmdline = get_cmdline(pid); if (cmdline) { dd_save_text(dd, FILENAME_CMDLINE, cmdline); free(cmdline); } } /* Store id of the user whose application crashed. */ char uid_str[sizeof(long) * 3 + 2]; sprintf(uid_str, "%lu", (long)client_uid); dd_save_text(dd, FILENAME_UID, uid_str); GHashTableIter iter; gpointer gpvalue; g_hash_table_iter_init(&iter, problem_info); while (g_hash_table_iter_next(&iter, &gpkey, &gpvalue)) { dd_save_text(dd, (gchar *) gpkey, (gchar *) gpvalue); } dd_close(dd); /* Not needing it anymore */ g_hash_table_destroy(problem_info); /* Move the completely created problem directory * to final directory. */ char *newpath = xstrndup(path, strlen(path) - strlen(".new")); if (rename(path, newpath) == 0) strcpy(path, newpath); free(newpath); log_notice("Saved problem directory of pid %u to '%s'", pid, path); /* We let the peer know that problem dir was created successfully * _before_ we run potentially long-running post-create. */ printf("HTTP/1.1 201 Created\r\n\r\n"); fflush(NULL); close(STDOUT_FILENO); xdup2(STDERR_FILENO, STDOUT_FILENO); /* paranoia: don't leave stdout fd closed */ /* Trim old problem directories if necessary */ if (g_settings_nMaxCrashReportsSize > 0) { trim_problem_dirs(g_settings_dump_location, g_settings_nMaxCrashReportsSize * (double)(1024*1024), path); } run_post_create(path); /* free(path); */ exit(0); }
static void create_and_send_email( const char *dump_dir_name, map_string_h *settings) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) exit(1); /* error msg is already logged by dd_opendir */ problem_data_t *problem_data = create_problem_data_from_dump_dir(dd); dd_close(dd); char* env; env = getenv("Mailx_Subject"); const char *subject = (env ? env : get_map_string_item_or_NULL(settings, "Subject") ? : "[abrt] full crash report"); env = getenv("Mailx_EmailFrom"); const char *email_from = (env ? env : get_map_string_item_or_NULL(settings, "EmailFrom") ? : "user@localhost"); env = getenv("Mailx_EmailTo"); const char *email_to = (env ? env : get_map_string_item_or_NULL(settings, "EmailTo") ? : "root@localhost"); env = getenv("Mailx_SendBinaryData"); bool send_binary_data = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SendBinaryData")); char **args = NULL; unsigned arg_size = 0; args = append_str_to_vector(args, &arg_size, "/bin/mailx"); char *dsc = make_description_mailx(problem_data); if (send_binary_data) { GHashTableIter iter; char *name; struct problem_item *value; g_hash_table_iter_init(&iter, problem_data); while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { if (value->flags & CD_FLAG_BIN) { args = append_str_to_vector(args, &arg_size, "-a"); args = append_str_to_vector(args, &arg_size, value->content); } } } args = append_str_to_vector(args, &arg_size, "-s"); args = append_str_to_vector(args, &arg_size, subject); args = append_str_to_vector(args, &arg_size, "-r"); args = append_str_to_vector(args, &arg_size, email_from); args = append_str_to_vector(args, &arg_size, email_to); log(_("Sending an email...")); exec_and_feed_input(dsc, args); free(dsc); while (*args) free(*args++); args -= arg_size; free(args); free_problem_data(problem_data); dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (dd) { char *msg = xasprintf("email: %s", email_to); add_reported_to(dd, msg); free(msg); dd_close(dd); } log("Email was sent to: %s", email_to); }