/* returns number of errors */ unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location, const char *analyzer, int flags) { const int oops_cnt = g_list_length(oops_list); unsigned countdown = ABRT_OOPS_MAX_DUMPED_COUNT; /* do not report hundreds of oopses */ log_notice("Saving %u oopses as problem dirs", oops_cnt >= countdown ? countdown : oops_cnt); char *cmdline_str = xmalloc_fopen_fgetline_fclose("/proc/cmdline"); char *fips_enabled = xmalloc_fopen_fgetline_fclose("/proc/sys/crypto/fips_enabled"); char *proc_modules = xmalloc_open_read_close("/proc/modules", /*maxsize:*/ NULL); char *suspend_stats = xmalloc_open_read_close("/sys/kernel/debug/suspend_stats", /*maxsize:*/ NULL); time_t t = time(NULL); const char *iso_date = iso_date_string(&t); /* dump should be readable by all if we're run with -x */ uid_t my_euid = (uid_t)-1L; mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH; /* and readable only for the owner otherwise */ if (!(flags & ABRT_OOPS_WORLD_READABLE)) { mode = DEFAULT_DUMP_DIR_MODE; my_euid = geteuid(); } pid_t my_pid = getpid(); unsigned idx = 0; unsigned errors = 0; while (idx < oops_cnt) { char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3]; sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx); char *path = concat_path_file(dump_location, base); struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode); if (dd) { dd_create_basic_files(dd, /*uid:*/ my_euid, NULL); abrt_oops_save_data_in_dump_dir(dd, (char*)g_list_nth_data(oops_list, idx++), proc_modules); dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION); dd_save_text(dd, FILENAME_ANALYZER, "abrt-oops"); dd_save_text(dd, FILENAME_TYPE, "Kerneloops"); if (cmdline_str) dd_save_text(dd, FILENAME_CMDLINE, cmdline_str); if (proc_modules) dd_save_text(dd, "proc_modules", proc_modules); if (fips_enabled && strcmp(fips_enabled, "0") != 0) dd_save_text(dd, "fips_enabled", fips_enabled); if (suspend_stats) dd_save_text(dd, "suspend_stats", suspend_stats); dd_close(dd); notify_new_path(path); } else errors++; free(path); if (--countdown == 0) break; if (dd && (flags & ABRT_OOPS_THROTTLE_CREATION)) if (abrt_oops_signaled_sleep(1) > 0) break; } free(cmdline_str); free(proc_modules); free(fips_enabled); free(suspend_stats); return errors; }
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 = _( "& [-vusoxm] [-d DIR]/[-D] [FILE]\n" "\n" "Extract oops from FILE (or standard input)" ); enum { OPT_v = 1 << 0, OPT_s = 1 << 1, OPT_o = 1 << 2, OPT_d = 1 << 3, OPT_D = 1 << 4, OPT_u = 1 << 5, OPT_x = 1 << 6, OPT_t = 1 << 7, OPT_m = 1 << 8, }; char *problem_dir = NULL; char *dump_location = 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 oopses on standard output")), /* oopses don't contain any sensitive info, and even * the old koops app was showing the oopses to all users */ OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")), OPT_BOOL( 'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")), OPT_STRING('u', NULL, &problem_dir, "PROBLEM", _("Save the extracted information in PROBLEM")), 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_BOOL( 'm', NULL, NULL, _("Print search string(s) to stdout and exit")), 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_m) { char *oops_string_filter_regex = abrt_oops_string_filter_regex(); if (oops_string_filter_regex) { regex_t filter_re; if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0) perror_msg_and_die(_("Failed to compile regex")); const regex_t *filter[] = { &filter_re, NULL }; koops_print_suspicious_strings_filtered(filter); regfree(&filter_re); free(oops_string_filter_regex); } else koops_print_suspicious_strings(); return 1; } 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 oops_utils_flags = 0; if ((opts & OPT_x)) oops_utils_flags |= ABRT_OOPS_WORLD_READABLE; if ((opts & OPT_t)) oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION; if ((opts & OPT_o)) oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT; argv += optind; if (argv[0]) xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO); GList *oops_list = NULL; scan_syslog_file(&oops_list, STDIN_FILENO); unsigned errors = 0; if (opts & OPT_u) { log_warning("Updating problem directory"); switch (g_list_length(oops_list)) { case 0: { error_msg(_("Can't update the problem: no oops found")); errors = 1; break; } default: { log_notice(_("More oopses found: process only the first one")); } /* falls trought */ case 1: { struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0); if (dd) { abrt_oops_save_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL); dd_close(dd); } } } } else errors = abrt_oops_process_list(oops_list, dump_location, ABRT_DUMP_OOPS_ANALYZER, oops_utils_flags); list_free_with_free(oops_list); //oops_list = NULL; return errors; }