diff options
Diffstat (limited to 'src/plugins')
25 files changed, 1304 insertions, 1719 deletions
diff --git a/src/plugins/CCpp.cpp b/src/plugins/CCpp.cpp deleted file mode 100644 index e6807ea7..00000000 --- a/src/plugins/CCpp.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* - CCpp.cpp - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <set> -#include "abrtlib.h" -#include "CCpp.h" -#include "abrt_exception.h" -#include "comm_layer_inner.h" - -using namespace std; - -#define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern" -#define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %p %s %u %c" -#define CORE_PIPE_LIMIT_IFACE "/proc/sys/kernel/core_pipe_limit" -/* core_pipe_limit specifies how many dump_helpers might run at the same time - * 0 - means unlimited, but it's not guaranteed that /proc/<pid> of crashing - * process will be available for dump_helper - * 4 - means that 4 dump_helpers can run at the same time (the rest will also - * run, but they will fail to read /proc/<pid>) - * This should be enough for ABRT, we can miss some crashes, but what are - * the odds that more processes crash at the same time? - * The value of 4 has been recommended by nhorman. - */ -#define CORE_PIPE_LIMIT "4" - -#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di" - -CAnalyzerCCpp::CAnalyzerCCpp() : - m_bBacktrace(true), - m_bBacktraceRemotes(false), - m_bMemoryMap(false), - m_bInstallDebugInfo(true), - m_nDebugInfoCacheMB(4000), - m_nGdbTimeoutSec(60) -{} - -/* - this is just a workaround until kernel changes it's behavior - when handling pipes in core_pattern -*/ -#ifdef HOSTILE_KERNEL -#define CORE_SIZE_PATTERN "Max core file size=1:unlimited" -static int isdigit_str(char *str) -{ - do { - if (*str < '0' || *str > '9') - return 0; - } while (*++str); - return 1; -} - -static int set_limits() -{ - DIR *dir = opendir("/proc"); - if (!dir) { - /* this shouldn't fail, but to be safe.. */ - return 1; - } - - struct dirent *ent; - while ((ent = readdir(dir)) != NULL) { - if (!isdigit_str(ent->d_name)) - continue; - - char limits_name[sizeof("/proc/%s/limits") + sizeof(long)*3]; - snprintf(limits_name, sizeof(limits_name), "/proc/%s/limits", ent->d_name); - FILE *limits_fp = fopen(limits_name, "r"); - if (!limits_fp) { - break; - } - - char line[128]; - char *ulimit_c = NULL; - while (1) { - if (fgets(line, sizeof(line)-1, limits_fp) == NULL) - break; - if (strncmp(line, "Max core file size", sizeof("Max core file size")-1) == 0) { - ulimit_c = skip_whitespace(line + sizeof("Max core file size")-1); - skip_non_whitespace(ulimit_c)[0] = '\0'; - break; - } - } - fclose(limits_fp); - if (!ulimit_c || ulimit_c[0] != '0' || ulimit_c[1] != '\0') { - /*process has nonzero ulimit -c, so need to modify it*/ - continue; - } - /* echo -n 'Max core file size=1:unlimited' >/proc/PID/limits */ - int fd = open(limits_name, O_WRONLY); - if (fd >= 0) { - errno = 0; - /*full_*/ - ssize_t n = write(fd, CORE_SIZE_PATTERN, sizeof(CORE_SIZE_PATTERN)-1); - if (n < sizeof(CORE_SIZE_PATTERN)-1) - log("warning: can't write core_size limit to: %s", limits_name); - close(fd); - } - else - { - log("warning: can't open %s for writing", limits_name); - } - } - closedir(dir); - return 0; -} -#endif /* HOSTILE_KERNEL */ - -void CAnalyzerCCpp::Init() -{ - FILE *fp = fopen(CORE_PATTERN_IFACE, "r"); - if (fp) - { - char line[PATH_MAX]; - if (fgets(line, sizeof(line), fp)) - m_sOldCorePattern = line; - fclose(fp); - } - if (m_sOldCorePattern[0] == '|') - { - if (m_sOldCorePattern == CORE_PATTERN) - { - log("warning: %s already contains %s, " - "did abrt daemon crash recently?", - CORE_PATTERN_IFACE, CORE_PATTERN); - /* There is no point in "restoring" CORE_PATTERN_IFACE - * to CORE_PATTERN on exit. Will restore to a default value: - */ - m_sOldCorePattern = "core"; - } else { - log("warning: %s was already set to run a crash analyser (%s), " - "abrt may interfere with it", - CORE_PATTERN_IFACE, CORE_PATTERN); - } - } -#ifdef HOSTILE_KERNEL - if (set_limits() != 0) - log("warning: failed to set core_size limit, ABRT won't detect crashes in" - "compiled apps"); -#endif - - fp = fopen(CORE_PATTERN_IFACE, "w"); - if (fp) - { - fputs(CORE_PATTERN, fp); - fclose(fp); - } - - /* read the core_pipe_limit and change it if it's == 0 - otherwise the abrt-hook-ccpp won't be able to read /proc/<pid> - of the crashing process - */ - fp = fopen(CORE_PIPE_LIMIT_IFACE, "r"); - if (fp) - { - /* we care only about the first char, if it's - * not '0' then we don't have to change it, - * because it means that it's already != 0 - */ - char pipe_limit[2]; - if (!fgets(pipe_limit, sizeof(pipe_limit), fp)) - pipe_limit[0] = '1'; /* not 0 */ - fclose(fp); - if (pipe_limit[0] == '0') - { - fp = fopen(CORE_PIPE_LIMIT_IFACE, "w"); - if (fp) - { - fputs(CORE_PIPE_LIMIT, fp); - fclose(fp); - } - else - { - log("warning: failed to set core_pipe_limit, ABRT won't detect" - "crashes in compiled apps if kernel > 2.6.31"); - } - } - } -} - -void CAnalyzerCCpp::DeInit() -{ - /* no need to restore the core_pipe_limit, because it's only used - when there is s pipe in core_pattern - */ - FILE *fp = fopen(CORE_PATTERN_IFACE, "w"); - if (fp) - { - fputs(m_sOldCorePattern.c_str(), fp); - fclose(fp); - } -} - -void CAnalyzerCCpp::SetSettings(const map_plugin_settings_t& pSettings) -{ - m_pSettings = pSettings; - - map_plugin_settings_t::const_iterator end = pSettings.end(); - map_plugin_settings_t::const_iterator it; - it = pSettings.find("Backtrace"); - if (it != end) - { - m_bBacktrace = string_to_bool(it->second.c_str()); - } - it = pSettings.find("BacktraceRemotes"); - if (it != end) - { - m_bBacktraceRemotes = string_to_bool(it->second.c_str()); - } - it = pSettings.find("MemoryMap"); - if (it != end) - { - m_bMemoryMap = string_to_bool(it->second.c_str()); - } - it = pSettings.find("DebugInfo"); - if (it != end) - { - m_sDebugInfo = it->second; - } - it = pSettings.find("DebugInfoCacheMB"); - if (it != end) - { - m_nDebugInfoCacheMB = xatou(it->second.c_str()); - } - it = pSettings.find("GdbTimeoutSec"); - if (it != end) - { - m_nGdbTimeoutSec = xatoi_u(it->second.c_str()); - } - it = pSettings.find("InstallDebugInfo"); - if (it == end) //compat, remove after 0.0.11 - it = pSettings.find("InstallDebuginfo"); - if (it != end) - { - m_bInstallDebugInfo = string_to_bool(it->second.c_str()); - } - m_sDebugInfoDirs = DEBUGINFO_CACHE_DIR; - it = pSettings.find("ReadonlyLocalDebugInfoDirs"); - if (it != end) - { - m_sDebugInfoDirs += ':'; - m_sDebugInfoDirs += it->second; - } -} - -//ok to delete? -//const map_plugin_settings_t& CAnalyzerCCpp::GetSettings() -//{ -// m_pSettings["MemoryMap"] = m_bMemoryMap ? "yes" : "no"; -// m_pSettings["DebugInfo"] = m_sDebugInfo; -// m_pSettings["DebugInfoCacheMB"] = to_string(m_nDebugInfoCacheMB); -// m_pSettings["InstallDebugInfo"] = m_bInstallDebugInfo ? "yes" : "no"; -// -// return m_pSettings; -//} - -PLUGIN_INFO(ANALYZER, - CAnalyzerCCpp, - "CCpp", - "0.0.1", - _("Analyzes crashes in C/C++ programs"), - "zprikryl@redhat.com", - "https://fedorahosted.org/abrt/wiki", - ""); diff --git a/src/plugins/CCpp.h b/src/plugins/CCpp.h deleted file mode 100644 index e95b4d09..00000000 --- a/src/plugins/CCpp.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - CCpp.h - header file for C/C++ analyzer plugin - - it can get UUID and memory maps from core files - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#ifndef CCPP_H_ -#define CCPP_H_ - -#include <string> -#include "plugin.h" -#include "analyzer.h" - -class CAnalyzerCCpp : public CAnalyzer -{ - private: - bool m_bBacktrace; - bool m_bBacktraceRemotes; - bool m_bMemoryMap; - bool m_bInstallDebugInfo; - unsigned m_nDebugInfoCacheMB; - unsigned m_nGdbTimeoutSec; - std::string m_sOldCorePattern; - std::string m_sDebugInfo; - std::string m_sDebugInfoDirs; - - public: - CAnalyzerCCpp(); - virtual void Init(); - virtual void DeInit(); - virtual void SetSettings(const map_plugin_settings_t& pSettings); -}; - -#endif /* CCPP */ diff --git a/src/plugins/Kerneloops.conf b/src/plugins/Kerneloops.conf index 67ad07b9..e65e176f 100644 --- a/src/plugins/Kerneloops.conf +++ b/src/plugins/Kerneloops.conf @@ -4,10 +4,4 @@ Enabled = yes # Set to "yes" for compatibility with kerneloops.org tool. InformAllUsers = yes -# Kerneloops Scanner configuration -################################## -SysLogFile = /var/log/messages - -# KerneloopsReporter configuration -################################## SubmitURL = http://submit.kerneloops.org/submitoops.php diff --git a/src/plugins/KerneloopsScanner.cpp b/src/plugins/KerneloopsScanner.cpp deleted file mode 100644 index 93f37e07..00000000 --- a/src/plugins/KerneloopsScanner.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - Copyright (C) 2010 ABRT team - Copyright (C) 2010 RedHat Inc - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - Authors: - Anton Arapov <anton@redhat.com> - Arjan van de Ven <arjan@linux.intel.com> -*/ -#include <syslog.h> -#include <asm/unistd.h> /* __NR_syslog */ -#include <glib.h> -#include "abrtlib.h" -#include "abrt_exception.h" -#include "comm_layer_inner.h" -#include "KerneloopsSysLog.h" -#include "KerneloopsScanner.h" - -// TODO: https://fedorahosted.org/abrt/ticket/78 - -static int scan_dmesg(GList **oopsList) -{ - VERB1 log("Scanning dmesg"); - - /* syslog(3) - read the last len bytes from the log buffer - * (non-destructively), but dont read more than was written - * into the buffer since the last"clear ring buffer" cmd. - * Returns the number of bytes read. - */ - char *buffer = (char*)xzalloc(16*1024); - syscall(__NR_syslog, 3, buffer, 16*1024 - 1); /* always NUL terminated */ - int cnt_FoundOopses = extract_oopses(oopsList, buffer, strlen(buffer)); - free(buffer); - - return cnt_FoundOopses; -} - - -/* "dumpoops" tool uses these two functions too */ -extern "C" { - -int scan_syslog_file(GList **oopsList, const char *filename, time_t *last_changed_p) -{ - VERB1 log("Scanning syslog file '%s'", filename); - - char *buffer; - struct stat statb; - int fd; - int cnt_FoundOopses; - ssize_t sz; - fd = open(filename, O_RDONLY); - if (fd < 0) - return 0; - statb.st_size = 0; /* paranoia */ - if (fstat(fd, &statb) != 0 || statb.st_size < 1) - { - close(fd); - return 0; - } - - if (last_changed_p != NULL) - { - if (*last_changed_p == statb.st_mtime) - { - VERB1 log("Syslog file '%s' hasn't changed since last scan, skipping", filename); - close(fd); - return 0; - } - *last_changed_p = statb.st_mtime; - } - - /* - * In theory we have a race here, since someone could spew - * to /var/log/messages before we read it in... we try to - * deal with it by reading at most 10kbytes extra. If there's - * more than that.. any oops will be in dmesg anyway. - * Do not try to allocate an absurd amount of memory; ignore - * older log messages because they are unlikely to have - * sufficiently recent data to be useful. 32MB is more - * than enough; it's not worth looping through more log - * if the log is larger than that. - */ - sz = statb.st_size + 10*1024; - if (statb.st_size > (32*1024*1024 - 10*1024)) - { - xlseek(fd, statb.st_size - (32*1024*1024 - 10*1024), SEEK_SET); - sz = 32*1024*1024; - } - buffer = (char*)xzalloc(sz); - sz = full_read(fd, buffer, sz); - close(fd); - - cnt_FoundOopses = 0; - if (sz > 0) - cnt_FoundOopses = extract_oopses(oopsList, buffer, sz); - free(buffer); - - return cnt_FoundOopses; -} - -/* returns number of errors */ -int save_oops_to_debug_dump(GList **oopsList) -{ - unsigned countdown = 16; /* do not report hundreds of oopses */ - unsigned idx = g_list_length(*oopsList); - time_t t = time(NULL); - pid_t my_pid = getpid(); - - VERB1 log("Saving %u oopses as crash dump dirs", idx >= countdown ? countdown-1 : idx); - - char *tainted_str = NULL; - /* once tainted flag is set to 1, only restart can reset the flag to 0 */ - FILE *tainted_fd = fopen("/proc/sys/kernel/tainted", "r"); - if (tainted_fd) - { - tainted_str = xmalloc_fgetline(tainted_fd); - fclose(tainted_fd); - } - else - error_msg("/proc/sys/kernel/tainted does not exist"); - - int errors = 0; - - while (idx != 0 && --countdown != 0) - { - char path[sizeof(DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu") + 3 * sizeof(long)*3]; - sprintf(path, DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu", (long)t, (long)my_pid, (long)idx); - - char *first_line = (char*)g_list_nth_data(*oopsList,--idx); - char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */ - *second_line++ = '\0'; - - struct dump_dir *dd = dd_create(path, /*uid:*/ 0); - if (dd) - { - dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops"); - dd_save_text(dd, FILENAME_EXECUTABLE, "kernel"); - dd_save_text(dd, FILENAME_KERNEL, first_line); - dd_save_text(dd, FILENAME_CMDLINE, "not_applicable"); - dd_save_text(dd, FILENAME_BACKTRACE, second_line); - /* Optional, makes generated bz more informative */ - strchrnul(second_line, '\n')[0] = '\0'; - dd_save_text(dd, FILENAME_REASON, second_line); - - if (tainted_str && tainted_str[0] != '0') - dd_save_text(dd, FILENAME_TAINTED, tainted_str); - - free(tainted_str); - dd_close(dd); - } - else - errors++; - } - - return errors; -} - -} /* extern "C" */ - - -CKerneloopsScanner::CKerneloopsScanner() -{ - int cnt_FoundOopses; - m_syslog_last_change = 0; - - /* Scan dmesg, on first call only */ - GList *oopsList = NULL; - cnt_FoundOopses = scan_dmesg(&oopsList); - if (cnt_FoundOopses > 0) - { - int errors = save_oops_to_debug_dump(&oopsList); - if (errors > 0) - log("%d errors while dumping oopses", errors); - } -} - -void CKerneloopsScanner::Run(const char *pActionDir, const char *pArgs, int force) -{ - const char *syslog_file = "/var/log/messages"; - map_plugin_settings_t::const_iterator it = m_pSettings.find("SysLogFile"); - if (it != m_pSettings.end()) - syslog_file = it->second.c_str(); - - GList *oopsList = NULL; - int cnt_FoundOopses = scan_syslog_file(&oopsList, syslog_file, &m_syslog_last_change); - if (cnt_FoundOopses > 0) - { - int errors = save_oops_to_debug_dump(&oopsList); - if (errors > 0) - log("%d errors while dumping oopses", errors); - /* - * This marker in syslog file prevents us from - * re-parsing old oopses (any oops before it is - * ignored by scan_syslog_file()). The only problem - * is that we can't be sure here that syslog_file - * is the file where syslog(xxx) stuff ends up. - */ - openlog("abrt", 0, LOG_KERN); - syslog(LOG_WARNING, - "Kerneloops: Reported %u kernel oopses to Abrt", - cnt_FoundOopses); - closelog(); - } - - for (GList *li = oopsList; li != NULL; li = g_list_next(li)) - free((char*)li->data); - g_list_free(oopsList); -} - -PLUGIN_INFO(ACTION, - CKerneloopsScanner, - "KerneloopsScanner", - "0.0.1", - _("Periodically scans for and saves kernel oopses"), - "anton@redhat.com", - "http://people.redhat.com/aarapov", - ""); diff --git a/src/plugins/KerneloopsScanner.h b/src/plugins/KerneloopsScanner.h deleted file mode 100644 index 2bddb0f4..00000000 --- a/src/plugins/KerneloopsScanner.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2007, Intel Corporation - * Copyright 2009, Red Hat Inc. - * - * This file is part of Abrt. - * - * This program file is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program in a file named COPYING; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * Authors: - * Anton Arapov <anton@redhat.com> - * Arjan van de Ven <arjan@linux.intel.com> - */ -#ifndef KERNELOOPSSCANNER_H_ -#define KERNELOOPSSCANNER_H_ - -#include "abrt_types.h" -#include "plugin.h" -#include "action.h" - -class CKerneloopsScanner : public CAction -{ - private: - time_t m_syslog_last_change; - public: - CKerneloopsScanner(); - virtual void Run(const char *pActionDir, const char *pArgs, int force); -}; - -#endif diff --git a/src/plugins/KerneloopsSysLog.cpp b/src/plugins/KerneloopsSysLog.cpp deleted file mode 100644 index 68f309bc..00000000 --- a/src/plugins/KerneloopsSysLog.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - Copyright (C) 2010 ABRT team - Copyright (C) 2010 RedHat Inc - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - Authors: - Anton Arapov <anton@redhat.com> - Arjan van de Ven <arjan@linux.intel.com> - */ -#include "abrtlib.h" -#include "KerneloopsSysLog.h" -#include <glib.h> - -static void queue_oops(GList **vec, const char *data, const char *version) -{ - char *ver_data = xasprintf("%s\n%s", version, data); - *vec = g_list_append(*vec, ver_data); -} - -/* - * extract_version tries to find the kernel version in given data - */ -static char *extract_version(const char *linepointer) -{ - if (strstr(linepointer, "Pid") - || strstr(linepointer, "comm") - || strstr(linepointer, "CPU") - || strstr(linepointer, "REGS") - || strstr(linepointer, "EFLAGS") - ) { - char* start; - char* end; - - start = strstr((char*)linepointer, "2.6."); - if (start) - { - end = strchr(start, ')'); - if (!end) - end = strchrnul(start, ' '); - return xstrndup(start, end-start); - } - } - - return NULL; -} - -/* - * extract_oops tries to find oops signatures in a log - */ -struct line_info { - char *ptr; - char level; -}; - -static int record_oops(GList **oopses, struct line_info* lines_info, int oopsstart, int oopsend) -{ - int q; - int len; - char *oops; - char *version; - - len = 2; - for (q = oopsstart; q <= oopsend; q++) - len += strlen(lines_info[q].ptr) + 1; - - oops = (char*)xzalloc(len); - - version = NULL; - for (q = oopsstart; q <= oopsend; q++) - { - if (!version) - version = extract_version(lines_info[q].ptr); - - if (lines_info[q].ptr[0]) - { - strcat(oops, lines_info[q].ptr); - strcat(oops, "\n"); - } - } - int rv = 1; - /* too short oopses are invalid */ - if (strlen(oops) > 100) - queue_oops(oopses, oops, version ? version : "undefined"); - else - { - VERB3 log("Dropped oops: too short"); - rv = 0; - } - free(oops); - free(version); - return rv; -} -#define REALLOC_CHUNK 1000 -int extract_oopses(GList **oopses, char *buffer, size_t buflen) -{ - char *c; - int linecount = 0; - int lines_info_alloc = 0; - struct line_info *lines_info = NULL; - - /* Split buffer into lines */ - - if (buflen != 0) - buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */ - c = buffer; - while (c < buffer + buflen) - { - char linelevel; - char *c9; - char *colon; - - c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */ - assert(c9); - *c9 = '\0'; /* turn the \n into a string termination */ - if (c9 == c) - goto next_line; - - /* Is it a syslog file (/var/log/messages or similar)? - * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx", - * some users run syslog in non-C locale: - * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah" - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!! - * We detect it by checking for N:NN:NN pattern in first 15 chars - * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled") - */ - colon = strchr(c, ':'); - if (colon && colon > c && colon < c + 15 - && isdigit(colon[-1]) /* N:... */ - && isdigit(colon[1]) /* ...N:NN:... */ - && isdigit(colon[2]) - && colon[3] == ':' - && isdigit(colon[4]) /* ...N:NN:NN... */ - && isdigit(colon[5]) - ) { - /* It's syslog file, not a bare dmesg */ - - /* Skip non-kernel lines */ - char *kernel_str = strstr(c, "kernel: "); - if (kernel_str == NULL) - { - /* if we see our own marker: - * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt" - * we know we submitted everything upto here already */ - if (strstr(c, "abrt:") && strstr(c, "Abrt")) - { - VERB3 log("Found our marker at line %d, restarting line count from 0", linecount); - linecount = 0; - lines_info_alloc = 0; - free(lines_info); - lines_info = NULL; - } - goto next_line; - } - c = kernel_str + sizeof("kernel: ")-1; - } - - linelevel = 0; - /* store and remove kernel log level */ - if (*c == '<' && c[1] && c[2] == '>') - { - linelevel = c[1]; - c += 3; - } - /* remove jiffies time stamp counter if present */ - if (*c == '[') - { - char *c2 = strchr(c, '.'); - char *c3 = strchr(c, ']'); - if (c2 && c3 && (c2 < c3) && (c3-c) < 14 && (c2-c) < 8) - { - c = c3 + 1; - if (*c == ' ') - c++; - } - } - if (linecount >= lines_info_alloc) - { - lines_info_alloc += REALLOC_CHUNK; - lines_info = (line_info*)xrealloc(lines_info, - lines_info_alloc * sizeof(struct line_info)); - } - lines_info[linecount].ptr = c; - lines_info[linecount].level = linelevel; - linecount++; -next_line: - c = c9 + 1; - } - - /* Analyze lines */ - - int i; - char prevlevel = 0; - int oopsstart = -1; - int inbacktrace = 0; - int oopsesfound = 0; - - i = 0; - while (i < linecount) - { - char *curline = lines_info[i].ptr; - - if (curline == NULL) - { - i++; - continue; - } - while (*curline == ' ') - curline++; - - if (oopsstart < 0) - { - /* find start-of-oops markers */ - if (strstr(curline, "general protection fault:")) - oopsstart = i; - else if (strstr(curline, "BUG:")) - oopsstart = i; - else if (strstr(curline, "kernel BUG at")) - oopsstart = i; - else if (strstr(curline, "do_IRQ: stack overflow:")) - oopsstart = i; - else if (strstr(curline, "RTNL: assertion failed")) - oopsstart = i; - else if (strstr(curline, "Eeek! page_mapcount(page) went negative!")) - oopsstart = i; - else if (strstr(curline, "near stack overflow (cur:")) - oopsstart = i; - else if (strstr(curline, "double fault:")) - oopsstart = i; - else if (strstr(curline, "Badness at")) - oopsstart = i; - else if (strstr(curline, "NETDEV WATCHDOG")) - oopsstart = i; - else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated message */ - oopsstart = i; - else if (strstr(curline, "Unable to handle kernel")) - oopsstart = i; - else if (strstr(curline, "sysctl table check failed")) - oopsstart = i; - else if (strstr(curline, "INFO: possible recursive locking detected")) - oopsstart = i; - // Not needed: "--[ cut here ]--" is always followed - // by "Badness at", "kernel BUG at", or "WARNING: at" string - //else if (strstr(curline, "------------[ cut here ]------------")) - // oopsstart = i; - else if (strstr(curline, "list_del corruption.")) - oopsstart = i; - else if (strstr(curline, "list_add corruption.")) - oopsstart = i; - if (strstr(curline, "Oops:") && i >= 3) - oopsstart = i-3; - - if (oopsstart >= 0) - { - /* debug information */ - VERB3 { - log("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr); - if (oopsstart != i) - log("Trigger line is %d: '%s'", i, c); - } - /* try to find the end marker */ - int i2 = i + 1; - while (i2 < linecount && i2 < (i+50)) - { - if (strstr(lines_info[i2].ptr, "---[ end trace")) - { - inbacktrace = 1; - i = i2; - break; - } - i2++; - } - } - } - - /* Are we entering a call trace part? */ - /* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */ - if (oopsstart >= 0 && !inbacktrace) - { - if (strstr(curline, "Call Trace:")) - inbacktrace = 1; - else - if (strnlen(curline, 9) > 8 - && curline[0] == '[' && curline[1] == '<' - && strstr(curline, ">]") - && strstr(curline, "+0x") - && strstr(curline, "/0x") - ) { - inbacktrace = 1; - } - } - - /* Are we at the end of an oops? */ - else if (oopsstart >= 0 && inbacktrace) - { - int oopsend = INT_MAX; - - /* line needs to start with " [" or have "] [" if it is still a call trace */ - /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */ - if (curline[0] != '[' - && !strstr(curline, "] [") - && !strstr(curline, "--- Exception") - && !strstr(curline, "LR =") - && !strstr(curline, "<#DF>") - && !strstr(curline, "<IRQ>") - && !strstr(curline, "<EOI>") - && !strstr(curline, "<<EOE>>") - && strncmp(curline, "Code: ", 6) != 0 - && strncmp(curline, "RIP ", 4) != 0 - && strncmp(curline, "RSP ", 4) != 0 - ) { - oopsend = i-1; /* not a call trace line */ - } - /* oops lines are always more than 8 chars long */ - else if (strnlen(curline, 8) < 8) - oopsend = i-1; - /* single oopses are of the same loglevel */ - else if (lines_info[i].level != prevlevel) - oopsend = i-1; - else if (strstr(curline, "Instruction dump:")) - oopsend = i; - /* if a new oops starts, this one has ended */ - else if (strstr(curline, "WARNING: at ") && oopsstart != i) /* WARN_ON() generated message */ - oopsend = i-1; - else if (strstr(curline, "Unable to handle") && oopsstart != i) - oopsend = i-1; - /* kernel end-of-oops marker (not including marker itself) */ - else if (strstr(curline, "---[ end trace")) - oopsend = i-1; - - if (oopsend <= i) - { - VERB3 log("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr); - if (record_oops(oopses, lines_info, oopsstart, oopsend)) - oopsesfound++; - oopsstart = -1; - inbacktrace = 0; - } - } - - prevlevel = lines_info[i].level; - i++; - - if (oopsstart >= 0) - { - /* Do we have a suspiciously long oops? Cancel it */ - if (i-oopsstart > 60) - { - inbacktrace = 0; - oopsstart = -1; - VERB3 log("Dropped oops, too long"); - continue; - } - if (!inbacktrace && i-oopsstart > 40) - { - /*inbacktrace = 0; - already is */ - oopsstart = -1; - VERB3 log("Dropped oops, too long"); - continue; - } - } - } /* while (i < linecount) */ - - /* process last oops if we have one */ - if (oopsstart >= 0 && inbacktrace) - { - int oopsend = i-1; - VERB3 log("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr); - if (record_oops(oopses, lines_info, oopsstart, oopsend)) - oopsesfound++; - } - - free(lines_info); - return oopsesfound; -} diff --git a/src/plugins/KerneloopsSysLog.h b/src/plugins/KerneloopsSysLog.h deleted file mode 100644 index d8b4d32b..00000000 --- a/src/plugins/KerneloopsSysLog.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2007, Intel Corporation - * Copyright 2009, Red Hat Inc. - * - * This file is part of Abrt. - * - * This program file is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program in a file named COPYING; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * Authors: - * Anton Arapov <anton@redhat.com> - * Arjan van de Ven <arjan@linux.intel.com> - */ - -#ifndef __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_ -#define __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_ - -#include "abrt_types.h" -#include <glib.h> - -int extract_oopses(GList **oopses, char *buffer, size_t buflen); - -#endif diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 71a2fd6f..207fc860 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,13 +1,22 @@ -INC_PATH=$(srcdir)/../include -UTILS_PATH=$(srcdir)/../lib -AM_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) -pluginslibdir=$(PLUGINS_LIB_DIR) -libexec_SCRIPTS = \ +pluginslibdir = $(PLUGINS_LIB_DIR) + +bin_SCRIPTS = \ abrt-action-install-debuginfo.py -pluginslib_LTLIBRARIES = \ - libCCpp.la \ - libKerneloopsScanner.la +bin_PROGRAMS = \ + abrt-dump-oops \ + abrt-action-analyze-c \ + abrt-action-analyze-python \ + abrt-action-analyze-oops \ + abrt-action-generate-backtrace \ + abrt-action-bugzilla \ + abrt-action-rhtsupport \ + abrt-action-kerneloops \ + abrt-action-upload \ + abrt-action-mailx \ + abrt-action-print \ + abrt-action-install-debuginfo \ + abrt-retrace-client dist_pluginslib_DATA = \ Logger.glade \ @@ -18,6 +27,7 @@ dist_pluginslib_DATA = \ KerneloopsReporter.glade pluginsconfdir = $(PLUGINS_CONF_DIR) + dist_pluginsconf_DATA = \ CCpp.conf \ Python.conf \ @@ -28,9 +38,13 @@ dist_pluginsconf_DATA = \ RHTSupport.conf \ Upload.conf +eventsconfdir = $(EVENTS_CONF_DIR) + +dist_eventsconf_DATA = \ + ccpp_events.conf + man_MANS = \ abrt-Bugzilla.7 \ - abrt-KerneloopsScanner.7 \ abrt-KerneloopsReporter.7 \ abrt-Logger.7 \ abrt-Mailx.7 \ @@ -48,39 +62,29 @@ install-data-hook: $(DESTDIR)/$(DEBUG_INFO_DIR) sed 's: = /var/: = $(localstatedir)/:g' -i \ $(DESTDIR)$(sysconfdir)/abrt/plugins/Logger.conf -# CCpp -libCCpp_la_SOURCES = CCpp.cpp CCpp.h -libCCpp_la_LDFLAGS = -avoid-version -libCCpp_la_CPPFLAGS = -Wall -Werror \ - -I$(INC_PATH) \ - -I$(UTILS_PATH) \ - -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \ +abrt_dump_oops_SOURCES = \ + abrt-dump-oops.c +abrt_dump_oops_CPPFLAGS = \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ + -I$(srcdir)/../lib \ + -DBIN_DIR=\"$(bindir)\" \ + -DVAR_RUN=\"$(VAR_RUN)\" \ + -DCONF_DIR=\"$(CONF_DIR)\" \ + -DLOCALSTATEDIR='"$(localstatedir)"' \ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DLOCALSTATEDIR='"$(localstatedir)"' -# -DHOSTILE_KERNEL - -# KerneloopsScanner -libKerneloopsScanner_la_SOURCES = KerneloopsScanner.cpp KerneloopsScanner.h KerneloopsSysLog.cpp KerneloopsSysLog.h -libKerneloopsScanner_la_LDFLAGS = -avoid-version $(GLIB_LIBS) -libKerneloopsScanner_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" $(GLIB_CFLAGS) - -libexec_PROGRAMS = \ - abrt-action-analyze-c \ - abrt-action-analyze-python \ - abrt-action-analyze-oops \ - abrt-action-generate-backtrace \ - abrt-action-bugzilla \ - abrt-action-rhtsupport \ - abrt-action-kerneloops \ - abrt-action-upload \ - abrt-action-mailx \ - abrt-action-print \ - abrt-retrace-client + -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ + -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ + -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ + -D_GNU_SOURCE \ + -Wall -Werror +abrt_dump_oops_LDADD = \ + ../lib/libreport.la abrt_action_analyze_c_SOURCES = \ abrt-action-analyze-c.c abrt_action_analyze_c_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -90,15 +94,16 @@ abrt_action_analyze_c_CPPFLAGS = \ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_analyze_c_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_analyze_python_SOURCES = \ abrt-action-analyze-python.c abrt_action_analyze_python_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -108,15 +113,16 @@ abrt_action_analyze_python_CPPFLAGS = \ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_analyze_python_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_analyze_oops_SOURCES = \ abrt-action-analyze-oops.c abrt_action_analyze_oops_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -126,15 +132,16 @@ abrt_action_analyze_oops_CPPFLAGS = \ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_analyze_oops_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_generate_backtrace_SOURCES = \ abrt-action-generate-backtrace.c abrt_action_generate_backtrace_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -144,16 +151,17 @@ abrt_action_generate_backtrace_CPPFLAGS = \ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_generate_backtrace_LDADD = \ - ../lib/libabrt.la \ + ../lib/libreport.la \ ../btparser/libbtparser.la abrt_action_bugzilla_SOURCES = \ abrt-action-bugzilla.cpp abrt_action_bugzilla_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -169,13 +177,13 @@ abrt_action_bugzilla_CPPFLAGS = \ abrt_action_bugzilla_LDADD = \ $(GLIB_LIBS) \ ../lib/libabrt_web.la \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_rhtsupport_SOURCES = \ abrt_rh_support.h abrt_rh_support.c \ - abrt-action-rhtsupport.cpp + abrt-action-rhtsupport.c abrt_action_rhtsupport_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -193,12 +201,12 @@ abrt_action_rhtsupport_LDADD = \ $(GLIB_LIBS) \ $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS) \ ../lib/libabrt_web.la \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_upload_SOURCES = \ - abrt-action-upload.cpp + abrt-action-upload.c abrt_action_upload_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -213,16 +221,15 @@ abrt_action_upload_CPPFLAGS = \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_upload_LDFLAGS = -ltar -# Needs libABRTdUtils only for LoadPluginSettings abrt_action_upload_LDADD = \ $(GLIB_LIBS) \ $(CURL_LIBS) \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_kerneloops_SOURCES = \ - abrt-action-kerneloops.cpp + abrt-action-kerneloops.c abrt_action_kerneloops_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -235,15 +242,14 @@ abrt_action_kerneloops_CPPFLAGS = \ $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror -# libABRTdUtils is used only because of LoadPluginSettings: abrt_action_kerneloops_LDADD = \ ../lib/libabrt_web.la \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_mailx_SOURCES = \ - abrt-action-mailx.cpp + abrt-action-mailx.c abrt_action_mailx_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -257,12 +263,12 @@ abrt_action_mailx_CPPFLAGS = \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_mailx_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_print_SOURCES = \ - abrt-action-print.cpp + abrt-action-print.c abrt_action_print_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -275,9 +281,17 @@ abrt_action_print_CPPFLAGS = \ $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror -# libABRTdUtils is used only because of make_description_logger: abrt_action_print_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la + +abrt_action_install_debuginfo_SOURCES = \ + abrt-action-install-debuginfo.c +abrt_action_install_debuginfo_CPPFLAGS = \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ + -I$(srcdir)/../lib \ + -D_GNU_SOURCE \ + -Wall +abrt_action_install_debuginfo_LDADD = abrt_retrace_client_SOURCES = \ abrt-retrace-client.c diff --git a/src/plugins/abrt-KerneloopsScanner.7 b/src/plugins/abrt-KerneloopsScanner.7 deleted file mode 100644 index ff094847..00000000 --- a/src/plugins/abrt-KerneloopsScanner.7 +++ /dev/null @@ -1,46 +0,0 @@ -.TH abrt "7" "1 Jun 2009" "" -.SH NAME -KerneloopsScanner plugin for abrt(8) -.SH DESCRIPTION -.P -.I abrt -is a daemon that watches for application crashes. When a crash occurs, -it collects the crash data and takes action according to -its configuration. This manual page describes the \fIKerneloopsScanner\fP -plugin for \fIabrt\fP. -.P -This plugin reads the system log file (default /var/log/messages) -and stores the kernel oops crashes, which were not already -reported, to abrt's debug dump directory. -.P -To distinguish between new crashes and crashes -that were already reported, the plugin makes its own entry -in the log file, which acts as a separator. -.SH INVOCATION -The plugin is invoked in the \fIabrt.conf\fP configuration file. -No parameters are necessary. -.SH CONFIGURATION -The \fIKerneloopsScanner.conf\fP configuration file contains one entry: -.SS SysLogFile -The file to scan. The default is -.br -SysLogFile = /var/log/messages -.SH EXAMPLES -.P -This is a snippet from the \fIabrt.conf\fP configuration file. -Every 10 seconds look if there were any kernel crashes: -.P -[common] -.br -ActionsAndReporters = Kerneloops, KerneloopsScanner -.br -[cron] -.br -10 = KerneloopsScanner -.SH "SEE ALSO" -.IR abrt (8), -.IR abrt.conf (5), -.IR abrt-plugins (7) -.SH AUTHOR -Written by Anton Arapov <anton@redhat.com>. Manual -page by Daniel Novotny <dnovotny@redhat.com>. diff --git a/src/plugins/abrt-action-analyze-c.c b/src/plugins/abrt-action-analyze-c.c index 6d8ac1b4..5def9aa1 100644 --- a/src/plugins/abrt-action-analyze-c.c +++ b/src/plugins/abrt-action-analyze-c.c @@ -52,7 +52,7 @@ static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec) return NULL; char *uid_str = dd_load_text(dd, FILENAME_UID); dd_close(dd); - unsigned uid = xatoi_u(uid_str); + unsigned uid = xatoi_positive(uid_str); free(uid_str); int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETGUID | EXECFLG_SETSID | EXECFLG_QUIET; @@ -104,7 +104,7 @@ static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec) if (status != 0) { - /* unstrip didnt exit with exitcode 0 */ + /* unstrip didnt exit with exit code 0 */ strbuf_free(buf_out); return NULL; } @@ -149,28 +149,28 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); + const char *dump_dir_name = "."; + /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( - PROGNAME" [-vs] -d DIR\n\n" + PROGNAME" [-v] -d DIR\n\n" "Calculates and saves UUID of coredumps" - ); - const char *dump_dir_name = "."; + ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, - OPT_s = 1 << 2, +// OPT_s = 1 << 2, }; /* 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", _("Crash dump directory")), - OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), +// OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = PROGNAME; //Maybe we will want this... later // if (opts & OPT_s) diff --git a/src/plugins/abrt-action-analyze-oops.c b/src/plugins/abrt-action-analyze-oops.c index 24538641..0072c71d 100644 --- a/src/plugins/abrt-action-analyze-oops.c +++ b/src/plugins/abrt-action-analyze-oops.c @@ -126,28 +126,28 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); + const char *dump_dir_name = "."; + /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( PROGNAME" [-vs] -d DIR\n\n" "Calculates and saves UUID and DUPHASH of oops crash dumps" ); - const char *dump_dir_name = "."; enum { OPT_v = 1 << 0, OPT_d = 1 << 1, - OPT_s = 1 << 2, +// OPT_s = 1 << 2, }; /* 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", _("Crash dump directory")), - OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), +// OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = PROGNAME; //Maybe we will want this... later // if (opts & OPT_s) diff --git a/src/plugins/abrt-action-analyze-python.c b/src/plugins/abrt-action-analyze-python.c index 9fe563db..feffb439 100644 --- a/src/plugins/abrt-action-analyze-python.c +++ b/src/plugins/abrt-action-analyze-python.c @@ -31,28 +31,28 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); + const char *dump_dir_name = "."; + /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( - PROGNAME" [-vs] -d DIR\n\n" + PROGNAME" [-v] -d DIR\n\n" "Calculates and saves UUID and DUPHASH of python crash dumps" - ); - const char *dump_dir_name = "."; + ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, - OPT_s = 1 << 2, +// OPT_s = 1 << 2, }; /* 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", _("Crash dump directory")), - OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), +// OPT_BOOL( 's', NULL, NULL, _("Log to syslog" )), OPT_END() }; /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = PROGNAME; //Maybe we will want this... later // if (opts & OPT_s) diff --git a/src/plugins/abrt-action-bugzilla.cpp b/src/plugins/abrt-action-bugzilla.cpp index b396e453..2aa32b75 100644 --- a/src/plugins/abrt-action-bugzilla.cpp +++ b/src/plugins/abrt-action-bugzilla.cpp @@ -18,8 +18,10 @@ */ #include "abrtlib.h" #include "abrt_xmlrpc.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" +#include "abrt_crash_data.h" +#include "parse_options.h" + +#define PROGNAME "abrt-action-bugzilla" #define XML_RPC_SUFFIX "/xmlrpc.cgi" #define MAX_HOPS 5 @@ -112,8 +114,8 @@ struct ctx: public abrt_xmlrpc_conn { xmlrpc_int32 get_bug_dup_id(xmlrpc_value* result_xml); void get_bug_cc(xmlrpc_value* result_xml, struct bug_info* bz); int add_plus_one_cc(xmlrpc_int32 bug_id, const char* login); - xmlrpc_int32 new_bug(const map_crash_data_t& pCrashData, int depend_on_bugno); - int add_attachments(const char* bug_id_str, const map_crash_data_t& pCrashData); + xmlrpc_int32 new_bug(crash_data_t *crash_data, int depend_on_bugno); + int add_attachments(const char* bug_id_str, crash_data_t *crash_data); int get_bug_info(struct bug_info* bz, xmlrpc_int32 bug_id); int add_comment(xmlrpc_int32 bug_id, const char* comment, bool is_private); @@ -326,7 +328,7 @@ xmlrpc_value* ctx::call_quicksearch_duphash(const char* component, const char* r { char *product = NULL; char *version = NULL; - parse_release(release, &product, &version); + parse_release_for_bz(release, &product, &version); query = xasprintf("ALL component:\"%s\" whiteboard:\"%s\" product:\"%s\"", component, duphash, product ); @@ -442,17 +444,17 @@ static const char *tainted_string(unsigned tainted) return taint_warnings[idx]; } -xmlrpc_int32 ctx::new_bug(const map_crash_data_t& pCrashData, int depend_on_bugno) +xmlrpc_int32 ctx::new_bug(crash_data_t *crash_data, int depend_on_bugno) { - const char *package = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_PACKAGE); - const char *component = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_COMPONENT); - const char *release = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_RELEASE); - const char *arch = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_ARCHITECTURE); - const char *duphash = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_DUPHASH); - const char *reason = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_REASON); - const char *function = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_CRASH_FUNCTION); - const char *analyzer = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_ANALYZER); - const char *tainted_str = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_TAINTED); + const char *package = get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE); + const char *component = get_crash_item_content_or_NULL(crash_data, FILENAME_COMPONENT); + const char *release = get_crash_item_content_or_NULL(crash_data, FILENAME_OS_RELEASE); + const char *arch = get_crash_item_content_or_NULL(crash_data, FILENAME_ARCHITECTURE); + const char *duphash = get_crash_item_content_or_NULL(crash_data, FILENAME_DUPHASH); + const char *reason = get_crash_item_content_or_NULL(crash_data, FILENAME_REASON); + const char *function = get_crash_item_content_or_NULL(crash_data, FILENAME_CRASH_FUNCTION); + const char *analyzer = get_crash_item_content_or_NULL(crash_data, FILENAME_ANALYZER); + const char *tainted_str = get_crash_item_content_or_NULL(crash_data, FILENAME_TAINTED); struct strbuf *buf_summary = strbuf_new(); strbuf_append_strf(buf_summary, "[abrt] %s", package); @@ -466,7 +468,7 @@ xmlrpc_int32 ctx::new_bug(const map_crash_data_t& pCrashData, int depend_on_bugn if (tainted_str && analyzer && (strcmp(analyzer, "Kerneloops") == 0) ) { - unsigned long tainted = xatoi_u(tainted_str); + unsigned long tainted = xatoi_positive(tainted_str); const char *tainted_warning = tainted_string(tainted); if (tainted_warning) strbuf_append_strf(buf_summary, ": TAINTED %s", tainted_warning); @@ -474,13 +476,13 @@ xmlrpc_int32 ctx::new_bug(const map_crash_data_t& pCrashData, int depend_on_bugn char *status_whiteboard = xasprintf("abrt_hash:%s", duphash); - char *bz_dsc = make_description_bz(pCrashData); + char *bz_dsc = make_description_bz(crash_data); char *full_dsc = xasprintf("abrt version: "VERSION"\n%s", bz_dsc); free(bz_dsc); char *product = NULL; char *version = NULL; - parse_release(release, &product, &version); + parse_release_for_bz(release, &product, &version); xmlrpc_value* result = NULL; char *summary = strbuf_free_nobuf(buf_summary); @@ -534,23 +536,24 @@ xmlrpc_int32 ctx::new_bug(const map_crash_data_t& pCrashData, int depend_on_bugn return bug_id; } -int ctx::add_attachments(const char* bug_id_str, const map_crash_data_t& pCrashData) +int ctx::add_attachments(const char* bug_id_str, crash_data_t *crash_data) { - map_crash_data_t::const_iterator it = pCrashData.begin(); - for (; it != pCrashData.end(); it++) + GHashTableIter iter; + char *name; + struct crash_item *value; + g_hash_table_iter_init(&iter, crash_data); + while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { - const char *itemname = it->first.c_str(); - const char *type = it->second[CD_TYPE].c_str(); - const char *content = it->second[CD_CONTENT].c_str(); + const char *content = value->content; - if ((strcmp(type, CD_TXT) == 0) - && (strlen(content) > CD_TEXT_ATT_SIZE || (strcmp(itemname, FILENAME_BACKTRACE) == 0)) + if ((value->flags & CD_FLAG_TXT) + && (strlen(content) > CD_TEXT_ATT_SIZE || (strcmp(name, FILENAME_BACKTRACE) == 0)) ) { char *encoded64 = encode_base64(content, strlen(content)); - char *filename = xasprintf("File: %s", itemname); + char *filename = xasprintf("File: %s", name); xmlrpc_value* result = call("bugzilla.addAttachment", "(s{s:s,s:s,s:s,s:s})", bug_id_str, "description", filename, - "filename", itemname, + "filename", name, "contenttype", "text/plain", "data", encoded64 ); @@ -567,7 +570,9 @@ int ctx::add_attachments(const char* bug_id_str, const map_crash_data_t& pCrashD int ctx::get_bug_info(struct bug_info* bz, xmlrpc_int32 bug_id) { - xmlrpc_value* result = call("bugzilla.getBug", "(s)", to_string(bug_id).c_str()); + char bug_id_str[sizeof(long)*3 + 2]; + sprintf(bug_id_str, "%lu", (long)bug_id); + xmlrpc_value* result = call("bugzilla.getBug", "(s)", bug_id_str); if (!result) return -1; @@ -611,15 +616,10 @@ int ctx::get_bug_info(struct bug_info* bz, xmlrpc_int32 bug_id) void ctx::login(const char* login, const char* passwd) { xmlrpc_value* result = call("User.login", "({s:s,s:s})", "login", login, "password", passwd); - if (!result) - { - char *errmsg = xasprintf("Can't login. Check Edit->Plugins->Bugzilla and /etc/abrt/plugins/Bugzilla.conf. Server said: %s", env.fault_string); - error_msg("%s", errmsg); // show error in daemon log - CABRTException e(EXCEP_PLUGIN, errmsg); - free(errmsg); - throw e; - } + error_msg_and_die("Can't login. Check Edit->Plugins->Bugzilla " + "and /etc/abrt/plugins/Bugzilla.conf. Server said: %s", + env.fault_string); xmlrpc_DECREF(result); } @@ -637,15 +637,12 @@ void ctx::logout() static void report_to_bugzilla( const char *dump_dir_name, - /*const*/ map_plugin_settings_t& settings) + map_string_h *settings) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) - { - throw CABRTException(EXCEP_PLUGIN, _("Can't open '%s'"), dump_dir_name); - } - map_crash_data_t pCrashData; - load_crash_data_from_crash_dump_dir(dd, pCrashData); + xfunc_die(); /* dd_opendir already emitted error msg */ + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); dd_close(dd); const char *env; @@ -656,27 +653,27 @@ static void report_to_bugzilla( bool ssl_verify; env = getenv("Bugzilla_Login"); - login = env ? env : settings["Login"].c_str(); + login = env ? env : get_map_string_item_or_empty(settings, "Login"); env = getenv("Bugzilla_Password"); - password = env ? env : settings["Password"].c_str(); + password = env ? env : get_map_string_item_or_empty(settings, "Password"); if (!login[0] || !password[0]) { VERB3 log("Empty login and password"); - throw CABRTException(EXCEP_PLUGIN, _("Empty login or password, please check %s"), PLUGINS_CONF_DIR"/Bugzilla.conf"); + error_msg_and_die(_("Empty login or password, please check %s"), PLUGINS_CONF_DIR"/Bugzilla.conf"); } env = getenv("Bugzilla_BugzillaURL"); - bugzilla_url = env ? env : settings["BugzillaURL"].c_str(); + 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 : settings["SSLVerify"].c_str()); + ssl_verify = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SSLVerify")); - const char *component = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_COMPONENT); - const char *duphash = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_DUPHASH); - const char *release = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_RELEASE); + const char *component = get_crash_item_content_or_NULL(crash_data, FILENAME_COMPONENT); + const char *duphash = get_crash_item_content_or_NULL(crash_data, FILENAME_DUPHASH); + const char *release = get_crash_item_content_or_NULL(crash_data, FILENAME_OS_RELEASE); ctx bz_server(bugzilla_xmlrpc, ssl_verify); @@ -687,7 +684,8 @@ static void report_to_bugzilla( char *product = NULL; char *version = NULL; - parse_release(release, &product, &version); + parse_release_for_bz(release, &product, &version); + free(version); xmlrpc_value *result; if (strcmp(product, "Fedora") == 0) @@ -704,7 +702,7 @@ static void report_to_bugzilla( if (!all_bugs) { throw_if_xml_fault_occurred(&bz_server.env); - throw CABRTException(EXCEP_PLUGIN, _("Missing mandatory member 'bugs'")); + error_msg_and_die(_("Missing mandatory member 'bugs'")); } xmlrpc_int32 bug_id = -1; @@ -723,7 +721,7 @@ static void report_to_bugzilla( { bug_info_destroy(&bz); throw_if_xml_fault_occurred(&bz_server.env); - throw CABRTException(EXCEP_PLUGIN, _("get_bug_info() failed. Could not collect all mandatory information")); + error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information")); } if (strcmp(bz.bug_product, product) != 0) @@ -740,7 +738,7 @@ static void report_to_bugzilla( if (!all_bugs) { throw_if_xml_fault_occurred(&bz_server.env); - throw CABRTException(EXCEP_PLUGIN, _("Missing mandatory member 'bugs'")); + error_msg_and_die(_("Missing mandatory member 'bugs'")); } all_bugs_size = bz_server.get_array_size(all_bugs); @@ -756,7 +754,7 @@ static void report_to_bugzilla( { bug_info_destroy(&bz); throw_if_xml_fault_occurred(&bz_server.env); - throw CABRTException(EXCEP_PLUGIN, _("get_bug_info() failed. Could not collect all mandatory information")); + error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information")); } } else @@ -764,7 +762,6 @@ static void report_to_bugzilla( } } free(product); - free(version); if (all_bugs_size < 0) { @@ -773,15 +770,17 @@ static void report_to_bugzilla( else if (all_bugs_size == 0) // Create new bug { log(_("Creating a new bug...")); - bug_id = bz_server.new_bug(pCrashData, depend_on_bugno); + bug_id = bz_server.new_bug(crash_data, depend_on_bugno); if (bug_id < 0) { throw_if_xml_fault_occurred(&bz_server.env); - throw CABRTException(EXCEP_PLUGIN, _("Bugzilla entry creation failed")); + error_msg_and_die(_("Bugzilla entry creation failed")); } - log("Adding attachments to bug %d...", bug_id); - int ret = bz_server.add_attachments(to_string(bug_id).c_str(), pCrashData); + log("Adding attachments to bug %ld...", (long)bug_id); + char bug_id_str[sizeof(long)*3 + 2]; + sprintf(bug_id_str, "%ld", (long) bug_id); + int ret = bz_server.add_attachments(bug_id_str, crash_data); if (ret == -1) { throw_if_xml_fault_occurred(&bz_server.env); @@ -816,7 +815,7 @@ static void report_to_bugzilla( { VERB3 log("Bugzilla could not find a parent of bug %d", (int)original_bug_id); bug_info_destroy(&bz); - throw CABRTException(EXCEP_PLUGIN, _("Bugzilla couldn't find parent of bug %d"), (int)original_bug_id); + error_msg_and_die(_("Bugzilla couldn't find parent of bug %d"), (int)original_bug_id); } log("Bug %d is a duplicate, using parent bug %d", bug_id, (int)bz.bug_dup_id); @@ -831,7 +830,7 @@ static void report_to_bugzilla( { throw_if_xml_fault_occurred(&bz_server.env); } - throw CABRTException(EXCEP_PLUGIN, _("get_bug_info() failed. Could not collect all mandatory information")); + error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information")); } // found a bug which is not CLOSED as DUPLICATE @@ -855,13 +854,13 @@ static void report_to_bugzilla( throw_if_xml_fault_occurred(&bz_server.env); } - char *dsc = make_description_reproduce_comment(pCrashData); + char *dsc = make_description_reproduce_comment(crash_data); if (dsc) { - const char* package = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_PACKAGE); - const char* release = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_RELEASE); - const char* arch = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_ARCHITECTURE); - const char* is_private = get_crash_data_item_content_or_NULL(pCrashData, "is_private"); + const char* package = get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE); + const char* release = get_crash_item_content_or_NULL(crash_data, FILENAME_OS_RELEASE); + const char* arch = get_crash_item_content_or_NULL(crash_data, FILENAME_ARCHITECTURE); + const char* is_private = get_crash_item_content_or_NULL(crash_data, "is_private"); char *full_dsc = xasprintf("Package: %s\n" "Architecture: %s\n" @@ -895,6 +894,7 @@ static void report_to_bugzilla( (int)bug_id ); + free_crash_data(crash_data); bug_info_destroy(&bz); } @@ -904,59 +904,50 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); - map_plugin_settings_t settings; - + map_string_h *settings = new_map_string(); const char *dump_dir_name = "."; + GList *conf_file = NULL; + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [-vs] -c CONFFILE -d DIR" + "\n" + "\nReport a crash to Bugzilla" + ); enum { - OPT_s = (1 << 0), + OPT_v = 1 << 0, + OPT_s = 1 << 1, + OPT_d = 1 << 2, + OPT_c = 1 << 3, }; - int optflags = 0; - int opt; - while ((opt = getopt(argc, argv, "c:d:vs")) != -1) - { - switch (opt) - { - case 'c': - VERB1 log("Loading settings from '%s'", optarg); - LoadPluginSettings(optarg, settings); - VERB3 log("Loaded '%s'", optarg); - break; - case 'd': - dump_dir_name = optarg; - break; - case 'v': - g_verbose++; - break; - case 's': - optflags |= OPT_s; - break; - default: - /* Careful: the string below contains tabs, dont replace with spaces */ - error_msg_and_die( - "Usage: abrt-action-bugzilla -c CONFFILE -d DIR [-vs]" - "\n" - "\nReport a crash to Bugzilla" - "\n" - "\nOptions:" - "\n -c FILE Configuration file (may be given many times)" - "\n -d DIR Crash dump directory" - "\n -v Verbose" - "\n -s Log to syslog" - ); - } - } + /* 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_STRING('d', NULL, &dump_dir_name, "DIR" , _("Crash dump directory")), + OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - //DONT! our stdout/stderr goes directly to daemon, don't want to have prefix there. -// msg_prefix = xasprintf("abrt-action-bugzilla[%u]", getpid()); - - if (optflags & OPT_s) +// msg_prefix = xasprintf(PROGNAME"[%u]", getpid()); + if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } + while (conf_file) + { + char *fn = (char *)conf_file->data; + VERB1 log("Loading settings from '%s'", fn); + load_conf_file(fn, settings, /*skip key w/o values:*/ true); + VERB3 log("Loaded '%s'", fn); + conf_file = g_list_remove(conf_file, fn); + } + VERB1 log("Initializing XML-RPC library"); xmlrpc_env env; xmlrpc_env_init(&env); @@ -965,14 +956,8 @@ int main(int argc, char **argv) error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code); xmlrpc_env_clean(&env); - try - { - report_to_bugzilla(dump_dir_name, settings); - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } + report_to_bugzilla(dump_dir_name, settings); + free_map_string(settings); return 0; } diff --git a/src/plugins/abrt-action-generate-backtrace.c b/src/plugins/abrt-action-generate-backtrace.c index 64ce4082..a8c18e36 100644 --- a/src/plugins/abrt-action-generate-backtrace.c +++ b/src/plugins/abrt-action-generate-backtrace.c @@ -28,8 +28,9 @@ #define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di" static const char *dump_dir_name = "."; -static const char *debuginfo_dirs; -static int exec_timeout_sec = 60; +static const char *debuginfo_dirs = DEBUGINFO_CACHE_DIR; +/* 60 seconds was too limiting on slow machines */ +static int exec_timeout_sec = 240; static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput) @@ -131,7 +132,7 @@ static char* exec_vp(char **args, uid_t uid, int redirect_stderr, int *status) static char *get_backtrace(struct dump_dir *dd) { char *uid_str = dd_load_text(dd, FILENAME_UID); - uid_t uid = xatoi_u(uid_str); + uid_t uid = xatoi_positive(uid_str); free(uid_str); char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); dd_close(dd); @@ -244,49 +245,49 @@ static char *get_backtrace(struct dump_dir *dd) return bt; } -static char *i_opt; -static const char abrt_action_generage_backtrace_usage[] = PROGNAME" [options] -d DIR"; -enum { - OPT_v = 1 << 0, - OPT_d = 1 << 1, - OPT_i = 1 << 2, - OPT_t = 1 << 3, - OPT_s = 1 << 4, -}; -/* Keep enum above and order of options below in sync! */ -static struct options abrt_action_generate_backtrace_options[] = { - OPT__VERBOSE(&g_verbose), - OPT_STRING( 'd', NULL, &dump_dir_name, "DIR", "Crash dump directory"), - OPT_STRING( 'i', NULL, &i_opt, "dir1[:dir2]...", "Additional debuginfo directories"), - OPT_INTEGER('t', NULL, &exec_timeout_sec, "Kill gdb if it runs for more than N seconds"), - OPT_BOOL( 's', NULL, NULL, "Log to syslog"), - OPT_END() -}; - int main(int argc, char **argv) { char *env_verbose = getenv("ABRT_VERBOSE"); if (env_verbose) g_verbose = atoi(env_verbose); - unsigned opts = parse_opts(argc, argv, abrt_action_generate_backtrace_options, - abrt_action_generage_backtrace_usage); - - debuginfo_dirs = DEBUGINFO_CACHE_DIR; - if (i_opt) - { - debuginfo_dirs = xasprintf("%s:%s", DEBUGINFO_CACHE_DIR, i_opt); - } + char *i_opt = NULL; + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [options] -d DIR" + ); + enum { + OPT_v = 1 << 0, + OPT_d = 1 << 1, + OPT_i = 1 << 2, + OPT_t = 1 << 3, + OPT_s = 1 << 4, + }; + /* 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" , _("Crash dump directory")), + OPT_STRING( 'i', NULL, &i_opt , "dir1[:dir2]...", _("Additional debuginfo directories")), + OPT_INTEGER('t', NULL, &exec_timeout_sec, _("Kill gdb if it runs for more than N seconds")), + OPT_BOOL( 's', NULL, NULL , _("Log to syslog")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = PROGNAME; - + //msg_prefix = PROGNAME; if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } + if (i_opt) + { + debuginfo_dirs = xasprintf("%s:%s", DEBUGINFO_CACHE_DIR, i_opt); + } + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; @@ -294,49 +295,70 @@ int main(int argc, char **argv) char *package = dd_load_text(dd, FILENAME_PACKAGE); char *executable = dd_load_text(dd, FILENAME_EXECUTABLE); - /* Create and store backtrace */ + /* Create gdb backtrace */ /* NB: get_backtrace() closes dd */ char *backtrace_str = get_backtrace(dd); if (!backtrace_str) { backtrace_str = xstrdup(""); - VERB3 log("get_backtrace() returns NULL, broken core/gdb?"); + log("get_backtrace() returns NULL, broken core/gdb?"); } + /* Compute backtrace hash */ + struct btp_location location; + btp_location_init(&location); + char *backtrace_str_ptr = backtrace_str; + struct btp_backtrace *backtrace = btp_backtrace_parse(&backtrace_str_ptr, &location); + + /* Store gdb backtrace */ + dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return 1; - dd_save_text(dd, FILENAME_BACKTRACE, backtrace_str); + /* Don't be completely silent. gdb run takes a few seconds, + * it is useful to let user know it (maybe) worked. + */ + log(_("Backtrace is generated and saved, %u bytes"), (int)strlen(backtrace_str)); + free(backtrace_str); + + /* Store backtrace hash */ - /* Compute and store backtrace hash. */ - struct btp_location location; - btp_location_init(&location); - char *backtrace_str_ptr = backtrace_str; - struct btp_backtrace *backtrace = btp_backtrace_parse(&backtrace_str_ptr, &location); if (!backtrace) { + /* + * The parser failed. Compute the UUID from the executable + * and package only. This is not supposed to happen often. + */ VERB1 log(_("Backtrace parsing failed for %s"), dump_dir_name); VERB1 log("%d:%d: %s", location.line, location.column, location.message); - /* If the parser failed compute the UUID from the executable - and package only. This is not supposed to happen often. - Do not store the rating, as we do not know how good the - backtrace is. */ struct strbuf *emptybt = strbuf_new(); strbuf_prepend_str(emptybt, executable); strbuf_prepend_str(emptybt, package); + char hash_str[SHA1_RESULT_LEN*2 + 1]; create_hash(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(backtrace_str); free(package); free(executable); dd_close(dd); - return 2; + + /* 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; } - free(backtrace_str); /* Compute duplication hash. */ char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace); @@ -344,8 +366,10 @@ int main(int argc, char **argv) strbuf_append_str(str_hash, package); strbuf_append_str(str_hash, executable); strbuf_append_str(str_hash, str_hash_core); + char hash_str[SHA1_RESULT_LEN*2 + 1]; create_hash(hash_str, str_hash->buf); + dd_save_text(dd, FILENAME_DUPHASH, hash_str); strbuf_free(str_hash); free(str_hash_core); @@ -368,14 +392,14 @@ int main(int argc, char **argv) /* Get the function name from the crash frame. */ struct btp_frame *crash_frame = btp_backtrace_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); } btp_frame_free(crash_frame); - } + } btp_backtrace_free(backtrace); dd_close(dd); diff --git a/src/plugins/abrt-action-install-debuginfo.c b/src/plugins/abrt-action-install-debuginfo.c new file mode 100644 index 00000000..39915e59 --- /dev/null +++ b/src/plugins/abrt-action-install-debuginfo.c @@ -0,0 +1,43 @@ +#include <unistd.h> +#include <string.h> + +#define EXECUTABLE "abrt-action-install-debuginfo.py" + +static void error_msg_and_die(const char *msg, const char *arg) +{ + write(2, msg, strlen(msg)); + if (arg) + { + write(2, " '", 2); + write(2, msg, strlen(msg)); + write(2, "'", 1); + } + write(2, "\n", 1); + exit(1); +} + + +/* A binary wrapper is needed around python scripts if we want + * to run them in sgid/suid mode. + * + * This is such a wrapper. + */ +int main(int argc, char **argv) +{ + /* + * We disallow passing of arguments which point to writable dirs. + * This way, the script will always use default arguments. + */ + char **pp = argv; + char *arg; + while ((arg = *++pp) != NULL) + { + if (strncmp(arg, "--cache", 7) == 0) + error_msg_and_die("bad option", arg); + if (strncmp(arg, "--tmpdir", 8) == 0) + error_msg_and_die("bad option", arg); + } + + execvp(EXECUTABLE, argv); + error_msg_and_die("Can't execute", EXECUTABLE); +} diff --git a/src/plugins/abrt-action-install-debuginfo.py b/src/plugins/abrt-action-install-debuginfo.py index b16cc3e9..9253c87f 100755 --- a/src/plugins/abrt-action-install-debuginfo.py +++ b/src/plugins/abrt-action-install-debuginfo.py @@ -6,6 +6,7 @@ from subprocess import Popen, PIPE import sys import os +import time import getopt import shutil from yum import _, YumBase @@ -51,7 +52,11 @@ def unmute_stdout(): def ask_yes_no(prompt, retries=4): while True: - response = raw_input(prompt) + try: + response = raw_input(prompt) + except EOFError: + log1("got eof, probably executed from helper, assuming - yes") + response = 'y' if response in ('y', 'Y'): return True if response in ('n', 'N', ''): @@ -65,30 +70,30 @@ def ask_yes_no(prompt, retries=4): # ..that can lead to: foo.c No such file and directory # files is not used... def unpack_rpm(package_nevra, files, tmp_dir, destdir, keeprpm): - package_file_suffix = ".rpm" - package_full_path = tmp_dir + "/" + package_nevra + package_file_suffix + package_name = package_nevra + ".rpm" + package_full_path = tmp_dir + "/" + package_name log1("Extracting %s to %s" % (package_full_path, destdir)) log2(files) - print (_("Extracting cpio from %s") % (package_full_path)) + print _("Extracting cpio from %s") % (package_full_path) unpacked_cpio_path = tmp_dir + "/unpacked.cpio" try: unpacked_cpio = open(unpacked_cpio_path, 'wb') except IOError, ex: - print (_("Can't write to:"), (unpacked_cpio_path,ex)) + print _("Can't write to '%s': %s") % (unpacked_cpio_path, ex) return RETURN_FAILURE rpm2cpio = Popen(["rpm2cpio", package_full_path], - stdout=unpacked_cpio, bufsize=-1) + stdout = unpacked_cpio, bufsize = -1) retcode = rpm2cpio.wait() if retcode == 0: log1("cpio written OK") if not keeprpm: log1("keeprpms = False, removing %s" % package_full_path) - print _("Removing the temporary rpm file") + #print _("Removing temporary rpm file") os.unlink(package_full_path) else: unpacked_cpio.close() - print (_("Can't extract package: %s") % package_full_path) + print _("Can't extract package '%s'") % package_full_path return RETURN_FAILURE # close the file @@ -96,18 +101,17 @@ def unpack_rpm(package_nevra, files, tmp_dir, destdir, keeprpm): # and open it for reading unpacked_cpio = open(unpacked_cpio_path, 'rb') - print (_("Caching files from %s made from %s") % - (unpacked_cpio_path, package_full_path)) + print _("Caching files from %s made from %s") % ("unpacked.cpio", package_name) cpio = Popen(["cpio","-i", "-d", "--quiet"], stdin=unpacked_cpio, cwd=destdir, bufsize=-1) retcode = cpio.wait() if retcode == 0: log1("files extracted OK") - print _("Removing the temporary cpio file") + #print _("Removing temporary cpio file") os.unlink(unpacked_cpio_path) else: - print (_("Can't extract files from: %s") % unpacked_cpio_path) + print _("Can't extract files from '%s'") % unpacked_cpio_path return RETURN_FAILURE class MyDownloadCallback(DownloadBaseCallback): @@ -115,36 +119,42 @@ class MyDownloadCallback(DownloadBaseCallback): self.total_pkgs = total_pkgs self.downloaded_pkgs = 0 self.last_pct = 0 + self.last_time = 0 DownloadBaseCallback.__init__(self) def updateProgress(self, name, frac, fread, ftime): - pct = int( frac*100 ) + pct = int(frac * 100) if pct == self.last_pct: log2("percentage is the same, not updating progress") return self.last_pct = pct - # if run from terminal we can have a fancy output + # if run from terminal we can have fancy output if sys.stdout.isatty(): - sys.stdout.write("\033[sDownloading (%i of %i) %.30s : %.3s %%\033[u" - % (self.downloaded_pkgs + 1, self.total_pkgs, - name, pct) - ) + sys.stdout.write("\033[sDownloading (%i of %i) %s: %3u%%\033[u" + % (self.downloaded_pkgs + 1, self.total_pkgs, name, pct) + ) if pct == 100: - print _("Downloading (%i of %i) %.30s : %.3s %%" - % (self.downloaded_pkgs + 1, self.total_pkgs, - name, pct) - ) + print (_("Downloading (%i of %i) %s: %3u%%") + % (self.downloaded_pkgs + 1, self.total_pkgs, name, pct) + ) # but we want machine friendly output when spawned from abrt-server else: - print (_("Downloading (%i of %i) %.30s : %.3s %%") - % (self.downloaded_pkgs + 1, self.total_pkgs, name, pct) - ) + t = time.time() + if self.last_time == 0: + self.last_time = t + # update only every 10 seconds + if pct == 100 or self.last_time > t or t - self.last_time >= 10: + print (_("Downloading (%i of %i) %s: %3u%%") + % (self.downloaded_pkgs + 1, self.total_pkgs, name, pct) + ) + self.last_time = t + if pct == 100: + self.last_time = 0 sys.stdout.flush() class DebugInfoDownload(YumBase): - """abrt-debuginfo-install --core=CORE tmpdir cachedir""" def __init__(self, cache, tmp, keep_rpms=False): self.cachedir = cache self.tmpdir = tmp @@ -166,13 +176,13 @@ class DebugInfoDownload(YumBase): if not files: return - print _("Searching the missing debuginfo packages") - # this suppress yum messages about setting up repositories - mute_stdout() + if verbose == 0: + # this suppress yum messages about setting up repositories + mute_stdout() # make yumdownloader work as non root user. if not self.setCacheDir(): - self.logger.error("Error: Could not make cachedir, exiting") + self.logger.error("Error: can't make cachedir, exiting") sys.exit(50) # disable all not needed @@ -191,13 +201,14 @@ class DebugInfoDownload(YumBase): self.repos.populateSack(mdtype='metadata', cacheonly=1) self.repos.populateSack(mdtype='filelists', cacheonly=1) - # re-enable the output to stdout - unmute_stdout() + if verbose == 0: + # re-enable the output to stdout + unmute_stdout() not_found = [] package_files_dict = {} for debuginfo_path in files: - log2("yum whatprovides %s" %debuginfo_path) + log2("yum whatprovides %s" % debuginfo_path) pkg = self.pkgSack.searchFiles(debuginfo_path) # sometimes one file is provided by more rpms, we can use either of # them, so let's use the first match @@ -210,29 +221,23 @@ class DebugInfoDownload(YumBase): installed_size += float(pkg[0].installedsize) total_pkgs += 1 - log2("found pkg for %s" % debuginfo_path) + log2("found pkg for %s: %s" % (debuginfo_path, pkg[0])) else: log2("not found pkg for %s" % debuginfo_path) not_found.append(debuginfo_path) # connect our progress update callback dnlcb = MyDownloadCallback(total_pkgs) - self.repos.setProgressBar( dnlcb ) - - log1("%i files in %i packages" % (len(files), total_pkgs)) + self.repos.setProgressBar(dnlcb) - print (_("To download: (%.2f) M / Installed size: %.2f M" % - ( - todownload_size / (1024**2), - installed_size / (1024**2)) - ) - ) - #print _("%i debug infos not found" % len(not_found)) - - log1("packages: %i\nTo download: %f \nUnpacked size: %f" % - (total_pkgs, - todownload_size / (1024**2), - installed_size / (1024**2))) + if verbose != 0 or len(not_found) != 0: + print _("Can't find packages for %u debuginfo files") % len(not_found) + if verbose != 0 or total_pkgs != 0: + print _("Found %u packages to download") % total_pkgs + print _("Downloading %.2fMb, installed size: %.2fMb") % ( + todownload_size / (1024**2), + installed_size / (1024**2) + ) # ask only if we have terminal, because for now we don't have a way # how to pass the question to gui and the response back @@ -271,13 +276,13 @@ class DebugInfoDownload(YumBase): downloaded_pkgs += 1 - if not self.keeprpms: + if not self.keeprpms and os.path.exists(self.tmpdir): print (_("All downloaded packages have been extracted, removing %s") % self.tmpdir) try: os.rmdir(self.tmpdir) except OSError: - print _("Can't remove %s, probably contains an error log") + print _("Can't remove %s, probably contains an error log" % self.tmpdir) verbose = 0 def log1(message): @@ -302,8 +307,7 @@ def extract_info_from_core(corefile): #SEP = 3 EXECUTABLE = 4 - print (_("Analyzing corefile: %(corefile_path)s") % - {"corefile_path":corefile}) + print _("Analyzing corefile '%s'") % corefile eu_unstrip_OUT = Popen(["eu-unstrip","--core=%s" % corefile, "-n"], stdout=PIPE, bufsize=-1).communicate()[0] # parse eu_unstrip_OUT and return the list of build_ids @@ -323,7 +327,7 @@ def extract_info_from_core(corefile): #print eu_unstrip_OUT # we failed to get build ids from the core -> die if not eu_unstrip_OUT: - log1("can't get build ids from the core") + print "Can't get build ids from %s" % corefile return RETURN_FAILURE lines = eu_unstrip_OUT.split('\n') @@ -344,7 +348,7 @@ def extract_info_from_core(corefile): libraries.add(library) build_ids.add(build_id) else: - log2("skipping line %s" % line) + log2("skipping line '%s'" % line) log1("Found %i build_ids" % len(build_ids)) log1("Found %i libs" % len(libraries)) return build_ids @@ -354,7 +358,7 @@ def build_ids_to_path(build_ids): build_id1=${build_id:0:2} build_id2=${build_id:2} file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug" - """ + """ return ["/usr/lib/debug/.build-id/%s/%s.debug" % (b_id[:2], b_id[2:]) for b_id in build_ids] # beware this finds only missing libraries, but not the executable itself .. @@ -381,9 +385,7 @@ def clean_up(): try: shutil.rmtree(tmpdir) except OSError, ex: - print (_("Can't remove %(tmpdir_path)s: %(reason)s") - % {"tmpdir_path":tmpdir, "reason": ex } - ) + print _("Can't remove '%s': %s") % (tmpdir, ex) def sigterm_handler(signum, frame): clean_up() @@ -391,10 +393,11 @@ def sigterm_handler(signum, frame): def sigint_handler(signum, frame): clean_up() - print "\n", _("Exiting on user Command") + print "\n", _("Exiting on user command") exit(RETURN_OK) import signal + if __name__ == "__main__": # abrt-server can send SIGTERM to abort the download signal.signal(signal.SIGTERM, sigterm_handler) @@ -404,15 +407,14 @@ if __name__ == "__main__": cachedir = None tmpdir = None keeprpms = False - result = RETURN_OK noninteractive = False # localization init_gettext() - help_text = _("Usage: %s --core=<COREFILE> " - "--tmpdir=<TMPDIR> " - "--cachedir=<CACHEDIR>") % sys.argv[0] + help_text = _("Usage: %s --core=COREFILE " + "--tmpdir=TMPDIR " + "--cache=CACHEDIR") % sys.argv[0] try: opts, args = getopt.getopt(sys.argv[1:], "vyhc:", ["help", "core=", "cache=", "tmpdir=", @@ -426,7 +428,7 @@ if __name__ == "__main__": verbose += 1 elif opt == "-y": noninteractive = True - elif opt in ("--core","-c"): + elif opt in ("--core", "-c"): core = arg elif opt in ("--cache"): cachedir = arg @@ -443,30 +445,26 @@ if __name__ == "__main__": print help_text exit(RETURN_FAILURE) if not cachedir: - print _("You have to specify the path to cachedir.") - print help_text - exit(RETURN_FAILURE) + cachedir = "/var/cache/abrt-di" if not tmpdir: - print _("You have to specify the path to tmpdir.") - print help_text - exit(RETURN_FAILURE) + # security people prefer temp subdirs in app's private dir, like /var/run/abrt + # for now, we use /tmp... + tmpdir = "/tmp/abrt-tmp-debuginfo-%s.%u" % (time.strftime("%Y-%m-%d-%H:%M:%S"), os.getpid()) b_ids = extract_info_from_core(core) if b_ids == RETURN_FAILURE: exit(RETURN_FAILURE) + missing = filter_installed_debuginfos(b_ids, cachedir) if missing: log2(missing) + print _("Coredump references %u debuginfo files, %u of them are not installed") % (len(b_ids), len(missing)) downloader = DebugInfoDownload(cache=cachedir, tmp=tmpdir) result = downloader.download(missing) - else: - print _("All debuginfo seems to be available") - exit(RETURN_OK) - - missing = filter_installed_debuginfos(b_ids, cachedir) - for bid in missing: - log1("MISSING:%s" % bid) - - print _("Complete!") - exit(result) + missing = filter_installed_debuginfos(b_ids, cachedir) + for bid in missing: + print _("Missing debuginfo file: %s") % bid + exit(result) + print _("All %u debuginfo files are available") % len(b_ids) + exit(RETURN_OK) diff --git a/src/plugins/abrt-action-kerneloops.cpp b/src/plugins/abrt-action-kerneloops.c index dea6df17..8d00da52 100644 --- a/src/plugins/abrt-action-kerneloops.cpp +++ b/src/plugins/abrt-action-kerneloops.c @@ -19,8 +19,7 @@ #include <curl/curl.h> #include "abrtlib.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" +#include "parse_options.h" #define PROGNAME "abrt-action-kerneloops" @@ -85,26 +84,21 @@ static CURLcode http_post_to_kerneloops_site(const char *url, const char *oopsda static void report_to_kerneloops( const char *dump_dir_name, - const map_plugin_settings_t& settings) + map_string_h *settings) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) exit(1); /* error msg is already logged */ - map_crash_data_t pCrashData; - load_crash_data_from_crash_dump_dir(dd, pCrashData); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); dd_close(dd); - const char *backtrace = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_BACKTRACE); + const char *backtrace = get_crash_item_content_or_NULL(crash_data, FILENAME_BACKTRACE); if (!backtrace) error_msg_and_die("Error sending kernel oops due to missing backtrace"); - map_plugin_settings_t::const_iterator end = settings.end(); - map_plugin_settings_t::const_iterator it; - const char *env = getenv("KerneloopsReporter_SubmitURL"); - it = settings.find("SubmitURL"); - const char *submitURL = (env ? env : it == end ? "" : it->second.c_str()); + const char *submitURL = (env ? env : get_map_string_item_or_empty(settings, "SubmitURL")); if (!submitURL[0]) submitURL = "http://submit.kerneloops.org/submitoops.php"; @@ -114,6 +108,8 @@ static void report_to_kerneloops( if (ret != CURLE_OK) error_msg_and_die("Kernel oops has not been sent due to %s", curl_easy_strerror(ret)); + free_crash_data(crash_data); + /* Server replies with: * 200 thank you for submitting the kernel oops information * RemoteIP: 34192fd15e34bf60fac6a5f01bba04ddbd3f0558 @@ -128,67 +124,52 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); - map_plugin_settings_t settings; - + map_string_h *settings = new_map_string(); const char *dump_dir_name = "."; + GList *conf_file = NULL; + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [-vs] -c CONFFILE -d DIR" + "\n" + "\nReport a kernel oops to kerneloops.org (or similar) site" + ); enum { - OPT_s = (1 << 0), + OPT_v = 1 << 0, + OPT_s = 1 << 1, + OPT_d = 1 << 2, + OPT_c = 1 << 3, }; - int optflags = 0; - int opt; - while ((opt = getopt(argc, argv, "c:d:vs")) != -1) - { - switch (opt) - { - case 'c': - VERB1 log("Loading settings from '%s'", optarg); - LoadPluginSettings(optarg, settings); - VERB3 log("Loaded '%s'", optarg); - break; - case 'd': - dump_dir_name = optarg; - break; - case 'v': - g_verbose++; - break; - case 's': - optflags |= OPT_s; - break; - default: - /* Careful: the string below contains tabs, dont replace with spaces */ - error_msg_and_die( - "Usage: "PROGNAME" -c CONFFILE -d DIR [-vs]" - "\n" - "\nReport a kernel oops to kerneloops.org (or similar) site" - "\n" - "\nOptions:" - "\n -c FILE Configuration file (may be given many times)" - "\n -d DIR Crash dump directory" - "\n -v Verbose" - "\n -s Log to syslog" - ); - } - } + /* 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_STRING('d', NULL, &dump_dir_name, "DIR" , _("Crash dump directory")), + OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - //DONT! our stdout/stderr goes directly to daemon, don't want to have prefix there. // msg_prefix = xasprintf(PROGNAME"[%u]", getpid()); - - if (optflags & OPT_s) + if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } - try + while (conf_file) { - report_to_kerneloops(dump_dir_name, settings); - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); + char *fn = (char *)conf_file->data; + VERB1 log("Loading settings from '%s'", fn); + load_conf_file(fn, settings, /*skip key w/o values:*/ true); + VERB3 log("Loaded '%s'", fn); + conf_file = g_list_remove(conf_file, fn); } + report_to_kerneloops(dump_dir_name, settings); + + free_map_string(settings); return 0; } diff --git a/src/plugins/abrt-action-mailx.cpp b/src/plugins/abrt-action-mailx.c index fa7fd8a0..3debf449 100644 --- a/src/plugins/abrt-action-mailx.cpp +++ b/src/plugins/abrt-action-mailx.c @@ -21,8 +21,6 @@ #include "abrtlib.h" #include "parse_options.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" #define PROGNAME "abrt-action-mailx" @@ -47,73 +45,71 @@ static void exec_and_feed_input(uid_t uid, const char* text, char **args) error_msg_and_die("Error running '%s'", args[0]); } -static char** append_str_to_vector(char **vec, unsigned &size, const char *str) +static char** append_str_to_vector(char **vec, unsigned *size_p, const char *str) { //log("old vec: %p", vec); + unsigned size = *size_p; vec = (char**) xrealloc(vec, (size+2) * sizeof(vec[0])); vec[size] = xstrdup(str); //log("new vec: %p, added [%d] %p", vec, size, vec[size]); size++; vec[size] = NULL; + *size_p = size; return vec; } static void create_and_send_email( const char *dump_dir_name, - const map_plugin_settings_t& settings) + 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 */ - map_crash_data_t pCrashData; - load_crash_data_from_crash_dump_dir(dd, pCrashData); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); dd_close(dd); char* env; - map_plugin_settings_t::const_iterator end = settings.end(); - map_plugin_settings_t::const_iterator it; env = getenv("Mailx_Subject"); - it = settings.find("Subject"); - const char *subject = xstrdup(env ? env : (it != end ? it->second.c_str() : "[abrt] full crash report")); + const char *subject = (env ? env : get_map_string_item_or_NULL(settings, "Subject") ? : "[abrt] full crash report"); env = getenv("Mailx_EmailFrom"); - it = settings.find("EmailFrom"); - const char *email_from = (env ? env : (it != end ? it->second.c_str() : "user@localhost")); + const char *email_from = (env ? env : get_map_string_item_or_NULL(settings, "EmailFrom") ? : "user@localhost"); env = getenv("Mailx_EmailTo"); - it = settings.find("EmailTo"); - const char *email_to = (env ? env : (it != end ? it->second.c_str() : "root@localhost")); + const char *email_to = (env ? env : get_map_string_item_or_NULL(settings, "EmailTo") ? : "root@localhost"); env = getenv("Mailx_SendBinaryData"); - it = settings.find("SendBinaryData"); - bool send_binary_data = string_to_bool(env ? env : (it != end ? it->second.c_str() : "0")); + 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"); + args = append_str_to_vector(args, &arg_size, "/bin/mailx"); - char *dsc = make_description_mailx(pCrashData); + char *dsc = make_description_mailx(crash_data); if (send_binary_data) { - map_crash_data_t::const_iterator it_cd; - for (it_cd = pCrashData.begin(); it_cd != pCrashData.end(); it_cd++) + GHashTableIter iter; + char *name; + struct crash_item *value; + g_hash_table_iter_init(&iter, crash_data); + while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { - if (it_cd->second[CD_TYPE] == CD_BIN) + if (value->flags & CD_FLAG_BIN) { - args = append_str_to_vector(args, arg_size, "-a"); - args = append_str_to_vector(args, arg_size, it_cd->second[CD_CONTENT].c_str()); + 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); + 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...")); - const char *uid_str = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_UID); - exec_and_feed_input(xatoi_u(uid_str), dsc, args); + const char *uid_str = get_crash_item_content_or_NULL(crash_data, FILENAME_UID); + exec_and_feed_input(xatoi_positive(uid_str), dsc, args); free(dsc); @@ -122,6 +118,8 @@ static void create_and_send_email( args -= arg_size; free(args); + free_crash_data(crash_data); + log("Email was sent to: %s", email_to); } @@ -134,7 +132,8 @@ int main(int argc, char **argv) const char *dump_dir_name = "."; const char *conf_file = NULL; - const char *program_usage = _( + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( PROGNAME" [-v] -d DIR [-c CONFFILE]\n" "\n" "Upload compressed tarball of crash dump" @@ -151,29 +150,22 @@ int main(int argc, char **argv) OPT_STRING('c', NULL, &conf_file , "CONFFILE", _("Config file")), OPT_END() }; - - /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage); + /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); //msg_prefix = PROGNAME; - //if (optflags & OPT_s) + //if (opts & OPT_s) //{ // openlog(msg_prefix, 0, LOG_DAEMON); // logmode = LOGMODE_SYSLOG; //} - map_plugin_settings_t settings; + map_string_h *settings = new_map_string(); if (conf_file) - LoadPluginSettings(conf_file, settings); + load_conf_file(conf_file, settings, /*skip key w/o values:*/ true); - try - { - create_and_send_email(dump_dir_name, settings); - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } + create_and_send_email(dump_dir_name, settings); + free_map_string(settings); return 0; } diff --git a/src/plugins/abrt-action-print.cpp b/src/plugins/abrt-action-print.c index 303c05f7..cc7fbb34 100644 --- a/src/plugins/abrt-action-print.cpp +++ b/src/plugins/abrt-action-print.c @@ -20,8 +20,6 @@ */ #include "abrtlib.h" #include "parse_options.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" #define PROGNAME "abrt-action-print" @@ -35,10 +33,12 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); - const char *program_usage = _( + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( PROGNAME" [-v] [-o FILE] -d DIR\n" "\n" - "Print information about the crash to standard output"); + "Print information about the crash to standard output" + ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, @@ -51,8 +51,7 @@ int main(int argc, char **argv) OPT_STRING('o', NULL, &output_file , "FILE", _("Output file")), OPT_END() }; - - /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage); + /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); //msg_prefix = PROGNAME; @@ -75,25 +74,17 @@ int main(int argc, char **argv) } } - try - { - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - return 1; /* error message is already logged */ + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return 1; /* error message is already logged */ - map_crash_data_t pCrashData; - load_crash_data_from_crash_dump_dir(dd, pCrashData); - dd_close(dd); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); + dd_close(dd); - char *dsc = make_description_logger(pCrashData); - fputs(dsc, stdout); - free(dsc); - } - catch (CABRTException& e) - { - log("%s", e.what()); - return 1; - } + char *dsc = make_description_logger(crash_data); + fputs(dsc, stdout); + free(dsc); + free_crash_data(crash_data); if (output_file) { diff --git a/src/plugins/abrt-action-rhtsupport.cpp b/src/plugins/abrt-action-rhtsupport.c index eb69489d..94523e08 100644 --- a/src/plugins/abrt-action-rhtsupport.cpp +++ b/src/plugins/abrt-action-rhtsupport.c @@ -22,21 +22,19 @@ #include "abrt_curl.h" #include "abrt_xmlrpc.h" #include "abrt_rh_support.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" +#include "parse_options.h" #define PROGNAME "abrt-action-rhtsupport" static void report_to_rhtsupport( const char *dump_dir_name, - const map_plugin_settings_t& settings) + 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 */ - map_crash_data_t pCrashData; - load_crash_data_from_crash_dump_dir(dd, pCrashData); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); dd_close(dd); /* Gzipping e.g. 0.5gig coredump takes a while. Let client know what we are doing */ @@ -54,34 +52,31 @@ static void report_to_rhtsupport( const char* package; char* env; - map_plugin_settings_t::const_iterator end = settings.end(); - map_plugin_settings_t::const_iterator it; - env = getenv("RHTSupport_URL"); - it = settings.find("URL"); - char *url = xstrdup(env ? env : it == end ? "https://api.access.redhat.com/rs" : it->second.c_str()); + char *url = xstrdup(env ? env : (get_map_string_item_or_NULL(settings, "URL") ? : "https://api.access.redhat.com/rs")); env = getenv("RHTSupport_Login"); - it = settings.find("Login"); - char *login = xstrdup(env ? env : it == end ? "" : it->second.c_str()); + char *login = xstrdup(env ? env : get_map_string_item_or_empty(settings, "Login")); env = getenv("RHTSupport_Password"); - it = settings.find("Password"); - char *password = xstrdup(env ? env : it == end ? "" : it->second.c_str()); + char *password = xstrdup(env ? env : get_map_string_item_or_empty(settings, "Password")); env = getenv("RHTSupport_SSLVerify"); - it = settings.find("SSLVerify"); - bool ssl_verify = string_to_bool(env ? env : it == end ? "1" : it->second.c_str()); + bool ssl_verify = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SSLVerify")); if (!login[0] || !password[0]) { - errmsg = _("Empty login or password, please check RHTSupport.conf"); - goto ret; + free_crash_data(crash_data); + free(url); + free(login); + free(password); + error_msg_and_die(_("Empty login or password, please check RHTSupport.conf")); + return; } - package = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_PACKAGE); - reason = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_REASON); - function = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_CRASH_FUNCTION); + package = get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE); + reason = get_crash_item_content_or_NULL(crash_data, FILENAME_REASON); + function = get_crash_item_content_or_NULL(crash_data, FILENAME_CRASH_FUNCTION); { struct strbuf *buf_summary = strbuf_new(); @@ -92,7 +87,7 @@ static void report_to_rhtsupport( strbuf_append_strf(buf_summary, ": %s", reason); summary = strbuf_free_nobuf(buf_summary); - char *bz_dsc = make_description_bz(pCrashData); + char *bz_dsc = make_description_bz(crash_data); dsc = xasprintf("abrt version: "VERSION"\n%s", bz_dsc); free(bz_dsc); } @@ -100,7 +95,7 @@ static void report_to_rhtsupport( file = new_reportfile(); /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - tempfile = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu.tar.gz", (long)getpid(), (long)time(NULL)); + tempfile = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%s-%lu.tar.gz", iso_date_string(NULL), (long)getpid()); int pipe_from_parent_to_child[2]; xpipe(pipe_from_parent_to_child); @@ -124,21 +119,23 @@ static void report_to_rhtsupport( } { - map_crash_data_t::const_iterator it = pCrashData.begin(); - for (; it != pCrashData.end(); it++) + GHashTableIter iter; + char *name; + struct crash_item *value; + g_hash_table_iter_init(&iter, crash_data); + while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { - if (it->first == FILENAME_COUNT) continue; - if (it->first == CD_DUMPDIR) continue; - if (it->first == FILENAME_INFORMALL) continue; - if (it->first == FILENAME_MESSAGE) continue; // plugin's status message (if we already reported it yesterday) - if (it->first == FILENAME_DESCRIPTION) continue; // package description - - const char *content = it->second[CD_CONTENT].c_str(); - if (it->second[CD_TYPE] == CD_TXT) + if (strcmp(name, FILENAME_COUNT) == 0) continue; + if (strcmp(name, CD_DUMPDIR) == 0) continue; + if (strcmp(name, FILENAME_INFORMALL) == 0) continue; + if (strcmp(name, FILENAME_MESSAGE) == 0) continue; // plugin's status message (if we already reported it yesterday) + + const char *content = value->content; + if (value->flags & CD_FLAG_TXT) { - reportfile_add_binding_from_string(file, it->first.c_str(), content); + reportfile_add_binding_from_string(file, name, content); } - else if (it->second[CD_TYPE] == CD_BIN) + else if (value->flags & CD_FLAG_BIN) { const char *basename = strrchr(content, '/'); if (basename) @@ -148,7 +145,7 @@ static void report_to_rhtsupport( char *xml_name = concat_path_file("content", basename); reportfile_add_binding_from_namedfile(file, /*on_disk_filename */ content, - /*binding_name */ it->first.c_str(), + /*binding_name */ name, /*recorded_filename*/ xml_name, /*binary */ 1); if (tar_append_file(tar, (char*)content, xml_name) != 0) @@ -248,6 +245,7 @@ static void report_to_rhtsupport( free(url); free(login); free(password); + free_crash_data(crash_data); if (errmsg) error_msg_and_die("%s", errmsg); @@ -259,59 +257,50 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); - map_plugin_settings_t settings; - + map_string_h *settings = new_map_string(); const char *dump_dir_name = "."; + GList *conf_file = NULL; + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [-vs] -c CONFFILE -d DIR" + "\n" + "\nReport a crash to RHTSupport" + ); enum { - OPT_s = (1 << 0), + OPT_v = 1 << 0, + OPT_s = 1 << 1, + OPT_d = 1 << 2, + OPT_c = 1 << 3, }; - int optflags = 0; - int opt; - while ((opt = getopt(argc, argv, "c:d:vs")) != -1) - { - switch (opt) - { - case 'c': - VERB1 log("Loading settings from '%s'", optarg); - LoadPluginSettings(optarg, settings); - VERB3 log("Loaded '%s'", optarg); - break; - case 'd': - dump_dir_name = optarg; - break; - case 'v': - g_verbose++; - break; - case 's': - optflags |= OPT_s; - break; - default: - /* Careful: the string below contains tabs, dont replace with spaces */ - error_msg_and_die( - "Usage: "PROGNAME" -c CONFFILE -d DIR [-vs]" - "\n" - "\nReport a crash to RHTSupport" - "\n" - "\nOptions:" - "\n -c FILE Configuration file (may be given many times)" - "\n -d DIR Crash dump directory" - "\n -v Verbose" - "\n -s Log to syslog" - ); - } - } + /* 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_STRING('d', NULL, &dump_dir_name, "DIR" , _("Crash dump directory")), + OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - //DONT! our stdout/stderr goes directly to daemon, don't want to have prefix there. // msg_prefix = xasprintf(PROGNAME"[%u]", getpid()); - - if (optflags & OPT_s) + if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } + while (conf_file) + { + char *fn = (char *)conf_file->data; + VERB1 log("Loading settings from '%s'", fn); + load_conf_file(fn, settings, /*skip key w/o values:*/ true); + VERB3 log("Loaded '%s'", fn); + conf_file = g_list_remove(conf_file, fn); + } + VERB1 log("Initializing XML-RPC library"); xmlrpc_env env; xmlrpc_env_init(&env); @@ -320,14 +309,8 @@ int main(int argc, char **argv) error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code); xmlrpc_env_clean(&env); - try - { - report_to_rhtsupport(dump_dir_name, settings); - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } + report_to_rhtsupport(dump_dir_name, settings); + free_map_string(settings); return 0; } diff --git a/src/plugins/abrt-action-upload.cpp b/src/plugins/abrt-action-upload.c index 9741f543..88380bd7 100644 --- a/src/plugins/abrt-action-upload.cpp +++ b/src/plugins/abrt-action-upload.c @@ -21,8 +21,6 @@ #include <curl/curl.h> #include "abrtlib.h" #include "parse_options.h" -#include "abrt_crash_dump.h" -#include "abrt_exception.h" #define PROGNAME "abrt-action-upload" @@ -104,7 +102,7 @@ static int send_file(const char *url, const char *filename) static int create_and_upload_archive( const char *dump_dir_name, - const map_plugin_settings_t& settings) + map_string_h *settings) { int result = 0; @@ -125,16 +123,12 @@ static int create_and_upload_archive( //ArchiveType = .tar.bz2 //ExcludeFiles = foo,bar*,b*z char* env; - map_plugin_settings_t::const_iterator end = settings.end(); - map_plugin_settings_t::const_iterator it; - env = getenv("Upload_URL"); - it = settings.find("URL"); - const char *url = (env ? env : (it == end ? NULL : it->second.c_str())); + const char *url = (env ? env : get_map_string_item_or_empty(settings, "URL")); /* Create a child gzip which will compress the data */ /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - tempfile = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu.tar.gz", (long)getpid(), (long)time(NULL)); + tempfile = xasprintf(LOCALSTATEDIR"/run/abrt/upload-%s-%lu.tar.gz", iso_date_string(NULL), (long)getpid()); int pipe_from_parent_to_child[2]; xpipe(pipe_from_parent_to_child); child = fork(); @@ -167,7 +161,6 @@ static int create_and_upload_archive( if (strcmp(short_name, CD_DUMPDIR) == 0) goto next; if (strcmp(short_name, FILENAME_INFORMALL) == 0) goto next; if (strcmp(short_name, FILENAME_MESSAGE) == 0) goto next; // plugin's status message (if we already reported it yesterday) - if (strcmp(short_name, FILENAME_DESCRIPTION) == 0) goto next; // package description // dd_get_next_file guarantees this: //struct stat stbuf; //if (stat(full_name, &stbuf) != 0) @@ -249,7 +242,8 @@ int main(int argc, char **argv) const char *conf_file = NULL; const char *url = NULL; - const char *program_usage = _( + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( PROGNAME" [-v] -d DIR [-c CONFFILE] [-u URL]\n" "\n" "Upload compressed tarball of crash dump" @@ -268,32 +262,24 @@ int main(int argc, char **argv) OPT_STRING('u', NULL, &url , "URL" , _("Base URL to upload to")), OPT_END() }; - - /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage); + /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); //msg_prefix = PROGNAME; - //if (optflags & OPT_s) + //if (opts & OPT_s) //{ // openlog(msg_prefix, 0, LOG_DAEMON); // logmode = LOGMODE_SYSLOG; //} - map_plugin_settings_t settings; + map_string_h *settings = new_map_string(); if (url) - settings["URL"] = url; + g_hash_table_replace(settings, xstrdup("URL"), xstrdup(url)); if (conf_file) - LoadPluginSettings(conf_file, settings); + load_conf_file(conf_file, settings, /*skip key w/o values:*/ true); - int result = 0; - try - { - result = create_and_upload_archive(dump_dir_name, settings); - } - catch (CABRTException& e) - { - error_msg_and_die("%s", e.what()); - } + int result = create_and_upload_archive(dump_dir_name, settings); + free_map_string(settings); return result; } diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c new file mode 100644 index 00000000..5b6a2062 --- /dev/null +++ b/src/plugins/abrt-dump-oops.c @@ -0,0 +1,710 @@ +/* + Copyright (C) 2011 ABRT team + Copyright (C) 2011 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + Authors: + Anton Arapov <anton@redhat.com> + Arjan van de Ven <arjan@linux.intel.com> + */ +#include <syslog.h> +#include <asm/unistd.h> /* __NR_syslog */ +#include <sys/inotify.h> +#include <sys/ioctl.h> /* ioctl(FIONREAD) */ +#include "abrtlib.h" +#include "parse_options.h" + +#define PROGNAME "abrt-dump-oops" + +static void queue_oops(GList **vec, const char *data, const char *version) +{ + char *ver_data = xasprintf("%s\n%s", version, data); + *vec = g_list_append(*vec, ver_data); +} + +/* + * extract_version tries to find the kernel version in given data + */ +static char *extract_version(const char *linepointer) +{ + if (strstr(linepointer, "Pid") + || strstr(linepointer, "comm") + || strstr(linepointer, "CPU") + || strstr(linepointer, "REGS") + || strstr(linepointer, "EFLAGS") + ) { + char* start; + char* end; + + start = strstr((char*)linepointer, "2.6."); + if (start) + { + end = strchr(start, ')'); + if (!end) + end = strchrnul(start, ' '); + return xstrndup(start, end-start); + } + } + + return NULL; +} + +/* + * extract_oops tries to find oops signatures in a log + */ +struct line_info { + char *ptr; + char level; +}; + +static int record_oops(GList **oopses, struct line_info* lines_info, int oopsstart, int oopsend) +{ + int q; + int len; + char *oops; + char *version; + + len = 2; + for (q = oopsstart; q <= oopsend; q++) + len += strlen(lines_info[q].ptr) + 1; + + oops = (char*)xzalloc(len); + + version = NULL; + for (q = oopsstart; q <= oopsend; q++) + { + if (!version) + version = extract_version(lines_info[q].ptr); + + if (lines_info[q].ptr[0]) + { + strcat(oops, lines_info[q].ptr); + strcat(oops, "\n"); + } + } + int rv = 1; + /* too short oopses are invalid */ + if (strlen(oops) > 100) + queue_oops(oopses, oops, version ? version : "undefined"); + else + { + VERB3 log("Dropped oops: too short"); + rv = 0; + } + free(oops); + free(version); + return rv; +} + +#define REALLOC_CHUNK 1000 +static int extract_oopses(GList **oopses, char *buffer, size_t buflen) +{ + char *c; + int linecount = 0; + int lines_info_alloc = 0; + struct line_info *lines_info = NULL; + + /* Split buffer into lines */ + + if (buflen != 0) + buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */ + c = buffer; + while (c < buffer + buflen) + { + char linelevel; + char *c9; + char *colon; + + c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */ + assert(c9); + *c9 = '\0'; /* turn the \n into a string termination */ + if (c9 == c) + goto next_line; + + /* Is it a syslog file (/var/log/messages or similar)? + * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx", + * some users run syslog in non-C locale: + * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah" + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!! + * We detect it by checking for N:NN:NN pattern in first 15 chars + * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled") + */ + colon = strchr(c, ':'); + if (colon && colon > c && colon < c + 15 + && isdigit(colon[-1]) /* N:... */ + && isdigit(colon[1]) /* ...N:NN:... */ + && isdigit(colon[2]) + && colon[3] == ':' + && isdigit(colon[4]) /* ...N:NN:NN... */ + && isdigit(colon[5]) + ) { + /* It's syslog file, not a bare dmesg */ + + /* Skip non-kernel lines */ + char *kernel_str = strstr(c, "kernel: "); + if (kernel_str == NULL) + { + /* if we see our own marker: + * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt" + * we know we submitted everything upto here already */ + if (strstr(c, "abrt:") && strstr(c, "Abrt")) + { + VERB3 log("Found our marker at line %d, restarting line count from 0", linecount); + linecount = 0; + lines_info_alloc = 0; + free(lines_info); + lines_info = NULL; + } + goto next_line; + } + c = kernel_str + sizeof("kernel: ")-1; + } + + linelevel = 0; + /* store and remove kernel log level */ + if (*c == '<' && c[1] && c[2] == '>') + { + linelevel = c[1]; + c += 3; + } + /* remove jiffies time stamp counter if present */ + if (*c == '[') + { + char *c2 = strchr(c, '.'); + char *c3 = strchr(c, ']'); + if (c2 && c3 && (c2 < c3) && (c3-c) < 14 && (c2-c) < 8) + { + c = c3 + 1; + if (*c == ' ') + c++; + } + } + if (linecount >= lines_info_alloc) + { + lines_info_alloc += REALLOC_CHUNK; + lines_info = (struct line_info*)xrealloc(lines_info, + lines_info_alloc * sizeof(lines_info[0])); + } + lines_info[linecount].ptr = c; + lines_info[linecount].level = linelevel; + linecount++; +next_line: + c = c9 + 1; + } + + /* Analyze lines */ + + int i; + char prevlevel = 0; + int oopsstart = -1; + int inbacktrace = 0; + int oopsesfound = 0; + + i = 0; + while (i < linecount) + { + char *curline = lines_info[i].ptr; + + if (curline == NULL) + { + i++; + continue; + } + while (*curline == ' ') + curline++; + + if (oopsstart < 0) + { + /* Find start-of-oops markers */ + /* In some comparisons, we skip 1st letter, to avoid dealing with + * changes in capitalization in kernel. For example, I see that + * current kernel git (at 2011-01-01) has both "kernel BUG at ..." + * and "Kernel BUG at ..." messages, and I don't want to change + * the code below whenever kernel is changed to use "K" (or "k") + * uniformly. + */ + if (strstr(curline, /*g*/ "eneral protection fault:")) + oopsstart = i; + else if (strstr(curline, "BUG:")) + oopsstart = i; + else if (strstr(curline, /*k*/ "ernel BUG at")) + oopsstart = i; + else if (strstr(curline, "do_IRQ: stack overflow:")) + oopsstart = i; + else if (strstr(curline, "RTNL: assertion failed")) + oopsstart = i; + else if (strstr(curline, /*e*/ "eek! page_mapcount(page) went negative!")) + oopsstart = i; + else if (strstr(curline, /*n*/ "ear stack overflow (cur:")) + oopsstart = i; + else if (strstr(curline, /*d*/ "ouble fault:")) + oopsstart = i; + else if (strstr(curline, /*b*/ "adness at")) + oopsstart = i; + else if (strstr(curline, "NETDEV WATCHDOG")) + oopsstart = i; + else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated message */ + oopsstart = i; + else if (strstr(curline, /*u*/ "nable to handle kernel")) + oopsstart = i; + else if (strstr(curline, /*s*/ "ysctl table check failed")) + oopsstart = i; + else if (strstr(curline, "INFO: possible recursive locking detected")) + oopsstart = i; + // Not needed: "--[ cut here ]--" is always followed + // by "Badness at", "kernel BUG at", or "WARNING: at" string + //else if (strstr(curline, "------------[ cut here ]------------")) + // oopsstart = i; + else if (strstr(curline, "list_del corruption")) + oopsstart = i; + else if (strstr(curline, "list_add corruption")) + oopsstart = i; + + if (i >= 3 && strstr(curline, "Oops:")) + oopsstart = i-3; + + if (oopsstart >= 0) + { + /* debug information */ + VERB3 { + log("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr); + if (oopsstart != i) + log("Trigger line is %d: '%s'", i, c); + } + /* try to find the end marker */ + int i2 = i + 1; + while (i2 < linecount && i2 < (i+50)) + { + if (strstr(lines_info[i2].ptr, "---[ end trace")) + { + inbacktrace = 1; + i = i2; + break; + } + i2++; + } + } + } + + /* Are we entering a call trace part? */ + /* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */ + if (oopsstart >= 0 && !inbacktrace) + { + if (strstr(curline, "Call Trace:")) + inbacktrace = 1; + else + if (strnlen(curline, 9) > 8 + && curline[0] == '[' && curline[1] == '<' + && strstr(curline, ">]") + && strstr(curline, "+0x") + && strstr(curline, "/0x") + ) { + inbacktrace = 1; + } + } + + /* Are we at the end of an oops? */ + else if (oopsstart >= 0 && inbacktrace) + { + int oopsend = INT_MAX; + + /* line needs to start with " [" or have "] [" if it is still a call trace */ + /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */ + if (curline[0] != '[' + && !strstr(curline, "] [") + && !strstr(curline, "--- Exception") + && !strstr(curline, "LR =") + && !strstr(curline, "<#DF>") + && !strstr(curline, "<IRQ>") + && !strstr(curline, "<EOI>") + && !strstr(curline, "<<EOE>>") + && strncmp(curline, "Code: ", 6) != 0 + && strncmp(curline, "RIP ", 4) != 0 + && strncmp(curline, "RSP ", 4) != 0 + ) { + oopsend = i-1; /* not a call trace line */ + } + /* oops lines are always more than 8 chars long */ + else if (strnlen(curline, 8) < 8) + oopsend = i-1; + /* single oopses are of the same loglevel */ + else if (lines_info[i].level != prevlevel) + oopsend = i-1; + else if (strstr(curline, "Instruction dump:")) + oopsend = i; + /* if a new oops starts, this one has ended */ + else if (strstr(curline, "WARNING: at ") && oopsstart != i) /* WARN_ON() generated message */ + oopsend = i-1; + else if (strstr(curline, "Unable to handle") && oopsstart != i) + oopsend = i-1; + /* kernel end-of-oops marker (not including marker itself) */ + else if (strstr(curline, "---[ end trace")) + oopsend = i-1; + + if (oopsend <= i) + { + VERB3 log("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr); + if (record_oops(oopses, lines_info, oopsstart, oopsend)) + oopsesfound++; + oopsstart = -1; + inbacktrace = 0; + } + } + + prevlevel = lines_info[i].level; + i++; + + if (oopsstart >= 0) + { + /* Do we have a suspiciously long oops? Cancel it */ + if (i-oopsstart > 60) + { + inbacktrace = 0; + oopsstart = -1; + VERB3 log("Dropped oops, too long"); + continue; + } + if (!inbacktrace && i-oopsstart > 40) + { + /*inbacktrace = 0; - already is */ + oopsstart = -1; + VERB3 log("Dropped oops, too long"); + continue; + } + } + } /* while (i < linecount) */ + + /* process last oops if we have one */ + if (oopsstart >= 0 && inbacktrace) + { + int oopsend = i-1; + VERB3 log("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr); + if (record_oops(oopses, lines_info, oopsstart, oopsend)) + oopsesfound++; + } + + free(lines_info); + return oopsesfound; +} + +#define MAX_SCAN_BLOCK (4*1024*1024) +#define READ_AHEAD (10*1024) + +static void scan_dmesg(GList **oops_list) +{ + VERB1 log("Scanning dmesg"); + + /* syslog(3) - read the last len bytes from the log buffer + * (non-destructively), but dont read more than was written + * into the buffer since the last "clear ring buffer" cmd. + * Returns the number of bytes read. + */ + char *buffer = xzalloc(16*1024); + syscall(__NR_syslog, 3, buffer, 16*1024 - 1); /* always NUL terminated */ + extract_oopses(oops_list, buffer, strlen(buffer)); + free(buffer); +} + +static int scan_syslog_file(GList **oops_list, int fd, struct stat *statbuf, int partial_line_len) +{ + /* fstat(fd, &statbuf) was just done by caller */ + + off_t cur_pos = lseek(fd, 0, SEEK_CUR); + if (statbuf->st_size <= cur_pos) + return partial_line_len; /* we are at EOF, nothing to do */ + + VERB3 log("File grew by %llu bytes, from %llu to %llu", + (long long)(statbuf->st_size - cur_pos), + (long long)(cur_pos), + (long long)(statbuf->st_size)); + + /* Do not try to allocate an absurd amount of memory. */ + int sz = MAX_SCAN_BLOCK - READ_AHEAD; + if (sz > statbuf->st_size - cur_pos) + sz = statbuf->st_size - cur_pos; + + /* Rewind to the beginning of the current line */ + if (partial_line_len > 0 && lseek(fd, -partial_line_len, SEEK_CUR) != (off_t)-1) + { + VERB3 log("Went back %u bytes", partial_line_len); + cur_pos -= partial_line_len; + sz += partial_line_len; + } + + /* + * In theory we have a race here, since someone can spew + * to /var/log/messages before we read it in... + * We try to deal with it by reading READ_AHEAD extra. + */ + sz += READ_AHEAD; + char *buffer = xzalloc(sz); + + partial_line_len = 0; + do { + int r = full_read(fd, buffer, sz-1); + if (r <= 0) + break; + VERB3 log("Read %u bytes", r); + + /* For future scans, try to find where last (incomplete) line starts */ + partial_line_len = 0; + char *last_newline = memrchr(buffer, '\n', r) ? : buffer-1; + partial_line_len = buffer+r - (last_newline+1); + if (partial_line_len > 500) /* cap it */ + partial_line_len = 500; + + extract_oopses(oops_list, buffer, r); + cur_pos += r; + } while (cur_pos < statbuf->st_size); + + free(buffer); + + return partial_line_len; +} + +/* returns number of errors */ +static int save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt) +{ + unsigned countdown = 16; /* do not report hundreds of oopses */ + unsigned idx = oops_cnt; + time_t t = time(NULL); + pid_t my_pid = getpid(); + + VERB1 log("Saving %u oopses as crash dump dirs", idx >= countdown ? countdown-1 : idx); + + char *tainted_str = NULL; + /* once tainted flag is set to 1, only restart can reset the flag to 0 */ + FILE *tainted_fp = fopen("/proc/sys/kernel/tainted", "r"); + if (tainted_fp) + { + tainted_str = xmalloc_fgetline(tainted_fp); + fclose(tainted_fp); + } + else + error_msg("/proc/sys/kernel/tainted does not exist"); + + int errors = 0; + + while (idx != 0 && --countdown != 0) + { + char path[sizeof(DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu") + 3 * sizeof(long)*3]; + sprintf(path, DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu", (long)t, (long)my_pid, (long)idx); + + char *first_line = (char*)g_list_nth_data(oops_list, --idx); + char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */ + *second_line++ = '\0'; + + struct dump_dir *dd = dd_create(path, /*uid:*/ 0); + if (dd) + { + dd_create_basic_files(dd, /*uid:*/ 0); + dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops"); + dd_save_text(dd, FILENAME_EXECUTABLE, "kernel"); + dd_save_text(dd, FILENAME_KERNEL, first_line); + dd_save_text(dd, FILENAME_CMDLINE, "not_applicable"); + dd_save_text(dd, FILENAME_BACKTRACE, second_line); + /* Optional, makes generated bz more informative */ + strchrnul(second_line, '\n')[0] = '\0'; + dd_save_text(dd, FILENAME_REASON, second_line); + + if (tainted_str && tainted_str[0] != '0') + dd_save_text(dd, FILENAME_TAINTED, tainted_str); + + free(tainted_str); + dd_close(dd); + } + else + errors++; + } + + return errors; +} + +int main(int argc, char **argv) +{ + char *env_verbose = getenv("ABRT_VERBOSE"); + if (env_verbose) + g_verbose = atoi(env_verbose); + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [-vsrdow] FILE\n" + "\n" + "Extract oops from syslog/dmesg file" + ); + enum { + OPT_v = 1 << 0, + OPT_s = 1 << 1, + OPT_r = 1 << 2, + OPT_d = 1 << 3, + OPT_o = 1 << 4, + OPT_w = 1 << 5, + }; + /* 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('r', NULL, NULL, _("Parse kernel's message buffer before parsing FILE")), + OPT_BOOL('d', NULL, NULL, _("Create ABRT dump for every oops found")), + OPT_BOOL('o', NULL, NULL, _("Print found oopses on standard output")), + OPT_BOOL('w', NULL, NULL, _("Do not exit, watch the file for new oopses")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); + + putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); + msg_prefix = PROGNAME; + if ((opts & OPT_s) + || getenv("ABRT_SYSLOG") + ) { + openlog(msg_prefix, 0, LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + } + + argv += optind; + if (!argv[0]) + show_usage_and_die(program_usage_string, program_options); + const char *filename = argv[0]; + + int inotify_fd = -1; + if (opts & OPT_w) + { + inotify_fd = inotify_init(); + if (inotify_fd == -1) + perror_msg_and_die("inotify_init failed"); + //close_on_exec_on(inotify_fd); + } + + GList *oops_list = NULL; + if (opts & OPT_r) + /* Scan dmesg (only once even with -w) */ + scan_dmesg(&oops_list); + + int partial_line_len = 0; + struct stat statbuf; + int file_fd = -1; + int wd = -1; + + while (1) /* loops only if -w */ + { + /* If file is already opened, parse oopses from current pos */ + if (file_fd >= 0) + { + memset(&statbuf, 0, sizeof(statbuf)); + fstat(file_fd, &statbuf); + partial_line_len = scan_syslog_file(&oops_list, file_fd, &statbuf, partial_line_len); + + /* Was file deleted or replaced? */ + ino_t fd_ino = statbuf.st_ino; + if (stat(filename, &statbuf) != 0 || statbuf.st_ino != fd_ino) /* yes */ + { + VERB2 log("Can't stat '%s', closing fd", filename); + close(file_fd); + if (wd >= 0) + inotify_rm_watch(inotify_fd, wd); + file_fd = -1; + wd = -1; + partial_line_len = 0; + } + } + + /* If file isn't opened, try to open it and parse oopses */ + if (file_fd < 0) + { + file_fd = open(filename, O_RDONLY); + if (file_fd < 0) + { + if (!(opts & OPT_w)) + perror_msg_and_die("Can't open '%s'", filename); + /* with -w, we ignore open errors */ + } + else + { + VERB2 log("Opened '%s'", filename); + /* For -w case, if we don't have inotify watch yet, open one */ + if ((opts & OPT_w) && wd < 0) + { + wd = inotify_add_watch(inotify_fd, filename, IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF); + if (wd < 0) + perror_msg("inotify_add_watch failed on '%s'", filename); + else + VERB2 log("Added inotify watch for '%s'", filename); + } + if (fstat(file_fd, &statbuf) == 0) + { + /* If file is large, skip the beginning. + * IOW: ignore old log messages because they are unlikely + * to have sufficiently recent data to be useful. + */ + if (statbuf.st_size > (MAX_SCAN_BLOCK - READ_AHEAD)) + lseek(file_fd, statbuf.st_size - (MAX_SCAN_BLOCK - READ_AHEAD), SEEK_SET); + /* Note that statbuf is filled by fstat by now, + * scan_syslog_file needs that + */ + partial_line_len = scan_syslog_file(&oops_list, file_fd, &statbuf, partial_line_len); + } + } + } + + /* Print and/or save oopses */ + int oops_cnt = g_list_length(oops_list); + if (!(opts & OPT_w) || oops_cnt != 0) + log("Found oopses: %d", oops_cnt); + if (oops_cnt != 0) + { + if (opts & OPT_o) + { + int i = 0; + while (i < oops_cnt) + printf("\nVersion: %s", (char*)g_list_nth_data(oops_list, i++)); + } + if (opts & OPT_d) + { + log("Creating dump directories"); + int errors = save_oops_to_dump_dir(oops_list, oops_cnt); + if (errors > 0) + log("%d errors while dumping oopses", errors); + } + } + list_free_with_free(oops_list); + oops_list = NULL; + + /* Done if no -w */ + if (!(opts & OPT_w)) + break; + + /* Even if log file grows all the time, say, a new line every 5 ms, + * we don't want to scan it all the time. Sleep a bit and let it grow + * in bigger increments. + * Sleep longer if file does not exist. + */ + sleep(file_fd >= 0 ? 1 : 59); + + /* Now wait for it to change, be moved or deleted */ + if (wd >= 0) + { + char buf[4096]; + VERB3 log("Waiting for '%s' to change", filename); + /* We block here: */ + int len = read(inotify_fd, buf, sizeof(buf)); + if (len < 0 && errno != EINTR) /* I saw EINTR here on strace attach */ + perror_msg("Error reading inotify fd"); + /* we don't actually check what happened to file - + * the code will handle all possibilities. + */ + VERB3 log("Change in '%s' detected", filename); + } + + } /* while (1) */ + + return 0; +} diff --git a/src/plugins/abrt-plugins.7 b/src/plugins/abrt-plugins.7 index 28de8f02..d8027057 100644 --- a/src/plugins/abrt-plugins.7 +++ b/src/plugins/abrt-plugins.7 @@ -33,7 +33,6 @@ stored in the \fI/etc/abrt/plugins\fP directory. .IR abrt-Bugzilla (7), .IR abrt-Upload (7), .IR abrt-KerneloopsReporter (7), -.IR abrt-KerneloopsScanner (7), .IR abrt-Logger (7), .IR abrt-Mailx (7), .SH AUTHOR diff --git a/src/plugins/abrt_rh_support.c b/src/plugins/abrt_rh_support.c index 04e2c8ef..9a48485b 100644 --- a/src/plugins/abrt_rh_support.c +++ b/src/plugins/abrt_rh_support.c @@ -212,69 +212,6 @@ reportfile_free(reportfile_t* file) // -// post_signature() -// -char* -post_signature(const char* baseURL, bool ssl_verify, const char* signature) -{ - char *URL = concat_path_file(baseURL, "/signatures"); - - abrt_post_state_t *state = new_abrt_post_state(0 - + ABRT_POST_WANT_HEADERS - + ABRT_POST_WANT_BODY - + ABRT_POST_WANT_ERROR_MSG - + (ssl_verify ? ABRT_POST_WANT_SSL_VERIFY : 0) - ); - int http_resp_code = abrt_post_string(state, URL, "application/xml", signature); - free(URL); - - char *retval; - const char *strata_msg; - switch (http_resp_code) - { - case 200: - case 201: - if (state->body) - { - retval = state->body; - state->body = NULL; - break; - } - strata_msg = find_header_in_abrt_post_state(state, "Strata-Message:"); - if (strata_msg && strcmp(strata_msg, "CREATED") != 0) { - retval = xstrdup(strata_msg); - break; - } - retval = xstrdup("Signature submitted successfully"); - break; - - default: - strata_msg = find_header_in_abrt_post_state(state, "Strata-Message:"); - if (strata_msg) - { - retval = xasprintf("Error (HTTP response %d): %s", - http_resp_code, - strata_msg); - break; - } - if (state->curl_error_msg) - { - if (http_resp_code >= 0) - retval = xasprintf("Error (HTTP response %d): %s", http_resp_code, state->curl_error_msg); - else - retval = xasprintf("Error in HTTP transaction: %s", state->curl_error_msg); - break; - } - retval = xasprintf("Error (HTTP response %d), body:\n%s", http_resp_code, state->body); - break; - } - - free_abrt_post_state(state); - return retval; -} - - -// // send_report_to_new_case() // @@ -391,6 +328,15 @@ send_report_to_new_case(const char* baseURL, char *case_location = find_header_in_abrt_post_state(case_state, "Location:"); switch (case_state->http_resp_code) { + case 404: + /* Not strictly necessary (default branch would deal with it too), + * but makes this typical error less cryptic: + * instead of returning html-encoded body, we show short concise message, + * and show offending URL (typos in which is a typical cause) */ + retval = xasprintf("error in case creation, " + "HTTP code: 404 (Not found), URL:'%s'", case_url); + break; + case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */ case 302: /* "302 Found" (just in case) */ case 305: /* "305 Use Proxy" */ @@ -401,27 +347,16 @@ send_report_to_new_case(const char* baseURL, free_abrt_post_state(case_state); goto redirect_case; } - goto bad_resp_code; - - case 404: - /* Not strictly necessary, but makes this typical error less cryptic: - * instead of returning html-encoded body, we show short concise message, - * and show offending URL (typos in which is a typical cause) */ - retval = xasprintf("error in case creation, " - "HTTP code: 404 (Not found), URL:'%s'", case_url); - break; + /* fall through */ default: - bad_resp_code: errmsg = case_state->curl_error_msg; - if (errmsg) + if (errmsg && errmsg[0]) retval = xasprintf("error in case creation: %s", errmsg); else { - errmsg = find_header_in_abrt_post_state(case_state, "Strata-Message:"); - if ((!errmsg || !errmsg[0]) && case_state->body && case_state->body[0]) - errmsg = case_state->body; - if (errmsg) + errmsg = case_state->body; + if (errmsg && errmsg[0]) retval = xasprintf("error in case creation, HTTP code: %d, server says: '%s'", case_state->http_resp_code, errmsg); else @@ -467,9 +402,7 @@ send_report_to_new_case(const char* baseURL, default: /* Case Creation Succeeded, attachement FAILED */ - errmsg = find_header_in_abrt_post_state(atch_state, "Strata-Message:"); - if (!errmsg || !errmsg[0]) - errmsg = atch_state->curl_error_msg; + errmsg = atch_state->curl_error_msg; if (atch_state->body && atch_state->body[0]) { if (errmsg && errmsg[0] diff --git a/src/plugins/ccpp_events.conf b/src/plugins/ccpp_events.conf new file mode 100644 index 00000000..1ad57608 --- /dev/null +++ b/src/plugins/ccpp_events.conf @@ -0,0 +1,17 @@ +EVENT=post-create analyzer=CCpp abrt-action-analyze-c + +#TODO: implement this (or add this functionality to abrt-action-install-debuginfo): +#EVENT=analyze analyzer=CCpp backtrace= trim-debuginfo-cache /var/cache/abrt-di 4096m + +#TODO: can we still specify additional directories to search for debuginfos, +# or was this ability lost with move to python installer? +EVENT=analyze analyzer=CCpp backtrace= abrt-action-install-debuginfo --core="$DUMP_DIR/coredump" +EVENT=analyze analyzer=CCpp backtrace= abrt-action-generate-backtrace + +# Same as "analyze", but executed when user requests "refresh" in GUI +#EVENT=reanalyze analyzer=CCpp trim-debuginfo-cache /var/cache/abrt-di 4096m +EVENT=reanalyze analyzer=CCpp abrt-action-install-debuginfo --core="$DUMP_DIR/coredump" +EVENT=reanalyze analyzer=CCpp abrt-action-generate-backtrace + +EVENT=report_Bugzilla analyzer=CCpp abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf +EVENT=report_Logger analyzer=CCpp abrt-action-print -o /var/log/abrt.log |