|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2011 ABRT Team
|
|
Packit |
8ea169 |
Copyright (C) 2011 RedHat inc.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
8ea169 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
8ea169 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
#include <satyr/thread.h>
|
|
Packit |
8ea169 |
#include <satyr/stacktrace.h>
|
|
Packit |
8ea169 |
#include <satyr/distance.h>
|
|
Packit |
8ea169 |
#include <satyr/abrt.h>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "libabrt.h"
|
|
Packit |
8ea169 |
#include <libreport/run_event.h>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* 70 % similarity */
|
|
Packit |
8ea169 |
#define BACKTRACE_DUP_THRESHOLD 0.3
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static char *uid = NULL;
|
|
Packit |
8ea169 |
static char *uuid = NULL;
|
|
Packit |
8ea169 |
static struct sr_stacktrace *corebt = NULL;
|
|
Packit |
8ea169 |
static char *type = NULL;
|
|
Packit |
8ea169 |
static char *executable = NULL;
|
|
Packit |
8ea169 |
static char *crash_dump_dup_name = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dup_corebt_fini(void);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static char* load_backtrace(const struct dump_dir *dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *filename = FILENAME_BACKTRACE;
|
|
Packit |
8ea169 |
if (strcmp(type, "CCpp") == 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
filename = FILENAME_CORE_BACKTRACE;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return dd_load_text_ext(dd, filename,
|
|
Packit |
8ea169 |
DD_FAIL_QUIETLY_ENOENT|DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int core_backtrace_is_duplicate(struct sr_stacktrace *bt1,
|
|
Packit |
8ea169 |
const char *bt2_text)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct sr_thread *thread1 = sr_stacktrace_find_crash_thread(bt1);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (thread1 == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("New stacktrace has no crash thread, disabling core stacktrace deduplicate");
|
|
Packit |
8ea169 |
dup_corebt_fini();
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int result;
|
|
Packit |
8ea169 |
char *error_message;
|
|
Packit |
8ea169 |
struct sr_stacktrace *bt2 = sr_stacktrace_parse(sr_abrt_type_from_type(type),
|
|
Packit |
8ea169 |
bt2_text, &error_message);
|
|
Packit |
8ea169 |
if (bt2 == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to parse backtrace, considering it not duplicate: %s", error_message);
|
|
Packit |
8ea169 |
free(error_message);
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct sr_thread *thread2 = sr_stacktrace_find_crash_thread(bt2);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (thread2 == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to get crash thread, considering it not duplicate");
|
|
Packit |
8ea169 |
result = 0;
|
|
Packit |
8ea169 |
goto end;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int length2 = sr_thread_frame_count(thread2);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (length2 <= 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Core backtrace has zero frames, considering it not duplicate");
|
|
Packit |
8ea169 |
result = 0;
|
|
Packit |
8ea169 |
goto end;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
float distance = sr_distance(SR_DISTANCE_DAMERAU_LEVENSHTEIN, thread1, thread2);
|
|
Packit |
8ea169 |
log_info("Distance between backtraces: %f", distance);
|
|
Packit |
8ea169 |
result = (distance <= BACKTRACE_DUP_THRESHOLD);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
end:
|
|
Packit |
8ea169 |
sr_stacktrace_free(bt2);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return result;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dup_uuid_init(const struct dump_dir *dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (uuid)
|
|
Packit |
8ea169 |
return; /* we already loaded it, don't do it again */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
uuid = dd_load_text_ext(dd, FILENAME_UUID,
|
|
Packit |
8ea169 |
DD_FAIL_QUIETLY_ENOENT + DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int dup_uuid_compare(const struct dump_dir *dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *dd_uuid;
|
|
Packit |
8ea169 |
int different;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!uuid)
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* don't do uuid-based check on crashes that have backtrace available (and
|
|
Packit |
8ea169 |
* nonempty)
|
|
Packit |
8ea169 |
* XXX: this relies on the fact that backtrace is created in the same event
|
|
Packit |
8ea169 |
* as UUID
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
if (corebt)
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dd_uuid = dd_load_text_ext(dd, FILENAME_UUID, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
different = strcmp(uuid, dd_uuid);
|
|
Packit |
8ea169 |
free(dd_uuid);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!different)
|
|
Packit |
8ea169 |
log_notice("Duplicate: UUID");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return !different;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dup_uuid_fini(void)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
free(uuid);
|
|
Packit |
8ea169 |
uuid = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dup_corebt_init(const struct dump_dir *dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (corebt)
|
|
Packit |
8ea169 |
return; /* already loaded */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *corebt_text = load_backtrace(dd);
|
|
Packit |
8ea169 |
if (!corebt_text)
|
|
Packit |
8ea169 |
return; /* no backtrace */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
enum sr_report_type report_type = sr_abrt_type_from_type(type);
|
|
Packit |
8ea169 |
if (report_type == SR_REPORT_INVALID)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Can't load stacktrace because of unsupported type: %s",
|
|
Packit |
8ea169 |
type);
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* sr_stacktrace_parse moves the pointer */
|
|
Packit |
8ea169 |
char *error_message;
|
|
Packit |
8ea169 |
corebt = sr_stacktrace_parse(report_type, corebt_text, &error_message);
|
|
Packit |
8ea169 |
if (!corebt)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Failed to load core stacktrace: %s", error_message);
|
|
Packit |
8ea169 |
free(error_message);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(corebt_text);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static int dup_corebt_compare(const struct dump_dir *dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!corebt)
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int isdup;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *dd_corebt = load_backtrace(dd);
|
|
Packit |
8ea169 |
if (!dd_corebt)
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
isdup = core_backtrace_is_duplicate(corebt, dd_corebt);
|
|
Packit |
8ea169 |
free(dd_corebt);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (isdup)
|
|
Packit |
8ea169 |
log_notice("Duplicate: core backtrace");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return isdup;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void dup_corebt_fini(void)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
sr_stacktrace_free(corebt);
|
|
Packit |
8ea169 |
corebt = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* This function is run after each post-create event is finished (there may be
|
|
Packit |
8ea169 |
* multiple such events).
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* It first checks if there is CORE_BACKTRACE or UUID item in the dump dir
|
|
Packit |
8ea169 |
* we are processing.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* If there is a CORE_BACKTRACE, it iterates over all other dump
|
|
Packit |
8ea169 |
* directories and computes similarity to their core backtraces (if any).
|
|
Packit |
8ea169 |
* If one of them is similar enough to be considered duplicate, the function
|
|
Packit |
8ea169 |
* saves the path to the dump directory in question and returns 1 to indicate
|
|
Packit |
8ea169 |
* that we have indeed found a duplicate of currently processed dump directory.
|
|
Packit |
8ea169 |
* No more events are processed and program prints the path to the other
|
|
Packit |
8ea169 |
* directory and returns failure.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* If there is an UUID item (and no core backtrace), the function again
|
|
Packit |
8ea169 |
* iterates over all other dump directories and compares this UUID to their
|
|
Packit |
8ea169 |
* UUID. If there is a match, the path to the duplicate is saved and 1 is returned.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* If duplicate is not found as described above, the function returns 0 and we
|
|
Packit |
8ea169 |
* either process remaining events if there are any, or successfully terminate
|
|
Packit |
8ea169 |
* processing of the current dump directory.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
static int is_crash_a_dup(const char *dump_dir_name, void *param)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int retval = 0; /* defaults to no dup found, "run_event, please continue iterating" */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
return 0; /* wtf? (error, but will be handled elsewhere later) */
|
|
Packit |
8ea169 |
free(type);
|
|
Packit |
8ea169 |
type = dd_load_text(dd, FILENAME_TYPE);
|
|
Packit |
8ea169 |
free(executable);
|
|
Packit |
8ea169 |
executable = dd_load_text_ext(dd, FILENAME_EXECUTABLE, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
char *container_id = dd_load_text_ext(dd, FILENAME_CONTAINER_ID, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
dup_uuid_init(dd);
|
|
Packit |
8ea169 |
dup_corebt_init(dd);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* dump_dir_name can be relative */
|
|
Packit |
8ea169 |
dump_dir_name = realpath(dump_dir_name, NULL);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
DIR *dir = opendir(g_settings_dump_location);
|
|
Packit |
8ea169 |
if (dir == NULL)
|
|
Packit |
8ea169 |
goto end;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Scan crash dumps looking for a dup */
|
|
Packit |
8ea169 |
//TODO: explain why this is safe wrt concurrent runs
|
|
Packit |
8ea169 |
struct dirent *dent;
|
|
Packit |
8ea169 |
while ((dent = readdir(dir)) != NULL && crash_dump_dup_name == NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (dot_or_dotdot(dent->d_name))
|
|
Packit |
8ea169 |
continue; /* skip "." and ".." */
|
|
Packit |
8ea169 |
const char *ext = strrchr(dent->d_name, '.');
|
|
Packit |
8ea169 |
if (ext && strcmp(ext, ".new") == 0)
|
|
Packit |
8ea169 |
continue; /* skip anything named "<dirname>.new" */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
dd = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *tmp_concat_path = concat_path_file(g_settings_dump_location, dent->d_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *dump_dir_name2 = realpath(tmp_concat_path, NULL);
|
|
Packit |
8ea169 |
if (g_verbose > 1 && !dump_dir_name2)
|
|
Packit |
8ea169 |
perror_msg("realpath(%s)", tmp_concat_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(tmp_concat_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (!dump_dir_name2)
|
|
Packit |
8ea169 |
continue;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *dd_uid = NULL, *dd_type = NULL;
|
|
Packit |
8ea169 |
char *dd_executable = NULL, *dd_container_id = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (strcmp(dump_dir_name, dump_dir_name2) == 0)
|
|
Packit |
8ea169 |
goto next; /* we are never a dup of ourself */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int sv_logmode = logmode;
|
|
Packit |
8ea169 |
/* Silently ignore any error in the silent log level. */
|
|
Packit |
8ea169 |
logmode = g_verbose == 0 ? 0 : sv_logmode;
|
|
Packit |
8ea169 |
dd = dd_opendir(dump_dir_name2, /*flags:*/ DD_FAIL_QUIETLY_ENOENT | DD_OPEN_READONLY);
|
|
Packit |
8ea169 |
logmode = sv_logmode;
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
goto next;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* problems from different containers are not duplicates */
|
|
Packit |
8ea169 |
if (container_id != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
dd_container_id = dd_load_text_ext(dd, FILENAME_CONTAINER_ID, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
if (dd_container_id != NULL && strcmp(container_id, dd_container_id) != 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
goto next;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* crashes of different users are not considered duplicates */
|
|
Packit |
8ea169 |
dd_uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
if (strcmp(uid, dd_uid))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
goto next;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* different crash types are not duplicates */
|
|
Packit |
8ea169 |
dd_type = dd_load_text_ext(dd, FILENAME_TYPE, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
if (strcmp(type, dd_type))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
goto next;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* different executables are not duplicates */
|
|
Packit |
8ea169 |
dd_executable = dd_load_text_ext(dd, FILENAME_EXECUTABLE, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
if ( (executable != NULL && dd_executable == NULL)
|
|
Packit |
8ea169 |
|| (executable == NULL && dd_executable != NULL)
|
|
Packit |
8ea169 |
|| ((executable != NULL && dd_executable != NULL)
|
|
Packit |
8ea169 |
&& strcmp(executable, dd_executable) != 0))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
goto next;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (dup_uuid_compare(dd)
|
|
Packit |
8ea169 |
|| dup_corebt_compare(dd)
|
|
Packit |
8ea169 |
) {
|
|
Packit |
8ea169 |
crash_dump_dup_name = dump_dir_name2;
|
|
Packit |
8ea169 |
dump_dir_name2 = NULL;
|
|
Packit |
8ea169 |
retval = 1; /* "run_event, please stop iterating" */
|
|
Packit |
8ea169 |
/* sonce crash_dump_dup_name != NULL now, we exit the loop */
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
next:
|
|
Packit |
8ea169 |
free(dump_dir_name2);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
free(dd_uid);
|
|
Packit |
8ea169 |
free(dd_type);
|
|
Packit |
8ea169 |
free(dd_container_id);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
closedir(dir);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
end:
|
|
Packit |
8ea169 |
free((char*)dump_dir_name);
|
|
Packit |
8ea169 |
free(container_id);
|
|
Packit |
8ea169 |
return retval;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static char *do_log(char *log_line, void *param)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* We pipe output of events to our log.
|
|
Packit |
8ea169 |
* Otherwise, errors on post-create result in
|
|
Packit |
8ea169 |
* "Corrupted or bad dump DIR, deleting" without adequate explanation why.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
log_warning("%s", log_line);
|
|
Packit |
8ea169 |
return log_line;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int main(int argc, char **argv)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* I18n */
|
|
Packit |
8ea169 |
setlocale(LC_ALL, "");
|
|
Packit |
8ea169 |
#if ENABLE_NLS
|
|
Packit |
8ea169 |
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
Packit |
8ea169 |
textdomain(PACKAGE);
|
|
Packit |
8ea169 |
#endif
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_init(argv);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *program_usage_string = _(
|
|
Packit |
8ea169 |
"& [-v -i -n INCREMENT] -e|--event EVENT DIR..."
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *event_name = NULL;
|
|
Packit |
8ea169 |
int interactive = 0; /* must be _int_, OPT_BOOL expects that! */
|
|
Packit |
8ea169 |
int nice_incr = 0;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct options program_options[] = {
|
|
Packit |
8ea169 |
OPT__VERBOSE(&g_verbose),
|
|
Packit |
8ea169 |
OPT_STRING('e', "event" , &event_name, "EVENT", _("Run EVENT on DIR")),
|
|
Packit |
8ea169 |
OPT_BOOL('i', "interactive" , &interactive, _("Communicate directly to the user")),
|
|
Packit |
8ea169 |
OPT_INTEGER('n', "nice" , &nice_incr, _("Increment the nice value by INCREMENT")),
|
|
Packit |
8ea169 |
OPT_END()
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
parse_opts(argc, argv, program_options, program_usage_string);
|
|
Packit |
8ea169 |
argv += optind;
|
|
Packit |
8ea169 |
if (!*argv || !event_name)
|
|
Packit |
8ea169 |
show_usage_and_die(program_usage_string, program_options);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
load_abrt_conf();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const char *const opt_env_nice = getenv("ABRT_EVENT_NICE");
|
|
Packit |
8ea169 |
if (opt_env_nice != NULL && opt_env_nice[0] != '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Using ABRT_EVENT_NICE=%s to increment the nice value", opt_env_nice);
|
|
Packit |
8ea169 |
nice_incr = xatoi(opt_env_nice);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (nice_incr != 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_debug("Incrementing the nice value by %d", nice_incr);
|
|
Packit |
8ea169 |
const int ret = nice(nice_incr);
|
|
Packit |
8ea169 |
if (ret == -1)
|
|
Packit |
8ea169 |
perror_msg_and_die("Failed to increment the nice value");
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
bool post_create = (strcmp(event_name, "post-create") == 0);
|
|
Packit |
8ea169 |
char *dump_dir_name = NULL;
|
|
Packit |
8ea169 |
while (*argv)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
dump_dir_name = xstrdup(*argv++);
|
|
Packit |
8ea169 |
int i = strlen(dump_dir_name);
|
|
Packit |
8ea169 |
while (--i >= 0)
|
|
Packit |
8ea169 |
if (dump_dir_name[i] != '/')
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
dump_dir_name[++i] = '\0';
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ DD_OPEN_READONLY);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
return 1;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
uid = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct run_event_state *run_state = new_run_event_state();
|
|
Packit |
8ea169 |
if (!interactive)
|
|
Packit |
8ea169 |
make_run_event_state_forwarding(run_state);
|
|
Packit |
8ea169 |
run_state->logging_callback = do_log;
|
|
Packit |
8ea169 |
if (post_create)
|
|
Packit |
8ea169 |
run_state->post_run_callback = is_crash_a_dup;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int r = run_event_on_dir_name(run_state, dump_dir_name, event_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const bool no_action_for_event = (r == 0 && run_state->children_count == 0);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free_run_event_state(run_state);
|
|
Packit |
8ea169 |
/* Needed only if is_crash_a_dup() was called, but harmless
|
|
Packit |
8ea169 |
* even if it wasn't:
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
dup_uuid_fini();
|
|
Packit |
8ea169 |
dup_corebt_fini();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (no_action_for_event)
|
|
Packit |
8ea169 |
error_msg_and_die("No actions are found for event '%s'", event_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
//TODO: consider this case:
|
|
Packit |
8ea169 |
// new dump is created, post-create detects that it is a dup,
|
|
Packit |
8ea169 |
// but then load_crash_info(dup_name) *FAILS*.
|
|
Packit |
8ea169 |
// In this case, we later delete damaged dup_name (right?)
|
|
Packit |
8ea169 |
// but new dump never gets its FILENAME_COUNT set!
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Is crash a dup? (In this case, is_crash_a_dup() should have
|
|
Packit |
8ea169 |
* aborted "post-create" event processing as soon as it saw uuid
|
|
Packit |
8ea169 |
* and determined that there is another crash with same uuid.
|
|
Packit |
8ea169 |
* In this case it sets crash_dump_dup_name)
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
if (crash_dump_dup_name)
|
|
Packit |
8ea169 |
error_msg_and_die("DUP_OF_DIR: %s", crash_dump_dup_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Was there error on one of processing steps in run_event? */
|
|
Packit |
8ea169 |
if (r != 0)
|
|
Packit |
8ea169 |
return r; /* yes */
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(dump_dir_name);
|
|
Packit |
8ea169 |
dump_dir_name = NULL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* exit 0 means, that there is no duplicate of dump-dir */
|
|
Packit |
8ea169 |
return 0;
|
|
Packit |
8ea169 |
}
|