/* Callback called by glib main loop when a client connects to ABRT's socket. */ static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused) { kill_idle_timeout(); load_abrt_conf(); int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL); if (socket == -1) { perror_msg("accept"); goto server_socket_finitio; } log_notice("New client connected"); fflush(NULL); /* paranoia */ int pipefd[2]; xpipe(pipefd); pid_t pid = fork(); if (pid < 0) { perror_msg("fork"); close(socket); close(pipefd[0]); close(pipefd[1]); goto server_socket_finitio; } if (pid == 0) /* child */ { xdup2(socket, STDIN_FILENO); xdup2(socket, STDOUT_FILENO); close(socket); close(pipefd[0]); xmove_fd(pipefd[1], STDERR_FILENO); char *argv[3]; /* abrt-server [-s] NULL */ char **pp = argv; *pp++ = (char*)"abrt-server"; if (logmode & LOGMODE_JOURNAL) *pp++ = (char*)"-s"; *pp = NULL; execvp(argv[0], argv); perror_msg_and_die("Can't execute '%s'", argv[0]); } /* parent */ close(socket); close(pipefd[1]); add_abrt_server_proc(pid, pipefd[0]); server_socket_finitio: start_idle_timeout(); return TRUE; }
int cmd_list(int argc, const char **argv) { const char *program_usage_string = _( "& list [options]" ); int opt_not_reported = 0; int opt_detailed = 0; int opt_since = 0; int opt_until = 0; struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL('n', "not-reported" , &opt_not_reported, _("List only not-reported problems")), /* deprecate -d option with --pretty=full*/ OPT_BOOL('d', "detailed" , &opt_detailed, _("Show detailed report")), OPT_INTEGER('s', "since" , &opt_since, _("List only the problems more recent than specified timestamp")), OPT_INTEGER('u', "until" , &opt_until, _("List only the problems older than specified timestamp")), OPT_END() }; parse_opts(argc, (char **)argv, program_options, program_usage_string); vector_of_problem_data_t *ci = fetch_crash_infos(); if (ci == NULL) return 1; g_ptr_array_sort_with_data(ci, &cmp_problem_data, (char *) FILENAME_LAST_OCCURRENCE); #if SUGGEST_AUTOREPORTING != 0 const bool output = #endif print_crash_list(ci, opt_detailed, opt_not_reported, opt_since, opt_until, CD_TEXT_ATT_SIZE_BZ); free_vector_of_problem_data(ci); #if SUGGEST_AUTOREPORTING != 0 load_abrt_conf(); if (!g_settings_autoreporting) { if (output) putc('\n', stderr); fprintf(stderr, _("The Autoreporting feature is disabled. Please consider enabling it by issuing\n" "'abrt-auto-reporting enabled' as a user with root privileges\n")); } #endif return 0; }
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 void handle_inotify_cb(struct abrt_inotify_watch *watch, struct inotify_event *event, gpointer ptr_unused) { kill_idle_timeout(); if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF) { log_warning("Recreating deleted dump location '%s'", g_settings_dump_location); load_abrt_conf(); sanitize_dump_dir_rights(); abrt_inotify_watch_reset(watch, g_settings_dump_location, IN_DUMP_LOCATION_FLAGS); } start_idle_timeout(); }
int cmd_report(int argc, const char **argv) { const char *program_usage_string = _( "& report [options] DIR..." ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_u = 1 << 2, }; struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL('d', "delete", NULL, _("Remove PROBLEM_DIR after reporting")), OPT_BOOL('u', "unsafe", NULL, _("Ignore security checks to be able to " "report all problems")), OPT_END() }; unsigned opts = parse_opts(argc, (char **)argv, program_options, program_usage_string); argv += optind; if (!argv[0]) show_usage_and_die(program_usage_string, program_options); export_abrt_envvars(/*prog_prefix:*/ 0); load_abrt_conf(); free_abrt_conf_data(); int report_flags = 0; if (opts & OPT_d) report_flags |= CMD_REPORT_REMOVE; if (opts & OPT_u) report_flags |= CMD_REPORT_UNSAFE; return _cmd_report(argv, report_flags); }
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]" ); enum { OPT_v = 1 << 0, OPT_u = 1 << 1, OPT_s = 1 << 2, OPT_p = 1 << 3, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_INTEGER('u', NULL, &client_uid, _("Use NUM as client uid")), OPT_BOOL( 's', NULL, NULL , _("Log to syslog")), OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(opts & OPT_p); msg_prefix = xasprintf("%s[%u]", g_progname, getpid()); if (opts & OPT_s) { logmode = LOGMODE_JOURNAL; } /* Set up timeout handling */ /* Part 1 - need this to make SIGALRM interrupt syscalls * (as opposed to restarting them): I want read syscall to be interrupted */ struct sigaction sa; /* sa.sa_flags.SA_RESTART bit is clear: make signal interrupt syscalls */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = dummy_handler; /* pity, SIG_DFL won't do */ sigaction(SIGALRM, &sa, NULL); /* Part 2 - set the timeout per se */ alarm(TIMEOUT); if (client_uid == (uid_t)-1L) { /* Get uid of the connected client */ struct ucred cr; socklen_t crlen = sizeof(cr); if (0 != getsockopt(STDIN_FILENO, SOL_SOCKET, SO_PEERCRED, &cr, &crlen)) perror_msg_and_die("getsockopt(SO_PEERCRED)"); if (crlen != sizeof(cr)) error_msg_and_die("%s: bad crlen %d", "getsockopt(SO_PEERCRED)", (int)crlen); client_uid = cr.uid; } load_abrt_conf(); int r = perform_http_xact(); if (r == 0) r = 200; free_abrt_conf_data(); printf("HTTP/1.1 %u \r\n\r\n", r); return (r >= 400); /* Error if 400+ */ }
int main(int argc, char **argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); const char *program_usage_string = _( "& [-v -i -n INCREMENT] -e|--event EVENT DIR..." ); char *event_name = NULL; int interactive = 0; /* must be _int_, OPT_BOOL expects that! */ int nice_incr = 0; struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_STRING('e', "event" , &event_name, "EVENT", _("Run EVENT on DIR")), OPT_BOOL('i', "interactive" , &interactive, _("Communicate directly to the user")), OPT_INTEGER('n', "nice" , &nice_incr, _("Increment the nice value by INCREMENT")), OPT_END() }; parse_opts(argc, argv, program_options, program_usage_string); argv += optind; if (!*argv || !event_name) show_usage_and_die(program_usage_string, program_options); load_abrt_conf(); const char *const opt_env_nice = getenv("ABRT_EVENT_NICE"); if (opt_env_nice != NULL && opt_env_nice[0] != '\0') { log_debug("Using ABRT_EVENT_NICE=%s to increment the nice value", opt_env_nice); nice_incr = xatoi(opt_env_nice); } if (nice_incr != 0) { log_debug("Incrementing the nice value by %d", nice_incr); const int ret = nice(nice_incr); if (ret == -1) perror_msg_and_die("Failed to increment the nice value"); } bool post_create = (strcmp(event_name, "post-create") == 0); char *dump_dir_name = NULL; while (*argv) { dump_dir_name = xstrdup(*argv++); int i = strlen(dump_dir_name); while (--i >= 0) if (dump_dir_name[i] != '/') break; dump_dir_name[++i] = '\0'; struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ DD_OPEN_READONLY); if (!dd) return 1; uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT); dd_close(dd); struct run_event_state *run_state = new_run_event_state(); if (!interactive) make_run_event_state_forwarding(run_state); run_state->logging_callback = do_log; if (post_create) run_state->post_run_callback = is_crash_a_dup; int r = run_event_on_dir_name(run_state, dump_dir_name, event_name); const bool no_action_for_event = (r == 0 && run_state->children_count == 0); free_run_event_state(run_state); /* Needed only if is_crash_a_dup() was called, but harmless * even if it wasn't: */ dup_uuid_fini(); dup_corebt_fini(); if (no_action_for_event) error_msg_and_die("No actions are found for event '%s'", event_name); //TODO: consider this case: // new dump is created, post-create detects that it is a dup, // but then load_crash_info(dup_name) *FAILS*. // In this case, we later delete damaged dup_name (right?) // but new dump never gets its FILENAME_COUNT set! /* Is crash a dup? (In this case, is_crash_a_dup() should have * aborted "post-create" event processing as soon as it saw uuid * and determined that there is another crash with same uuid. * In this case it sets crash_dump_dup_name) */ if (crash_dump_dup_name) error_msg_and_die("DUP_OF_DIR: %s", crash_dump_dup_name); /* Was there error on one of processing steps in run_event? */ if (r != 0) return r; /* yes */ free(dump_dir_name); dump_dir_name = NULL; } /* exit 0 means, that there is no duplicate of dump-dir */ return 0; }
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 = _( "& [-vsoxm] [-d DIR]/[-D] [FILE]\n" "\n" "Extract Xorg crash from FILE (or standard input)" ); /* Keep OPT_z enums 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 crash data on standard output")), OPT_STRING('d', NULL, &debug_dumps_dir, "DIR", _("Create 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( 'm', NULL, NULL, _("Print search string(s) to stdout and exit")), OPT_END() }; unsigned opts = g_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) { puts("Backtrace"); return 0; } if (opts & OPT_D) { if (opts & OPT_d) show_usage_and_die(program_usage_string, program_options); load_abrt_conf(); debug_dumps_dir = g_settings_dump_location; g_settings_dump_location = NULL; free_abrt_conf_data(); } argv += optind; if (argv[0]) xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO); char *line; while ((line = xmalloc_fgetline(stdin)) != NULL) { char *p = skip_pfx(line); if (strcmp(p, "Backtrace:") == 0) { free(line); g_bt_count++; process_xorg_bt(); continue; } free(line); } /* If we are run by a log watcher, this delays log rescan * (because log watcher waits to us to terminate) * and possibly prevents dreaded "abrt storm". */ if (opts & (OPT_d|OPT_D)) { if (g_bt_count > MAX_DUMPED_DD_COUNT) sleep(g_bt_count - MAX_DUMPED_DD_COUNT); } return 0; }
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; }
int main(int argc, char** argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); int parent_pid = getpid(); const char *program_usage_string = _( "& [options]" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_s = 1 << 2, // TODO: get rid of -t NUM, it is no longer useful since dbus is moved to a separate tool OPT_t = 1 << 3, OPT_p = 1 << 4, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL( 'd', NULL, NULL , _("Do not daemonize")), OPT_BOOL( 's', NULL, NULL , _("Log to syslog even with -d")), OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")), OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(opts & OPT_p); #if 0 /* We no longer use dbus */ /* When dbus daemon starts us, it doesn't set PATH * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE). * In this case, set something sane: */ const char *env_path = getenv("PATH"); if (!env_path || !env_path[0]) putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin"); #endif unsetenv("ABRT_SYSLOG"); msg_prefix = g_progname; /* for log_warning(), error_msg() and such */ if (getuid() != 0) error_msg_and_die("Must be run as root"); if (opts & OPT_s) start_logging(); xpipe(s_signal_pipe); close_on_exec_on(s_signal_pipe[0]); close_on_exec_on(s_signal_pipe[1]); ndelay_on(s_signal_pipe[0]); /* I/O should not block - */ ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */ signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGCHLD, handle_signal); GIOChannel* channel_signal = NULL; guint channel_id_signal_event = 0; bool pidfile_created = false; struct abrt_inotify_watch *aiw = NULL; int ret = 1; /* Initialization */ log_notice("Loading settings"); if (load_abrt_conf() != 0) goto init_error; /* Moved before daemonization because parent waits for signal from daemon * only for short period and time consumed by * mark_unprocessed_dump_dirs_not_reportable() is slightly unpredictable. */ sanitize_dump_dir_rights(); mark_unprocessed_dump_dirs_not_reportable(g_settings_dump_location); /* Daemonize unless -d */ if (!(opts & OPT_d)) { /* forking to background */ fflush(NULL); /* paranoia */ pid_t pid = fork(); if (pid < 0) { perror_msg_and_die("fork"); } if (pid > 0) { /* Parent */ /* Wait for child to notify us via SIGTERM that it feels ok */ int i = 20; /* 2 sec */ while (s_sig_caught == 0 && --i) { usleep(100 * 1000); } if (s_sig_caught == SIGTERM) { exit(0); } if (s_sig_caught) { error_msg_and_die("Failed to start: got sig %d", s_sig_caught); } error_msg_and_die("Failed to start: timeout waiting for child"); } /* Child (daemon) continues */ if (setsid() < 0) perror_msg_and_die("setsid"); if (g_verbose == 0 && logmode != LOGMODE_JOURNAL) start_logging(); } log_notice("Creating glib main loop"); s_main_loop = g_main_loop_new(NULL, FALSE); /* Watching 'g_settings_dump_location' for delete self * because hooks expects that the dump location exists if abrtd is running */ aiw = abrt_inotify_watch_init(g_settings_dump_location, IN_DUMP_LOCATION_FLAGS, handle_inotify_cb, /*user data*/NULL); /* Add an event source which waits for INT/TERM signal */ log_notice("Adding signal pipe watch to glib main loop"); channel_signal = abrt_gio_channel_unix_new(s_signal_pipe[0]); channel_id_signal_event = add_watch_or_die(channel_signal, G_IO_IN | G_IO_PRI | G_IO_HUP, handle_signal_cb); guint name_id = 0; /* Mark the territory */ log_notice("Creating pid file"); if (create_pidfile() != 0) goto init_error; pidfile_created = true; /* Open socket to receive new problem data (from python etc). */ dumpsocket_init(); /* Inform parent that we initialized ok */ if (!(opts & OPT_d)) { log_notice("Signalling parent"); kill(parent_pid, SIGTERM); if (logmode != LOGMODE_JOURNAL) start_logging(); } /* Only now we want signal pipe to work */ s_signal_pipe_write = s_signal_pipe[1]; /* Own a name on D-Bus */ name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, ABRTD_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); start_idle_timeout(); /* Enter the event loop */ log_debug("Init complete, entering main loop"); g_main_loop_run(s_main_loop); ret = 0; /* Jump to exit */ goto cleanup; init_error: /* Initialization error */ error_msg("Error while initializing daemon"); /* Inform parent that initialization failed */ if (!(opts & OPT_d)) kill(parent_pid, SIGINT); cleanup: if (name_id > 0) g_bus_unown_name (name_id); /* Error or INT/TERM. Clean up, in reverse order. * Take care to not undo things we did not do. */ dumpsocket_shutdown(); if (pidfile_created) unlink(VAR_RUN_PIDFILE); if (channel_id_signal_event > 0) g_source_remove(channel_id_signal_event); if (channel_signal) g_io_channel_unref(channel_signal); abrt_inotify_watch_destroy(aiw); if (s_main_loop) g_main_loop_unref(s_main_loop); free_abrt_conf_data(); if (s_sig_caught && s_sig_caught != SIGCHLD) { /* We use TERM to stop abrtd, so not printing out error message. */ if (s_sig_caught != SIGTERM) { error_msg("Got signal %d, exiting", s_sig_caught); signal(s_sig_caught, SIG_DFL); raise(s_sig_caught); } } /* Exiting */ log_notice("Exiting"); return ret; }
/* Queueing the process will also lead to cleaning up the dump location. */ static void queue_post_craete_process(struct abrt_server_proc *proc) { load_abrt_conf(); struct abrt_server_proc *running = s_dir_queue == NULL ? NULL : (struct abrt_server_proc *)s_dir_queue->data; if (g_settings_nMaxCrashReportsSize == 0) goto consider_processing; const char *full_path_ignored = running != NULL ? running->dirname : proc->dirname; const char *ignored = strrchr(full_path_ignored, '/'); if (NULL == ignored) /* Paranoia, this should not happen. */ ignored = full_path_ignored; else /* Move behind '/' */ ++ignored; char *worst_dir = NULL; const double max_size = 1024 * 1024 * g_settings_nMaxCrashReportsSize; while (get_dirsize_find_largest_dir(g_settings_dump_location, &worst_dir, ignored) >= max_size && worst_dir) { const char *kind = "old"; GList *proc_of_deleted_item = NULL; if (proc != NULL && strcmp(worst_dir, proc->dirname) == 0) { kind = "new"; stop_abrt_server(proc); proc = NULL; } else if ((proc_of_deleted_item = g_list_find_custom(s_dir_queue, worst_dir, (GCompareFunc)abrt_server_compare_dirname))) { kind = "unprocessed"; struct abrt_server_proc *removed_proc = (struct abrt_server_proc *)proc_of_deleted_item->data; s_dir_queue = g_list_delete_link(s_dir_queue, proc_of_deleted_item); stop_abrt_server(removed_proc); } log_warning("Size of '%s' >= %u MB (MaxCrashReportsSize), deleting %s directory '%s'", g_settings_dump_location, g_settings_nMaxCrashReportsSize, kind, worst_dir); char *deleted = concat_path_file(g_settings_dump_location, worst_dir); free(worst_dir); worst_dir = NULL; struct dump_dir *dd = dd_opendir(deleted, DD_FAIL_QUIETLY_ENOENT); if (dd != NULL) dd_delete(dd); free(deleted); } consider_processing: /* If the process survived cleaning up the dump location, append it to the * post-create queue. */ if (proc != NULL) s_dir_queue = g_list_append(s_dir_queue, proc); /* If there were no running post-crate process before we added the * currently handled process to the post-create queue, start processing of * the currently handled process. */ if (running == NULL) notify_next_post_create_process(NULL/*finished*/); }
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; }