Jakub Filak f4e249
From c036609d34dfbfded9891be83d5e43db0a9feae2 Mon Sep 17 00:00:00 2001
Jakub Filak f4e249
From: Jakub Filak <jfilak@redhat.com>
Jakub Filak f4e249
Date: Mon, 7 Jul 2014 18:11:13 +0200
Jakub Filak f4e249
Subject: [PATCH 4/9] koops: dump oopses from systemd-journal
Jakub Filak f4e249
Jakub Filak f4e249
Resolves rhbz#1059724
Jakub Filak f4e249
---
Jakub Filak f4e249
 configure.ac                         |   3 +
Jakub Filak f4e249
 doc/Makefile.am                      |   1 +
Jakub Filak f4e249
 doc/abrt-dump-journal-oops.txt       |  68 ++++++
Jakub Filak f4e249
 init-scripts/abrt-oops.service       |   4 +-
Jakub Filak f4e249
 po/POTFILES.in                       |   2 +
Jakub Filak f4e249
 src/include/libabrt.h                |  19 ++
Jakub Filak f4e249
 src/lib/kernel.c                     | 103 +++++----
Jakub Filak f4e249
 src/plugins/Makefile.am              |  23 ++
Jakub Filak f4e249
 src/plugins/abrt-dump-journal-oops.c | 394 +++++++++++++++++++++++++++++++++++
Jakub Filak f4e249
 src/plugins/abrt-dump-oops.c         | 313 ++++------------------------
Jakub Filak f4e249
 src/plugins/abrt-journal.c           | 295 ++++++++++++++++++++++++++
Jakub Filak f4e249
 src/plugins/abrt-journal.h           | 110 ++++++++++
Jakub Filak f4e249
 src/plugins/oops-utils.c             | 279 +++++++++++++++++++++++++
Jakub Filak f4e249
 src/plugins/oops-utils.h             |  48 +++++
Jakub Filak f4e249
 15 files changed, 1353 insertions(+), 310 deletions(-)
Jakub Filak f4e249
 create mode 100644 doc/abrt-dump-journal-oops.txt
Jakub Filak f4e249
 create mode 100644 src/plugins/abrt-dump-journal-oops.c
Jakub Filak f4e249
 create mode 100644 src/plugins/abrt-journal.c
Jakub Filak f4e249
 create mode 100644 src/plugins/abrt-journal.h
Jakub Filak f4e249
 create mode 100644 src/plugins/oops-utils.c
Jakub Filak f4e249
 create mode 100644 src/plugins/oops-utils.h
Jakub Filak f4e249
Jakub Filak f4e249
diff --git a/configure.ac b/configure.ac
Jakub Filak f4e249
index c051ec5..03882e9 100644
Jakub Filak f4e249
--- a/configure.ac
Jakub Filak f4e249
+++ b/configure.ac
Jakub Filak f4e249
@@ -140,6 +140,7 @@ PKG_CHECK_MODULES([LIBREPORT_GTK], [libreport-gtk])
Jakub Filak f4e249
 PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1])
Jakub Filak f4e249
 PKG_CHECK_MODULES([GIO], [gio-2.0])
Jakub Filak f4e249
 PKG_CHECK_MODULES([SATYR], [satyr])
Jakub Filak f4e249
+PKG_CHECK_MODULES([SYSTEMD_JOURNAL], [libsystemd-journal])
Jakub Filak f4e249
 
Jakub Filak f4e249
 PKG_PROG_PKG_CONFIG
Jakub Filak f4e249
 AC_ARG_WITH([systemdsystemunitdir],
Jakub Filak f4e249
@@ -167,6 +168,7 @@ AC_CHECK_HEADERS([locale.h])
Jakub Filak f4e249
 CONF_DIR='${sysconfdir}/${PACKAGE_NAME}'
Jakub Filak f4e249
 DEFAULT_CONF_DIR='${datadir}/${PACKAGE_NAME}/conf.d'
Jakub Filak f4e249
 VAR_RUN='${localstatedir}/run'
Jakub Filak f4e249
+VAR_STATE='${localstatedir}/lib/${PACKAGE_NAME}'
Jakub Filak f4e249
 PLUGINS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/plugins'
Jakub Filak f4e249
 DEFAULT_PLUGINS_CONF_DIR='${datadir}/${PACKAGE_NAME}/conf.d/plugins'
Jakub Filak f4e249
 EVENTS_DIR='${datadir}/libreport/events'
Jakub Filak f4e249
@@ -255,6 +257,7 @@ AC_ARG_ENABLE([native-unwinder],
Jakub Filak f4e249
 AC_SUBST(CONF_DIR)
Jakub Filak f4e249
 AC_SUBST(DEFAULT_CONF_DIR)
Jakub Filak f4e249
 AC_SUBST(VAR_RUN)
Jakub Filak f4e249
+AC_SUBST(VAR_STATE)
Jakub Filak f4e249
 AC_SUBST(PLUGINS_CONF_DIR)
Jakub Filak f4e249
 AC_SUBST(DEFAULT_PLUGINS_CONF_DIR)
Jakub Filak f4e249
 AC_SUBST(EVENTS_CONF_DIR)
Jakub Filak f4e249
diff --git a/doc/Makefile.am b/doc/Makefile.am
Jakub Filak f4e249
index 55cb0f3..064e2ba 100644
Jakub Filak f4e249
--- a/doc/Makefile.am
Jakub Filak f4e249
+++ b/doc/Makefile.am
Jakub Filak f4e249
@@ -19,6 +19,7 @@ MAN1_TXT += abrt-action-perform-ccpp-analysis.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-action-notify.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-applet.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-dump-oops.txt
Jakub Filak f4e249
+MAN1_TXT += abrt-dump-journal-oops.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-dump-xorg.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-auto-reporting.txt
Jakub Filak f4e249
 MAN1_TXT += abrt-retrace-client.txt
Jakub Filak f4e249
diff --git a/doc/abrt-dump-journal-oops.txt b/doc/abrt-dump-journal-oops.txt
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..e0b8d79
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/doc/abrt-dump-journal-oops.txt
Jakub Filak f4e249
@@ -0,0 +1,68 @@
Jakub Filak f4e249
+abrt-dump-journal-oops(1)
Jakub Filak f4e249
+=========================
Jakub Filak f4e249
+
Jakub Filak f4e249
+NAME
Jakub Filak f4e249
+----
Jakub Filak f4e249
+abrt-dump-journal-oops - Extract oops from systemd-journal
Jakub Filak f4e249
+
Jakub Filak f4e249
+SYNOPSIS
Jakub Filak f4e249
+--------
Jakub Filak f4e249
+'abrt-dump-journal-oops' [-vsoxtf] [-e]/[-c CURSOR] [-d DIR]/[-D]
Jakub Filak f4e249
+
Jakub Filak f4e249
+DESCRIPTION
Jakub Filak f4e249
+-----------
Jakub Filak f4e249
+This tool creates problem directory from oops extracted from systemd-journal.
Jakub Filak f4e249
+The tool can follow systemd-journal and extract oopses in time of their
Jakub Filak f4e249
+occurrence.
Jakub Filak f4e249
+
Jakub Filak f4e249
+The following start from the last seen cursor. If the last seen cursor file
Jakub Filak f4e249
+does not exist, the following start by scanning the entire sytemd-journal or
Jakub Filak f4e249
+from the end if '-e' option is specified.
Jakub Filak f4e249
+
Jakub Filak f4e249
+FILES
Jakub Filak f4e249
+-----
Jakub Filak f4e249
+/etc/abrt/plugins/oops.conf::
Jakub Filak f4e249
+   Configuration file where user can disable detection of non-fatal MCEs
Jakub Filak f4e249
+
Jakub Filak f4e249
+/var/lib/abrt/abrt-dump-journal-oops.state::
Jakub Filak f4e249
+   State file where systemd-journal cursor to the last seen message is saved
Jakub Filak f4e249
+
Jakub Filak f4e249
+OPTIONS
Jakub Filak f4e249
+-------
Jakub Filak f4e249
+-v, --verbose::
Jakub Filak f4e249
+   Be more verbose. Can be given multiple times.
Jakub Filak f4e249
+
Jakub Filak f4e249
+-s::
Jakub Filak f4e249
+   Log to syslog
Jakub Filak f4e249
+
Jakub Filak f4e249
+-o::
Jakub Filak f4e249
+   Print found oopses on standard output
Jakub Filak f4e249
+
Jakub Filak f4e249
+-d DIR::
Jakub Filak f4e249
+   Create new problem directory in DIR for every oops found
Jakub Filak f4e249
+
Jakub Filak f4e249
+-D::
Jakub Filak f4e249
+   Same as -d DumpLocation, DumpLocation is specified in abrt.conf
Jakub Filak f4e249
+
Jakub Filak f4e249
+-s CURSOR::
Jakub Filak f4e249
+   Starts scannig systemd-journal from CURSOR
Jakub Filak f4e249
+
Jakub Filak f4e249
+-e::
Jakub Filak f4e249
+   Starts following systemd-journal from the end
Jakub Filak f4e249
+
Jakub Filak f4e249
+-x::
Jakub Filak f4e249
+   Make the problem directory world readable. Usable only with -d/-D
Jakub Filak f4e249
+
Jakub Filak f4e249
+-t::
Jakub Filak f4e249
+   Throttle problem directory creation to 1 per second
Jakub Filak f4e249
+
Jakub Filak f4e249
+-f::
Jakub Filak f4e249
+   Follow systemd-journal
Jakub Filak f4e249
+
Jakub Filak f4e249
+SEE ALSO
Jakub Filak f4e249
+--------
Jakub Filak f4e249
+abrt.conf(5)
Jakub Filak f4e249
+
Jakub Filak f4e249
+AUTHORS
Jakub Filak f4e249
+-------
Jakub Filak f4e249
+* ABRT team
Jakub Filak f4e249
diff --git a/init-scripts/abrt-oops.service b/init-scripts/abrt-oops.service
Jakub Filak f4e249
index d8ac028..69aaaa9 100644
Jakub Filak f4e249
--- a/init-scripts/abrt-oops.service
Jakub Filak f4e249
+++ b/init-scripts/abrt-oops.service
Jakub Filak f4e249
@@ -4,8 +4,8 @@ After=abrtd.service
Jakub Filak f4e249
 Requisite=abrtd.service
Jakub Filak f4e249
 
Jakub Filak f4e249
 [Service]
Jakub Filak f4e249
-# TODO: do we really need absolute paths here?
Jakub Filak f4e249
-ExecStart=/bin/sh -c '/bin/dmesg | /usr/bin/abrt-dump-oops -xD; exec /usr/bin/abrt-watch-log -F "`/usr/bin/abrt-dump-oops -m`" /var/log/messages -- /usr/bin/abrt-dump-oops -xtD'
Jakub Filak f4e249
+# systemd requires absolute paths to executables
Jakub Filak f4e249
+ExecStart=/usr/bin/abrt-dump-journal-oops -fxtD
Jakub Filak f4e249
 
Jakub Filak f4e249
 [Install]
Jakub Filak f4e249
 WantedBy=multi-user.target
Jakub Filak f4e249
diff --git a/po/POTFILES.in b/po/POTFILES.in
Jakub Filak f4e249
index ff9b97a..160cd8b 100644
Jakub Filak f4e249
--- a/po/POTFILES.in
Jakub Filak f4e249
+++ b/po/POTFILES.in
Jakub Filak f4e249
@@ -35,12 +35,14 @@ src/plugins/abrt-action-trim-files.c
Jakub Filak f4e249
 src/plugins/abrt-gdb-exploitable
Jakub Filak f4e249
 src/plugins/abrt-watch-log.c
Jakub Filak f4e249
 src/plugins/abrt-dump-oops.c
Jakub Filak f4e249
+src/plugins/abrt-dump-journal-oops.c
Jakub Filak f4e249
 src/plugins/abrt-dump-xorg.c
Jakub Filak f4e249
 src/plugins/abrt-retrace-client.c
Jakub Filak f4e249
 src/plugins/analyze_LocalGDB.xml.in
Jakub Filak f4e249
 src/plugins/analyze_RetraceServer.xml.in
Jakub Filak f4e249
 src/plugins/collect_xsession_errors.xml.in
Jakub Filak f4e249
 src/plugins/https-utils.c
Jakub Filak f4e249
+src/plugins/oops-utils.c
Jakub Filak f4e249
 src/plugins/bodhi.c
Jakub Filak f4e249
 
Jakub Filak f4e249
 src/hooks/abrt-merge-pstoreoops.c
Jakub Filak f4e249
diff --git a/src/include/libabrt.h b/src/include/libabrt.h
Jakub Filak f4e249
index d6eb4a5..37704dd 100644
Jakub Filak f4e249
--- a/src/include/libabrt.h
Jakub Filak f4e249
+++ b/src/include/libabrt.h
Jakub Filak f4e249
@@ -109,8 +109,27 @@ char *kernel_tainted_long(const char *tainted_short);
Jakub Filak f4e249
 int koops_hash_str_ext(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *oops_buf, int frame_count, int duphas_flags);
Jakub Filak f4e249
 #define koops_hash_str abrt_koops_hash_str
Jakub Filak f4e249
 int koops_hash_str(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *oops_buf);
Jakub Filak f4e249
+
Jakub Filak f4e249
+
Jakub Filak f4e249
+#define koops_line_skip_level abrt_koops_line_skip_level
Jakub Filak f4e249
+int koops_line_skip_level(const char **c);
Jakub Filak f4e249
+#define koops_line_skip_jiffies abrt_koops_line_skip_jiffies
Jakub Filak f4e249
+void koops_line_skip_jiffies(const char **c);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * extract_oops tries to find oops signatures in a log
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+struct abrt_koops_line_info {
Jakub Filak f4e249
+    char *ptr;
Jakub Filak f4e249
+    int level;
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+#define koops_extract_oopses_from_lines abrt_koops_extract_oopses_from_lines
Jakub Filak f4e249
+void koops_extract_oopses_from_lines(GList **oops_list, const struct abrt_koops_line_info *lines_info, int lines_info_size);
Jakub Filak f4e249
 #define koops_extract_oopses abrt_koops_extract_oopses
Jakub Filak f4e249
 void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen);
Jakub Filak f4e249
+#define koops_suspicious_strings_list abrt_koops_suspicious_strings_list
Jakub Filak f4e249
+GList *koops_suspicious_strings_list(void);
Jakub Filak f4e249
 #define koops_print_suspicious_strings abrt_koops_print_suspicious_strings
Jakub Filak f4e249
 void koops_print_suspicious_strings(void);
Jakub Filak f4e249
 /**
Jakub Filak f4e249
diff --git a/src/lib/kernel.c b/src/lib/kernel.c
Jakub Filak f4e249
index b2d72b6..be80cbc 100644
Jakub Filak f4e249
--- a/src/lib/kernel.c
Jakub Filak f4e249
+++ b/src/lib/kernel.c
Jakub Filak f4e249
@@ -22,21 +22,12 @@
Jakub Filak f4e249
 #define _GNU_SOURCE 1 /* for strcasestr */
Jakub Filak f4e249
 #include "libabrt.h"
Jakub Filak f4e249
 
Jakub Filak f4e249
-/*
Jakub Filak f4e249
- * extract_oops tries to find oops signatures in a log
Jakub Filak f4e249
- */
Jakub Filak f4e249
-
Jakub Filak f4e249
-struct line_info {
Jakub Filak f4e249
-    char *ptr;
Jakub Filak f4e249
-    char level;
Jakub Filak f4e249
-};
Jakub Filak f4e249
-
Jakub Filak f4e249
 /* Used to be 100, but some MCE oopses are short:
Jakub Filak f4e249
  * "CPU 0: Machine Check Exception: 0000000000000007"
Jakub Filak f4e249
  */
Jakub Filak f4e249
 #define SANE_MIN_OOPS_LEN 30
Jakub Filak f4e249
 
Jakub Filak f4e249
-static void record_oops(GList **oops_list, struct line_info* lines_info, int oopsstart, int oopsend)
Jakub Filak f4e249
+static void record_oops(GList **oops_list, const struct abrt_koops_line_info* lines_info, int oopsstart, int oopsend)
Jakub Filak f4e249
 {
Jakub Filak f4e249
     int q;
Jakub Filak f4e249
     int len;
Jakub Filak f4e249
@@ -161,6 +152,15 @@ void koops_print_suspicious_strings(void)
Jakub Filak f4e249
     koops_print_suspicious_strings_filtered(NULL);
Jakub Filak f4e249
 }
Jakub Filak f4e249
 
Jakub Filak f4e249
+GList *koops_suspicious_strings_list(void)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    GList *strings = NULL;
Jakub Filak f4e249
+    for (const char *const *str = s_koops_suspicious_strings; *str; ++str)
Jakub Filak f4e249
+        strings = g_list_prepend(strings, (gpointer)*str);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return strings;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
 static bool match_any(const regex_t **res, const char *str)
Jakub Filak f4e249
 {
Jakub Filak f4e249
     for (const regex_t **r = res; *r != NULL; ++r)
Jakub Filak f4e249
@@ -189,12 +189,57 @@ void koops_print_suspicious_strings_filtered(const regex_t **filterout)
Jakub Filak f4e249
     }
Jakub Filak f4e249
 }
Jakub Filak f4e249
 
Jakub Filak f4e249
+
Jakub Filak f4e249
+void koops_line_skip_jiffies(const char **c)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    /* remove jiffies time stamp counter if present
Jakub Filak f4e249
+     * jiffies are unsigned long, so it can be 2^64 long, which is
Jakub Filak f4e249
+     * 20 decimal digits
Jakub Filak f4e249
+     */
Jakub Filak f4e249
+    if (**c == '[')
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        const char *c2 = strchr(*c, '.');
Jakub Filak f4e249
+        const char *c3 = strchr(*c, ']');
Jakub Filak f4e249
+        if (c2 && c3 && (c2 < c3) && (c3-*c) < 21)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            *c = c3 + 1;
Jakub Filak f4e249
+            if (**c == ' ')
Jakub Filak f4e249
+                (*c)++;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int koops_line_skip_level(const char **c)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    int linelevel = 0;
Jakub Filak f4e249
+    if (**c == '<')
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        const char *ptr = *c + 1;
Jakub Filak f4e249
+        while (isdigit(*ptr))
Jakub Filak f4e249
+            ++ptr;
Jakub Filak f4e249
+
Jakub Filak f4e249
+        if (*ptr == '>' && (ptr - *c > 1))
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            const char *const bck = ptr + 1;
Jakub Filak f4e249
+            unsigned exp = 1;
Jakub Filak f4e249
+            while (--ptr != *c)
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                linelevel += (*ptr - '0') * exp;
Jakub Filak f4e249
+                exp *= 10;
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+            *c = bck;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return linelevel;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
 void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen)
Jakub Filak f4e249
 {
Jakub Filak f4e249
     char *c;
Jakub Filak f4e249
     int linecount = 0;
Jakub Filak f4e249
     int lines_info_size = 0;
Jakub Filak f4e249
-    struct line_info *lines_info = NULL;
Jakub Filak f4e249
+    struct abrt_koops_line_info *lines_info = NULL;
Jakub Filak f4e249
 
Jakub Filak f4e249
     /* Split buffer into lines */
Jakub Filak f4e249
 
Jakub Filak f4e249
@@ -254,28 +299,10 @@ void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen)
Jakub Filak f4e249
             c = kernel_str + sizeof("kernel: ")-1;
Jakub Filak f4e249
         }
Jakub Filak f4e249
 
Jakub Filak f4e249
-        linelevel = 0;
Jakub Filak f4e249
         /* store and remove kernel log level */
Jakub Filak f4e249
-        if (*c == '<' && c[1] && c[2] == '>')
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            linelevel = c[1];
Jakub Filak f4e249
-            c += 3;
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-        /* remove jiffies time stamp counter if present
Jakub Filak f4e249
-         * jiffies are unsigned long, so it can be 2^64 long, which is
Jakub Filak f4e249
-         * 20 decimal digits
Jakub Filak f4e249
-         */
Jakub Filak f4e249
-        if (*c == '[')
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            char *c2 = strchr(c, '.');
Jakub Filak f4e249
-            char *c3 = strchr(c, ']');
Jakub Filak f4e249
-            if (c2 && c3 && (c2 < c3) && (c3-c) < 21)
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                c = c3 + 1;
Jakub Filak f4e249
-                if (*c == ' ')
Jakub Filak f4e249
-                    c++;
Jakub Filak f4e249
-            }
Jakub Filak f4e249
-        }
Jakub Filak f4e249
+        linelevel = koops_line_skip_level((const char **)&c);
Jakub Filak f4e249
+        koops_line_skip_jiffies((const char **)&c);
Jakub Filak f4e249
+
Jakub Filak f4e249
         if ((lines_info_size & 0xfff) == 0)
Jakub Filak f4e249
         {
Jakub Filak f4e249
             lines_info = xrealloc(lines_info, (lines_info_size + 0x1000) * sizeof(lines_info[0]));
Jakub Filak f4e249
@@ -287,6 +314,12 @@ next_line:
Jakub Filak f4e249
         c = c9 + 1;
Jakub Filak f4e249
     }
Jakub Filak f4e249
 
Jakub Filak f4e249
+    koops_extract_oopses_from_lines(oops_list, lines_info, lines_info_size);
Jakub Filak f4e249
+    free(lines_info);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+void koops_extract_oopses_from_lines(GList **oops_list, const struct abrt_koops_line_info *lines_info, int lines_info_size)
Jakub Filak f4e249
+{
Jakub Filak f4e249
     /* Analyze lines */
Jakub Filak f4e249
 
Jakub Filak f4e249
     int i;
Jakub Filak f4e249
@@ -323,8 +356,6 @@ next_line:
Jakub Filak f4e249
             {
Jakub Filak f4e249
                 /* debug information */
Jakub Filak f4e249
                 log_debug("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr);
Jakub Filak f4e249
-                if (oopsstart != i)
Jakub Filak f4e249
-                        log_debug("Trigger line is %d: '%s'", i, c);
Jakub Filak f4e249
                 /* try to find the end marker */
Jakub Filak f4e249
                 int i2 = i + 1;
Jakub Filak f4e249
                 while (i2 < lines_info_size && i2 < (i+50))
Jakub Filak f4e249
@@ -471,10 +502,7 @@ next_line:
Jakub Filak f4e249
             record_oops(oops_list, lines_info, oopsstart, oopsstart);
Jakub Filak f4e249
         }
Jakub Filak f4e249
     }
Jakub Filak f4e249
-
Jakub Filak f4e249
-    free(lines_info);
Jakub Filak f4e249
 }
Jakub Filak f4e249
-
Jakub Filak f4e249
 int koops_hash_str_ext(char result[SHA1_RESULT_LEN*2 + 1], const char *oops_buf, int frame_count, int duphash_flags)
Jakub Filak f4e249
 {
Jakub Filak f4e249
     char *hash_str = NULL, *error = NULL;
Jakub Filak f4e249
@@ -507,6 +535,7 @@ int koops_hash_str_ext(char result[SHA1_RESULT_LEN*2 + 1], const char *oops_buf,
Jakub Filak f4e249
         else
Jakub Filak f4e249
             log("Nothing useful for duphash");
Jakub Filak f4e249
 
Jakub Filak f4e249
+
Jakub Filak f4e249
         free(hash_str);
Jakub Filak f4e249
     }
Jakub Filak f4e249
 
Jakub Filak f4e249
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
Jakub Filak f4e249
index 14b6fe0..a804f82 100644
Jakub Filak f4e249
--- a/src/plugins/Makefile.am
Jakub Filak f4e249
+++ b/src/plugins/Makefile.am
Jakub Filak f4e249
@@ -15,6 +15,7 @@ bin_SCRIPTS = \
Jakub Filak f4e249
 bin_PROGRAMS = \
Jakub Filak f4e249
     abrt-watch-log \
Jakub Filak f4e249
     abrt-dump-oops \
Jakub Filak f4e249
+    abrt-dump-journal-oops \
Jakub Filak f4e249
     abrt-dump-xorg \
Jakub Filak f4e249
     abrt-action-analyze-c \
Jakub Filak f4e249
     abrt-action-analyze-python \
Jakub Filak f4e249
@@ -97,6 +98,8 @@ EXTRA_DIST = \
Jakub Filak f4e249
     abrt-action-ureport \
Jakub Filak f4e249
     abrt-gdb-exploitable \
Jakub Filak f4e249
     https-utils.h \
Jakub Filak f4e249
+    oops-utils.h \
Jakub Filak f4e249
+    abrt-journal.h \
Jakub Filak f4e249
     post_report.xml.in \
Jakub Filak f4e249
     abrt-action-analyze-ccpp-local.in
Jakub Filak f4e249
 
Jakub Filak f4e249
@@ -120,6 +123,7 @@ abrt_watch_log_LDADD = \
Jakub Filak f4e249
     ../lib/libabrt.la
Jakub Filak f4e249
 
Jakub Filak f4e249
 abrt_dump_oops_SOURCES = \
Jakub Filak f4e249
+    oops-utils.c \
Jakub Filak f4e249
     abrt-dump-oops.c
Jakub Filak f4e249
 abrt_dump_oops_CPPFLAGS = \
Jakub Filak f4e249
     -I$(srcdir)/../include \
Jakub Filak f4e249
@@ -133,6 +137,25 @@ abrt_dump_oops_LDADD = \
Jakub Filak f4e249
     $(LIBREPORT_LIBS) \
Jakub Filak f4e249
     ../lib/libabrt.la
Jakub Filak f4e249
 
Jakub Filak f4e249
+abrt_dump_journal_oops_SOURCES = \
Jakub Filak f4e249
+    oops-utils.c \
Jakub Filak f4e249
+    abrt-journal.c \
Jakub Filak f4e249
+    abrt-dump-journal-oops.c
Jakub Filak f4e249
+abrt_dump_journal_oops_CPPFLAGS = \
Jakub Filak f4e249
+    -I$(srcdir)/../include \
Jakub Filak f4e249
+    -I$(srcdir)/../lib \
Jakub Filak f4e249
+    $(GLIB_CFLAGS) \
Jakub Filak f4e249
+    $(LIBREPORT_CFLAGS) \
Jakub Filak f4e249
+    $(SYSTEMD_JOURNAL_CFLAGS) \
Jakub Filak f4e249
+    -DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \
Jakub Filak f4e249
+    -DVAR_STATE=\"$(VAR_STATE)\" \
Jakub Filak f4e249
+    -D_GNU_SOURCE
Jakub Filak f4e249
+abrt_dump_journal_oops_LDADD = \
Jakub Filak f4e249
+    $(GLIB_LIBS) \
Jakub Filak f4e249
+    $(LIBREPORT_LIBS) \
Jakub Filak f4e249
+    $(SYSTEMD_JOURNAL_LIBS) \
Jakub Filak f4e249
+    ../lib/libabrt.la
Jakub Filak f4e249
+
Jakub Filak f4e249
 abrt_dump_xorg_SOURCES = \
Jakub Filak f4e249
     abrt-dump-xorg.c
Jakub Filak f4e249
 abrt_dump_xorg_CPPFLAGS = \
Jakub Filak f4e249
diff --git a/src/plugins/abrt-dump-journal-oops.c b/src/plugins/abrt-dump-journal-oops.c
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..3f1f419
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/src/plugins/abrt-dump-journal-oops.c
Jakub Filak f4e249
@@ -0,0 +1,394 @@
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Copyright (C) 2014  ABRT team
Jakub Filak f4e249
+ * Copyright (C) 2014  RedHat Inc
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
+ * it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
+ * the Free Software Foundation; either version 2 of the License, or
Jakub Filak f4e249
+ * (at your option) any later version.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is distributed in the hope that it will be useful,
Jakub Filak f4e249
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jakub Filak f4e249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Jakub Filak f4e249
+ * GNU General Public License for more details.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#include "libabrt.h"
Jakub Filak f4e249
+#include "abrt-journal.h"
Jakub Filak f4e249
+#include "oops-utils.h"
Jakub Filak f4e249
+
Jakub Filak f4e249
+#define ABRT_JOURNAL_WATCH_STATE_FILE VAR_STATE"/abrt-dump-journal-oops.state"
Jakub Filak f4e249
+#define ABRT_JOURNAL_WATCH_STATE_FILE_MODE 0600
Jakub Filak f4e249
+#define ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ (4 * 1024)
Jakub Filak f4e249
+
Jakub Filak f4e249
+/* Limit number of buffered lines */
Jakub Filak f4e249
+#define ABRT_JOURNAL_MAX_READ_LINES (1024 * 1024)
Jakub Filak f4e249
+
Jakub Filak f4e249
+/* Forward declarations */
Jakub Filak f4e249
+static void save_abrt_journal_watch_position(abrt_journal_t *journal, const char *file_name);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Koops extractor
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+
Jakub Filak f4e249
+static GList* abrt_journal_extract_kernel_oops(abrt_journal_t *journal)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    size_t lines_info_count = 0;
Jakub Filak f4e249
+    size_t lines_info_size = 32;
Jakub Filak f4e249
+    struct abrt_koops_line_info *lines_info = xmalloc(lines_info_size * sizeof(lines_info[0]));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    do
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        const char *line = NULL;
Jakub Filak f4e249
+        if (abrt_journal_get_log_line(journal, &line) < 0)
Jakub Filak f4e249
+            error_msg_and_die(_("Cannot read journal data."));
Jakub Filak f4e249
+
Jakub Filak f4e249
+        if (lines_info_count == lines_info_size)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            lines_info_size *= 2;
Jakub Filak f4e249
+            lines_info = xrealloc(lines_info, lines_info_size * sizeof(lines_info[0]));
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        lines_info[lines_info_count].level = koops_line_skip_level(&line);
Jakub Filak f4e249
+        koops_line_skip_jiffies(&line);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        lines_info[lines_info_count].ptr = xstrdup(line);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        ++lines_info_count;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+    while (lines_info_count < ABRT_JOURNAL_MAX_READ_LINES
Jakub Filak f4e249
+            && abrt_journal_next(journal) > 0);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    GList *oops_list = NULL;
Jakub Filak f4e249
+    koops_extract_oopses_from_lines(&oops_list, lines_info, lines_info_count);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    log_debug("Extracted: %d oopses", g_list_length(oops_list));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    for (size_t i = 0; i < lines_info_count; ++i)
Jakub Filak f4e249
+        free(lines_info[i].ptr);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free(lines_info);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return oops_list;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * An adatapter of abrt_journal_extract_kernel_oops for abrt_journal_watch_callback
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+struct watch_journald_settings
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const char *dump_location;
Jakub Filak f4e249
+    int oops_utils_flags;
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+static void abrt_journal_watch_extract_kernel_oops(abrt_journal_watch_t *watch, void *data)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const struct watch_journald_settings *conf = (const struct watch_journald_settings *)data;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_t *journal = abrt_journal_watch_get_journal(watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Give systemd-journal one second to suck in all kernel's strings */
Jakub Filak f4e249
+    if (abrt_oops_signaled_sleep(1) > 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        abrt_journal_watch_stop(watch);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    GList *oopses = abrt_journal_extract_kernel_oops(journal);
Jakub Filak f4e249
+    abrt_oops_process_list(oopses, conf->dump_location, conf->oops_utils_flags);
Jakub Filak f4e249
+    g_list_free_full(oopses, (GDestroyNotify)free);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Skip stuff which appeared while processing oops as it is not necessary */
Jakub Filak f4e249
+    /* to catch all consecutive oopses (anyway such oopses are almost */
Jakub Filak f4e249
+    /* certainly duplicates of the already extracted ones) */
Jakub Filak f4e249
+    abrt_journal_seek_tail(journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* In case of disaster, lets make sure we won't read the journal messages */
Jakub Filak f4e249
+    /* again. */
Jakub Filak f4e249
+    save_abrt_journal_watch_position(journal, ABRT_JOURNAL_WATCH_STATE_FILE);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (g_abrt_oops_sleep_woke_up_on_signal > 0)
Jakub Filak f4e249
+        abrt_journal_watch_stop(watch);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Koops extractor end
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+
Jakub Filak f4e249
+static void try_restore_abrt_journal_watch_position(abrt_journal_t *journal, const char *file_name)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    struct stat buf;
Jakub Filak f4e249
+    if (lstat(file_name, &buf) < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        if (errno == ENOENT)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            /* Only notice because this is expected */
Jakub Filak f4e249
+            log_notice(_("Not restoring journal watch's position: file '%s' does not exist"), file_name);
Jakub Filak f4e249
+            return;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        perror_msg(_("Cannot restore journal watch's position form file '%s'"), file_name);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (!(buf.st_mode & S_IFREG))
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        error_msg(_("Cannot restore journal watch's position: path '%s' is not regular file"), file_name);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (buf.st_size > ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        error_msg(_("Cannot restore journal watch's position: file '%s' exceeds %dB size limit"),
Jakub Filak f4e249
+                file_name, ABRT_JOURNAL_WATCH_STATE_FILE_MAX_SZ);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int state_fd = open(file_name, O_RDONLY | O_NOFOLLOW);
Jakub Filak f4e249
+    if (state_fd < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        perror_msg(_("Cannot restore journal watch's position: open('%s')"), file_name);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    char *crsr = xmalloc(buf.st_size + 1);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const int sz = full_read(state_fd, crsr, buf.st_size);
Jakub Filak f4e249
+    if (sz != buf.st_size)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        error_msg(_("Cannot restore journal watch's position: cannot read entire file '%s'"), file_name);
Jakub Filak f4e249
+        close(state_fd);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    crsr[sz] = '\0';
Jakub Filak f4e249
+    close(state_fd);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const int r = abrt_journal_set_cursor(journal, crsr);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        /* abrt_journal_set_cursor() prints error message in verbose mode */
Jakub Filak f4e249
+        error_msg(_("Failed to move the journal to a cursor from file '%s'"), file_name);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free(crsr);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+static void save_abrt_journal_watch_position(abrt_journal_t *journal, const char *file_name)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    char *crsr = NULL;
Jakub Filak f4e249
+    const int r = abrt_journal_get_cursor(journal, &crsr);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        /* abrt_journal_set_cursor() prints error message in verbose mode */
Jakub Filak f4e249
+        error_msg(_("Cannot save journal watch's position"));
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int state_fd = open(file_name,
Jakub Filak f4e249
+            O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
Jakub Filak f4e249
+            ABRT_JOURNAL_WATCH_STATE_FILE_MODE);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (state_fd < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        perror_msg(_("Cannot save journal watch's position: open('%s')"), file_name);
Jakub Filak f4e249
+        return;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    full_write_str(state_fd, crsr);
Jakub Filak f4e249
+    close(state_fd);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free(crsr);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+static void watch_journald(abrt_journal_t *journal, const char *dump_location, int flags)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    GList *koops_strings = koops_suspicious_strings_list();
Jakub Filak f4e249
+
Jakub Filak f4e249
+    char *oops_string_filter_regex = abrt_oops_string_filter_regex();
Jakub Filak f4e249
+    if (oops_string_filter_regex)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        regex_t filter_re;
Jakub Filak f4e249
+        if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0)
Jakub Filak f4e249
+            perror_msg_and_die(_("Failed to compile regex"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+        GList *iter = koops_strings;
Jakub Filak f4e249
+        while(iter != NULL)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            GList *next = g_list_next(iter);
Jakub Filak f4e249
+
Jakub Filak f4e249
+            const int reti = regexec(&filter_re, (const char *)iter->data, 0, NULL, 0);
Jakub Filak f4e249
+            if (reti == 0)
Jakub Filak f4e249
+                koops_strings = g_list_delete_link(koops_strings, iter);
Jakub Filak f4e249
+            else if (reti != REG_NOMATCH)
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                char msgbuf[100];
Jakub Filak f4e249
+                regerror(reti, &filter_re, msgbuf, sizeof(msgbuf));
Jakub Filak f4e249
+                error_msg_and_die("Regex match failed: %s", msgbuf);
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+
Jakub Filak f4e249
+            iter = next;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        regfree(&filter_re);
Jakub Filak f4e249
+        free(oops_string_filter_regex);
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    struct watch_journald_settings watch_conf = {
Jakub Filak f4e249
+        .dump_location = dump_location,
Jakub Filak f4e249
+        .oops_utils_flags = flags,
Jakub Filak f4e249
+    };
Jakub Filak f4e249
+
Jakub Filak f4e249
+    struct abrt_journal_watch_notify_strings notify_strings_conf = {
Jakub Filak f4e249
+        .decorated_cb = abrt_journal_watch_extract_kernel_oops,
Jakub Filak f4e249
+        .decorated_cb_data = &watch_conf,
Jakub Filak f4e249
+        .strings = koops_strings,
Jakub Filak f4e249
+    };
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_watch_t *watch = NULL;
Jakub Filak f4e249
+    if (abrt_journal_watch_new(&watch, journal, abrt_journal_watch_notify_strings, &notify_strings_conf) < 0)
Jakub Filak f4e249
+        error_msg_and_die(_("Failed to initialize systemd-journal watch"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_watch_run_sync(watch);
Jakub Filak f4e249
+    abrt_journal_watch_free(watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    g_list_free(koops_strings);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int main(int argc, char *argv[])
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    /* I18n */
Jakub Filak f4e249
+    setlocale(LC_ALL, "");
Jakub Filak f4e249
+#if ENABLE_NLS
Jakub Filak f4e249
+    bindtextdomain(PACKAGE, LOCALEDIR);
Jakub Filak f4e249
+    textdomain(PACKAGE);
Jakub Filak f4e249
+#endif
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_init(argv);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Can't keep these strings/structs static: _() doesn't support that */
Jakub Filak f4e249
+    const char *program_usage_string = _(
Jakub Filak f4e249
+        "& [-vsoxtf] [-e]/[-c CURSOR] [-d DIR]/[-D]\n"
Jakub Filak f4e249
+        "\n"
Jakub Filak f4e249
+        "Extract oops from systemd-journal\n"
Jakub Filak f4e249
+        "\n"
Jakub Filak f4e249
+        "-c and -e options conflicts because both specifies the first read message.\n"
Jakub Filak f4e249
+        "\n"
Jakub Filak f4e249
+        "-e is useful only for -f because the following of journal starts by reading \n"
Jakub Filak f4e249
+        "the entire journal if the last seen possition is not available.\n"
Jakub Filak f4e249
+        "\n"
Jakub Filak f4e249
+        "The last seen position is saved in "ABRT_JOURNAL_WATCH_STATE_FILE"\n"
Jakub Filak f4e249
+    );
Jakub Filak f4e249
+    enum {
Jakub Filak f4e249
+        OPT_v = 1 << 0,
Jakub Filak f4e249
+        OPT_s = 1 << 1,
Jakub Filak f4e249
+        OPT_o = 1 << 2,
Jakub Filak f4e249
+        OPT_d = 1 << 3,
Jakub Filak f4e249
+        OPT_D = 1 << 4,
Jakub Filak f4e249
+        OPT_x = 1 << 5,
Jakub Filak f4e249
+        OPT_t = 1 << 6,
Jakub Filak f4e249
+        OPT_c = 1 << 7,
Jakub Filak f4e249
+        OPT_e = 1 << 8,
Jakub Filak f4e249
+        OPT_f = 1 << 9,
Jakub Filak f4e249
+    };
Jakub Filak f4e249
+
Jakub Filak f4e249
+    char *cursor = NULL;
Jakub Filak f4e249
+    char *dump_location = NULL;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Keep enum above and order of options below in sync! */
Jakub Filak f4e249
+    struct options program_options[] = {
Jakub Filak f4e249
+        OPT__VERBOSE(&g_verbose),
Jakub Filak f4e249
+        OPT_BOOL(  's', NULL, NULL, _("Log to syslog")),
Jakub Filak f4e249
+        OPT_BOOL(  'o', NULL, NULL, _("Print found oopses on standard output")),
Jakub Filak f4e249
+        /* oopses don't contain any sensitive info, and even
Jakub Filak f4e249
+         * the old koops app was showing the oopses to all users
Jakub Filak f4e249
+         */
Jakub Filak f4e249
+        OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")),
Jakub Filak f4e249
+        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
Jakub Filak f4e249
+        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
Jakub Filak f4e249
+        OPT_BOOL(  't', NULL, NULL, _("Throttle problem directory creation to 1 per second")),
Jakub Filak f4e249
+        OPT_STRING('c', NULL, &cursor, "CURSOR", _("Start reading systemd-journal from the CURSOR position")),
Jakub Filak f4e249
+        OPT_BOOL(  'e', NULL, NULL, _("Start reading systemd-journal from the end")),
Jakub Filak f4e249
+        OPT_BOOL(  'f', NULL, NULL, _("Follow systemd-journal from the last seen position (if available)")),
Jakub Filak f4e249
+        OPT_END()
Jakub Filak f4e249
+    };
Jakub Filak f4e249
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    export_abrt_envvars(0);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    msg_prefix = g_progname;
Jakub Filak f4e249
+    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        logmode = LOGMODE_JOURNAL;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_c) && (opts & OPT_e))
Jakub Filak f4e249
+        error_msg_and_die(_("You need to specify either -c CURSOR or -e"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (opts & OPT_D)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        if (opts & OPT_d)
Jakub Filak f4e249
+            show_usage_and_die(program_usage_string, program_options);
Jakub Filak f4e249
+        load_abrt_conf();
Jakub Filak f4e249
+        dump_location = g_settings_dump_location;
Jakub Filak f4e249
+        g_settings_dump_location = NULL;
Jakub Filak f4e249
+        free_abrt_conf_data();
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int oops_utils_flags = 0;
Jakub Filak f4e249
+    if ((opts & OPT_x))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_WORLD_READABLE;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_t))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_o))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const char *const env_journal_filter = getenv("ABRT_DUMP_JOURNAL_OOPS_DEBUG_FILTER");
Jakub Filak f4e249
+    static const char *kernel_journal_filter[2] = { 0 };
Jakub Filak f4e249
+    kernel_journal_filter[0] = (env_journal_filter ? env_journal_filter : "SYSLOG_IDENTIFIER=kernel");
Jakub Filak f4e249
+    log_debug("Using journal match: '%s'", kernel_journal_filter[0]);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_t *journal = NULL;
Jakub Filak f4e249
+    if (abrt_journal_new(&journal))
Jakub Filak f4e249
+        error_msg_and_die(_("Cannot open systemd-journal"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (abrt_journal_set_journal_filter(journal, kernel_journal_filter) < 0)
Jakub Filak f4e249
+        error_msg_and_die(_("Cannot filter systemd-journal to kernel data only"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_e) && abrt_journal_seek_tail(journal) < 0)
Jakub Filak f4e249
+        error_msg_and_die(_("Cannot seek to the end of journal"));
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_f))
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        if (!cursor)
Jakub Filak f4e249
+            try_restore_abrt_journal_watch_position(journal, ABRT_JOURNAL_WATCH_STATE_FILE);
Jakub Filak f4e249
+        else if(abrt_journal_set_cursor(journal, cursor))
Jakub Filak f4e249
+            error_msg_and_die(_("Failed to start watch from cursor '%s'"), cursor);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        watch_journald(journal, dump_location, oops_utils_flags);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        save_abrt_journal_watch_position(journal, ABRT_JOURNAL_WATCH_STATE_FILE);
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+    else
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        if (cursor && abrt_journal_set_cursor(journal, cursor))
Jakub Filak f4e249
+            error_msg_and_die(_("Failed to set systemd-journal cursor '%s'"), cursor);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        /* Compatibility hack, a watch's callback gets the journal already moved
Jakub Filak f4e249
+         * to a next message.*/
Jakub Filak f4e249
+        abrt_journal_next(journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        GList *oopses = abrt_journal_extract_kernel_oops(journal);
Jakub Filak f4e249
+        const int errors = abrt_oops_process_list(oopses, dump_location, oops_utils_flags);
Jakub Filak f4e249
+        g_list_free_full(oopses, (GDestroyNotify)free);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        return errors;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_free(journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return EXIT_SUCCESS;
Jakub Filak f4e249
+}
Jakub Filak f4e249
diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c
Jakub Filak f4e249
index 9f0dc87..b1031ea 100644
Jakub Filak f4e249
--- a/src/plugins/abrt-dump-oops.c
Jakub Filak f4e249
+++ b/src/plugins/abrt-dump-oops.c
Jakub Filak f4e249
@@ -1,6 +1,6 @@
Jakub Filak f4e249
 /*
Jakub Filak f4e249
-    Copyright (C) 2011  ABRT team
Jakub Filak f4e249
-    Copyright (C) 2011  RedHat Inc
Jakub Filak f4e249
+    Copyright (C) 2011,2014  ABRT team
Jakub Filak f4e249
+    Copyright (C) 2011,2014  RedHat Inc
Jakub Filak f4e249
 
Jakub Filak f4e249
     This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
     it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
@@ -18,16 +18,7 @@
Jakub Filak f4e249
  */
Jakub Filak f4e249
 #include <syslog.h>
Jakub Filak f4e249
 #include "libabrt.h"
Jakub Filak f4e249
-
Jakub Filak f4e249
-/* How many problem dirs to create at most?
Jakub Filak f4e249
- * Also causes cooldown sleep with -t if exceeded -
Jakub Filak f4e249
- * useful when called from a log watcher.
Jakub Filak f4e249
- */
Jakub Filak f4e249
-#define MAX_DUMPED_DD_COUNT  5
Jakub Filak f4e249
-
Jakub Filak f4e249
-static bool world_readable_dump = false;
Jakub Filak f4e249
-static bool throttle_dd_creation = false;
Jakub Filak f4e249
-static const char *debug_dumps_dir = ".";
Jakub Filak f4e249
+#include "oops-utils.h"
Jakub Filak f4e249
 
Jakub Filak f4e249
 #define MAX_SCAN_BLOCK  (4*1024*1024)
Jakub Filak f4e249
 #define READ_AHEAD          (10*1024)
Jakub Filak f4e249
@@ -69,175 +60,6 @@ static void scan_syslog_file(GList **oops_list, int fd)
Jakub Filak f4e249
     free(buffer);
Jakub Filak f4e249
 }
Jakub Filak f4e249
 
Jakub Filak f4e249
-static char *list_of_tainted_modules(const char *proc_modules)
Jakub Filak f4e249
-{
Jakub Filak f4e249
-    struct strbuf *result = strbuf_new();
Jakub Filak f4e249
-
Jakub Filak f4e249
-    const char *p = proc_modules;
Jakub Filak f4e249
-    for (;;)
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        const char *end = strchrnul(p, '\n');
Jakub Filak f4e249
-        const char *paren = strchrnul(p, '(');
Jakub Filak f4e249
-        /* We look for a line with this format:
Jakub Filak f4e249
-         * "kvm_intel 126289 0 - Live 0xf829e000 (taint_flags)"
Jakub Filak f4e249
-         * where taint_flags have letters
Jakub Filak f4e249
-         * (flags '+' and '-' indicate (un)loading, we must ignore them).
Jakub Filak f4e249
-         */
Jakub Filak f4e249
-        while (++paren < end)
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            if ((unsigned)(toupper(*paren) - 'A') <= 'Z'-'A')
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                strbuf_append_strf(result, result->len == 0 ? "%.*s" : ",%.*s",
Jakub Filak f4e249
-                        (int)(strchrnul(p,' ') - p), p
Jakub Filak f4e249
-                );
Jakub Filak f4e249
-                break;
Jakub Filak f4e249
-            }
Jakub Filak f4e249
-            if (*paren == ')')
Jakub Filak f4e249
-                break;
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-
Jakub Filak f4e249
-        if (*end == '\0')
Jakub Filak f4e249
-            break;
Jakub Filak f4e249
-        p = end + 1;
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-
Jakub Filak f4e249
-    if (result->len == 0)
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        strbuf_free(result);
Jakub Filak f4e249
-        return NULL;
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-    return strbuf_free_nobuf(result);
Jakub Filak f4e249
-}
Jakub Filak f4e249
-
Jakub Filak f4e249
-static void save_oops_data_in_dump_dir(struct dump_dir *dd, char *oops, const char *proc_modules)
Jakub Filak f4e249
-{
Jakub Filak f4e249
-    char *first_line = oops;
Jakub Filak f4e249
-    char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
Jakub Filak f4e249
-    *second_line++ = '\0';
Jakub Filak f4e249
-
Jakub Filak f4e249
-    if (first_line[0])
Jakub Filak f4e249
-        dd_save_text(dd, FILENAME_KERNEL, first_line);
Jakub Filak f4e249
-    dd_save_text(dd, FILENAME_BACKTRACE, second_line);
Jakub Filak f4e249
-
Jakub Filak f4e249
-    /* check if trace doesn't have line: 'Your BIOS is broken' */
Jakub Filak f4e249
-    if (strstr(second_line, "Your BIOS is broken"))
Jakub Filak f4e249
-        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
Jakub Filak f4e249
-                _("A kernel problem occurred because of broken BIOS. "
Jakub Filak f4e249
-                  "Unfortunately, such problems are not fixable by kernel maintainers."));
Jakub Filak f4e249
-    /* check if trace doesn't have line: 'Your hardware is unsupported' */
Jakub Filak f4e249
-    else if (strstr(second_line, "Your hardware is unsupported"))
Jakub Filak f4e249
-        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
Jakub Filak f4e249
-                _("A kernel problem occurred, but your hardware is unsupported, "
Jakub Filak f4e249
-                  "therefore kernel maintainers are unable to fix this problem."));
Jakub Filak f4e249
-    else
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        char *tainted_short = kernel_tainted_short(second_line);
Jakub Filak f4e249
-        if (tainted_short)
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            log_notice("Kernel is tainted '%s'", tainted_short);
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
Jakub Filak f4e249
-
Jakub Filak f4e249
-            char *tnt_long = kernel_tainted_long(tainted_short);
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long);
Jakub Filak f4e249
-            free(tnt_long);
Jakub Filak f4e249
-
Jakub Filak f4e249
-            struct strbuf *reason = strbuf_new();
Jakub Filak f4e249
-            const char *fmt = _("A kernel problem occurred, but your kernel has been "
Jakub Filak f4e249
-                    "tainted (flags:%s). Kernel maintainers are unable to "
Jakub Filak f4e249
-                    "diagnose tainted reports.");
Jakub Filak f4e249
-            strbuf_append_strf(reason, fmt, tainted_short);
Jakub Filak f4e249
-
Jakub Filak f4e249
-            char *modlist = !proc_modules ? NULL : list_of_tainted_modules(proc_modules);
Jakub Filak f4e249
-            if (modlist)
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                strbuf_append_strf(reason, _(" Tainted modules: %s."), modlist);
Jakub Filak f4e249
-                free(modlist);
Jakub Filak f4e249
-            }
Jakub Filak f4e249
-
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason->buf);
Jakub Filak f4e249
-            strbuf_free(reason);
Jakub Filak f4e249
-            free(tainted_short);
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-
Jakub Filak f4e249
-    // TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
Jakub Filak f4e249
-    // kernel oops 1st line may look quite puzzling otherwise...
Jakub Filak f4e249
-    strchrnul(second_line, '\n')[0] = '\0';
Jakub Filak f4e249
-    dd_save_text(dd, FILENAME_REASON, second_line);
Jakub Filak f4e249
-}
Jakub Filak f4e249
-
Jakub Filak f4e249
-/* returns number of errors */
Jakub Filak f4e249
-static unsigned create_oops_dump_dirs(GList *oops_list, unsigned oops_cnt)
Jakub Filak f4e249
-{
Jakub Filak f4e249
-    unsigned countdown = MAX_DUMPED_DD_COUNT; /* do not report hundreds of oopses */
Jakub Filak f4e249
-
Jakub Filak f4e249
-    log_notice("Saving %u oopses as problem dirs", oops_cnt >= countdown ? countdown : oops_cnt);
Jakub Filak f4e249
-
Jakub Filak f4e249
-    char *cmdline_str = xmalloc_fopen_fgetline_fclose("/proc/cmdline");
Jakub Filak f4e249
-    char *fips_enabled = xmalloc_fopen_fgetline_fclose("/proc/sys/crypto/fips_enabled");
Jakub Filak f4e249
-    char *proc_modules = xmalloc_open_read_close("/proc/modules", /*maxsize:*/ NULL);
Jakub Filak f4e249
-    char *suspend_stats = xmalloc_open_read_close("/sys/kernel/debug/suspend_stats", /*maxsize:*/ NULL);
Jakub Filak f4e249
-
Jakub Filak f4e249
-    time_t t = time(NULL);
Jakub Filak f4e249
-    const char *iso_date = iso_date_string(&t);
Jakub Filak f4e249
-    /* dump should be readable by all if we're run with -x */
Jakub Filak f4e249
-    uid_t my_euid = (uid_t)-1L;
Jakub Filak f4e249
-    mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH;
Jakub Filak f4e249
-    /* and readable only for the owner otherwise */
Jakub Filak f4e249
-    if (!world_readable_dump)
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        mode = DEFAULT_DUMP_DIR_MODE;
Jakub Filak f4e249
-        my_euid = geteuid();
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-
Jakub Filak f4e249
-    pid_t my_pid = getpid();
Jakub Filak f4e249
-    unsigned idx = 0;
Jakub Filak f4e249
-    unsigned errors = 0;
Jakub Filak f4e249
-    while (idx < oops_cnt)
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
Jakub Filak f4e249
-        sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
Jakub Filak f4e249
-        char *path = concat_path_file(debug_dumps_dir, base);
Jakub Filak f4e249
-
Jakub Filak f4e249
-        struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode);
Jakub Filak f4e249
-        if (dd)
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
Jakub Filak f4e249
-            save_oops_data_in_dump_dir(dd, (char*)g_list_nth_data(oops_list, idx++), proc_modules);
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
Jakub Filak f4e249
-            dd_save_text(dd, FILENAME_TYPE, "Kerneloops");
Jakub Filak f4e249
-            if (cmdline_str)
Jakub Filak f4e249
-                dd_save_text(dd, FILENAME_CMDLINE, cmdline_str);
Jakub Filak f4e249
-            if (proc_modules)
Jakub Filak f4e249
-                dd_save_text(dd, "proc_modules", proc_modules);
Jakub Filak f4e249
-            if (fips_enabled && strcmp(fips_enabled, "0") != 0)
Jakub Filak f4e249
-                dd_save_text(dd, "fips_enabled", fips_enabled);
Jakub Filak f4e249
-            if (suspend_stats)
Jakub Filak f4e249
-                dd_save_text(dd, "suspend_stats", suspend_stats);
Jakub Filak f4e249
-            dd_close(dd);
Jakub Filak f4e249
-            notify_new_path(path);
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-        else
Jakub Filak f4e249
-            errors++;
Jakub Filak f4e249
-
Jakub Filak f4e249
-        free(path);
Jakub Filak f4e249
-
Jakub Filak f4e249
-        if (--countdown == 0)
Jakub Filak f4e249
-            break;
Jakub Filak f4e249
-
Jakub Filak f4e249
-        if (dd && throttle_dd_creation)
Jakub Filak f4e249
-            sleep(1);
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-
Jakub Filak f4e249
-    free(cmdline_str);
Jakub Filak f4e249
-    free(proc_modules);
Jakub Filak f4e249
-    free(fips_enabled);
Jakub Filak f4e249
-    free(suspend_stats);
Jakub Filak f4e249
-
Jakub Filak f4e249
-    return errors;
Jakub Filak f4e249
-}
Jakub Filak f4e249
-
Jakub Filak f4e249
 int main(int argc, char **argv)
Jakub Filak f4e249
 {
Jakub Filak f4e249
     /* I18n */
Jakub Filak f4e249
@@ -267,6 +89,7 @@ int main(int argc, char **argv)
Jakub Filak f4e249
         OPT_m = 1 << 8,
Jakub Filak f4e249
     };
Jakub Filak f4e249
     char *problem_dir = NULL;
Jakub Filak f4e249
+    char *dump_location = NULL;
Jakub Filak f4e249
     /* Keep enum above and order of options below in sync! */
Jakub Filak f4e249
     struct options program_options[] = {
Jakub Filak f4e249
         OPT__VERBOSE(&g_verbose),
Jakub Filak f4e249
@@ -275,7 +98,7 @@ int main(int argc, char **argv)
Jakub Filak f4e249
         /* oopses don't contain any sensitive info, and even
Jakub Filak f4e249
          * the old koops app was showing the oopses to all users
Jakub Filak f4e249
          */
Jakub Filak f4e249
-        OPT_STRING('d', NULL, &debug_dumps_dir, "DIR", _("Create new problem directory in DIR for every oops found")),
Jakub Filak f4e249
+        OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")),
Jakub Filak f4e249
         OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
Jakub Filak f4e249
         OPT_STRING('u', NULL, &problem_dir, "PROBLEM", _("Save the extracted information in PROBLEM")),
Jakub Filak f4e249
         OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
Jakub Filak f4e249
@@ -295,26 +118,19 @@ int main(int argc, char **argv)
Jakub Filak f4e249
 
Jakub Filak f4e249
     if (opts & OPT_m)
Jakub Filak f4e249
     {
Jakub Filak f4e249
-        map_string_t *settings = new_map_string();
Jakub Filak f4e249
-
Jakub Filak f4e249
-        load_abrt_plugin_conf_file("oops.conf", settings);
Jakub Filak f4e249
-
Jakub Filak f4e249
-        int only_fatal_mce = 1;
Jakub Filak f4e249
-        try_get_map_string_item_as_bool(settings, "OnlyFatalMCE", &only_fatal_mce);
Jakub Filak f4e249
-
Jakub Filak f4e249
-        free_map_string(settings);
Jakub Filak f4e249
-
Jakub Filak f4e249
-        if (only_fatal_mce)
Jakub Filak f4e249
+        char *oops_string_filter_regex = abrt_oops_string_filter_regex();
Jakub Filak f4e249
+        if (oops_string_filter_regex)
Jakub Filak f4e249
         {
Jakub Filak f4e249
-            regex_t mce_re;
Jakub Filak f4e249
-            if (regcomp(&mce_re, "^Machine .*$", REG_NOSUB) != 0)
Jakub Filak f4e249
+            regex_t filter_re;
Jakub Filak f4e249
+            if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0)
Jakub Filak f4e249
                 perror_msg_and_die(_("Failed to compile regex"));
Jakub Filak f4e249
 
Jakub Filak f4e249
-            const regex_t *filter[] = { &mce_re, NULL };
Jakub Filak f4e249
+            const regex_t *filter[] = { &filter_re, NULL };
Jakub Filak f4e249
 
Jakub Filak f4e249
             koops_print_suspicious_strings_filtered(filter);
Jakub Filak f4e249
 
Jakub Filak f4e249
-            regfree(&mce_re);
Jakub Filak f4e249
+            regfree(&filter_re);
Jakub Filak f4e249
+            free(oops_string_filter_regex);
Jakub Filak f4e249
         }
Jakub Filak f4e249
         else
Jakub Filak f4e249
             koops_print_suspicious_strings();
Jakub Filak f4e249
@@ -327,100 +143,55 @@ int main(int argc, char **argv)
Jakub Filak f4e249
         if (opts & OPT_d)
Jakub Filak f4e249
             show_usage_and_die(program_usage_string, program_options);
Jakub Filak f4e249
         load_abrt_conf();
Jakub Filak f4e249
-        debug_dumps_dir = g_settings_dump_location;
Jakub Filak f4e249
+        dump_location = g_settings_dump_location;
Jakub Filak f4e249
         g_settings_dump_location = NULL;
Jakub Filak f4e249
         free_abrt_conf_data();
Jakub Filak f4e249
     }
Jakub Filak f4e249
 
Jakub Filak f4e249
+    int oops_utils_flags = 0;
Jakub Filak f4e249
+    if ((opts & OPT_x))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_WORLD_READABLE;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_t))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if ((opts & OPT_o))
Jakub Filak f4e249
+        oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT;
Jakub Filak f4e249
+
Jakub Filak f4e249
     argv += optind;
Jakub Filak f4e249
     if (argv[0])
Jakub Filak f4e249
         xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO);
Jakub Filak f4e249
 
Jakub Filak f4e249
-    world_readable_dump = (opts & OPT_x);
Jakub Filak f4e249
-    throttle_dd_creation = (opts & OPT_t);
Jakub Filak f4e249
-    unsigned errors = 0;
Jakub Filak f4e249
     GList *oops_list = NULL;
Jakub Filak f4e249
     scan_syslog_file(&oops_list, STDIN_FILENO);
Jakub Filak f4e249
 
Jakub Filak f4e249
-    int oops_cnt = g_list_length(oops_list);
Jakub Filak f4e249
-    if (oops_cnt != 0)
Jakub Filak f4e249
+    unsigned errors = 0;
Jakub Filak f4e249
+    if (opts & OPT_u)
Jakub Filak f4e249
     {
Jakub Filak f4e249
-        log("Found oopses: %d", oops_cnt);
Jakub Filak f4e249
-        if (opts & OPT_o)
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            int i = 0;
Jakub Filak f4e249
-            while (i < oops_cnt)
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                char *kernel_bt = (char*)g_list_nth_data(oops_list, i++);
Jakub Filak f4e249
-                char *tainted_short = kernel_tainted_short(kernel_bt);
Jakub Filak f4e249
-                if (tainted_short)
Jakub Filak f4e249
-                    log("Kernel is tainted '%s'", tainted_short);
Jakub Filak f4e249
-
Jakub Filak f4e249
-                free(tainted_short);
Jakub Filak f4e249
-                printf("\nVersion: %s", kernel_bt);
Jakub Filak f4e249
-            }
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-        if (opts & (OPT_d|OPT_D))
Jakub Filak f4e249
-        {
Jakub Filak f4e249
-            if (opts & OPT_D)
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                load_abrt_conf();
Jakub Filak f4e249
-                debug_dumps_dir = g_settings_dump_location;
Jakub Filak f4e249
-            }
Jakub Filak f4e249
-
Jakub Filak f4e249
-            log("Creating problem directories");
Jakub Filak f4e249
-            errors = create_oops_dump_dirs(oops_list, oops_cnt);
Jakub Filak f4e249
-            if (errors)
Jakub Filak f4e249
-                log("%d errors while dumping oopses", errors);
Jakub Filak f4e249
-            /*
Jakub Filak f4e249
-             * This marker in syslog file prevents us from
Jakub Filak f4e249
-             * re-parsing old oopses. The only problem is that we
Jakub Filak f4e249
-             * can't be sure here that the file we are watching
Jakub Filak f4e249
-             * is the same file where syslog(xxx) stuff ends up.
Jakub Filak f4e249
-             */
Jakub Filak f4e249
-            syslog(LOG_WARNING,
Jakub Filak f4e249
-                    "Reported %u kernel oopses to Abrt",
Jakub Filak f4e249
-                    oops_cnt
Jakub Filak f4e249
-            );
Jakub Filak f4e249
-        }
Jakub Filak f4e249
-        if (opts & OPT_u)
Jakub Filak f4e249
+        log("Updating problem directory");
Jakub Filak f4e249
+        switch (g_list_length(oops_list))
Jakub Filak f4e249
         {
Jakub Filak f4e249
-            log("Updating problem directory");
Jakub Filak f4e249
-            switch (oops_cnt)
Jakub Filak f4e249
-            {
Jakub Filak f4e249
-                case 1:
Jakub Filak f4e249
+            case 1:
Jakub Filak f4e249
+                {
Jakub Filak f4e249
+                    struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0);
Jakub Filak f4e249
+                    if (dd)
Jakub Filak f4e249
                     {
Jakub Filak f4e249
-                        struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0);
Jakub Filak f4e249
-                        if (dd)
Jakub Filak f4e249
-                        {
Jakub Filak f4e249
-                            save_oops_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL);
Jakub Filak f4e249
-                            dd_close(dd);
Jakub Filak f4e249
-                        }
Jakub Filak f4e249
+                        abrt_oops_save_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL);
Jakub Filak f4e249
+                        dd_close(dd);
Jakub Filak f4e249
                     }
Jakub Filak f4e249
-                    break;
Jakub Filak f4e249
-                default:
Jakub Filak f4e249
-                    error_msg(_("Can't update the problem: more than one oops found"));
Jakub Filak f4e249
-                    break;
Jakub Filak f4e249
-            }
Jakub Filak f4e249
+                }
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
+            default:
Jakub Filak f4e249
+                error_msg(_("Can't update the problem: more than one oops found"));
Jakub Filak f4e249
+                errors = 1;
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
         }
Jakub Filak f4e249
     }
Jakub Filak f4e249
+    else
Jakub Filak f4e249
+        errors = abrt_oops_process_list(oops_list, dump_location, oops_utils_flags);
Jakub Filak f4e249
+
Jakub Filak f4e249
     list_free_with_free(oops_list);
Jakub Filak f4e249
     //oops_list = NULL;
Jakub Filak f4e249
 
Jakub Filak f4e249
-    /* If we are run by a log watcher, this delays log rescan
Jakub Filak f4e249
-     * (because log watcher waits to us to terminate)
Jakub Filak f4e249
-     * and possibly prevents dreaded "abrt storm".
Jakub Filak f4e249
-     */
Jakub Filak f4e249
-    int unreported_cnt = oops_cnt - MAX_DUMPED_DD_COUNT;
Jakub Filak f4e249
-    if (unreported_cnt > 0 && throttle_dd_creation)
Jakub Filak f4e249
-    {
Jakub Filak f4e249
-        /* Quadratic throttle time growth, but careful to not overflow in "n*n" */
Jakub Filak f4e249
-        int n = unreported_cnt > 30 ? 30 : unreported_cnt;
Jakub Filak f4e249
-        n = n * n;
Jakub Filak f4e249
-        if (n > 9)
Jakub Filak f4e249
-            log(_("Sleeping for %d seconds"), n);
Jakub Filak f4e249
-        sleep(n); /* max 15 mins */
Jakub Filak f4e249
-    }
Jakub Filak f4e249
-
Jakub Filak f4e249
     return errors;
Jakub Filak f4e249
 }
Jakub Filak f4e249
diff --git a/src/plugins/abrt-journal.c b/src/plugins/abrt-journal.c
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..472357d
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/src/plugins/abrt-journal.c
Jakub Filak f4e249
@@ -0,0 +1,295 @@
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Copyright (C) 2014  ABRT team
Jakub Filak f4e249
+ * Copyright (C) 2014  RedHat Inc
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
+ * it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
+ * the Free Software Foundation; either version 2 of the License, or
Jakub Filak f4e249
+ * (at your option) any later version.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is distributed in the hope that it will be useful,
Jakub Filak f4e249
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jakub Filak f4e249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Jakub Filak f4e249
+ * GNU General Public License for more details.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#include <unistd.h>
Jakub Filak f4e249
+#include <signal.h>
Jakub Filak f4e249
+#include <poll.h>
Jakub Filak f4e249
+#include <stdlib.h>
Jakub Filak f4e249
+#include <abrt/libabrt.h>
Jakub Filak f4e249
+#include <stdio.h>
Jakub Filak f4e249
+
Jakub Filak f4e249
+#include "abrt-journal.h"
Jakub Filak f4e249
+
Jakub Filak f4e249
+#include <systemd/sd-journal.h>
Jakub Filak f4e249
+
Jakub Filak f4e249
+
Jakub Filak f4e249
+struct abrt_journal
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    sd_journal *j;
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_new(abrt_journal_t **journal)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    sd_journal *j;
Jakub Filak f4e249
+    const int r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log_notice("Failed to open journal: %s", strerror(-r));
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    *journal = xzalloc(sizeof(**journal));
Jakub Filak f4e249
+    (*journal)->j = j;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_free(abrt_journal_t *journal)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    sd_journal_close(journal->j);
Jakub Filak f4e249
+    journal->j = (void *)0xDEADBEAF;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free(journal);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_set_journal_filter(abrt_journal_t *journal, const char *const *journal_filter_list)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const char *const *cursor = journal_filter_list;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    while (*cursor)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        const int r = sd_journal_add_match(journal->j, *cursor, strlen(*cursor));
Jakub Filak f4e249
+        if (r < 0)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            log_notice("Failed to set journal filter: %s", strerror(-r));
Jakub Filak f4e249
+            return r;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        ++cursor;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_field(abrt_journal_t *journal, const char *field, const void **value, size_t *value_len)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = sd_journal_get_data(journal->j, field, value, value_len);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log_notice("Failed to read '%s' field: %s", field, strerror(-r));
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_string_field(abrt_journal_t *journal, const char *field, const char **value)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    size_t value_len;
Jakub Filak f4e249
+    const int r = abrt_journal_get_field(journal, field, (const void **)value, &value_len);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const size_t pfx_len = strlen(field) + 1;
Jakub Filak f4e249
+    if (value_len < pfx_len)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        error_msg("Invalid data format from journal: field data are not prefixed with field name");
Jakub Filak f4e249
+        return -EBADMSG;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    *value += pfx_len;
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_log_line(abrt_journal_t *journal, const char **line)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = abrt_journal_get_string_field(journal, "MESSAGE", line);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+        log_notice("Cannot read journal data. Exiting");
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return r;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_cursor(abrt_journal_t *journal, char **cursor)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = sd_journal_get_cursor(journal->j, cursor);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log_notice("Could not get journal cursor: '%s'", strerror(-r));
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_set_cursor(abrt_journal_t *journal, const char *cursor)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = sd_journal_seek_cursor(journal->j, cursor);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log_notice("Failed to seek journal to cursor '%s': %s\n", cursor, strerror(-r));
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_seek_tail(abrt_journal_t *journal)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = sd_journal_seek_tail(journal->j);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log_notice("Failed to seek journal to the end: %s\n", strerror(-r));
Jakub Filak f4e249
+        return r;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* BUG: https://bugzilla.redhat.com/show_bug.cgi?id=979487 */
Jakub Filak f4e249
+    sd_journal_previous_skip(journal->j, 1);
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_next(abrt_journal_t *journal)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int r = sd_journal_next(journal->j);
Jakub Filak f4e249
+    if (r < 0)
Jakub Filak f4e249
+        log_notice("Failed to iterate to next entry: %s", strerror(-r));
Jakub Filak f4e249
+    return r;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * ABRT systemd-journal wrapper end
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+
Jakub Filak f4e249
+static volatile int s_loop_terminated;
Jakub Filak f4e249
+void signal_loop_to_terminate(int signum)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    signum = signum;
Jakub Filak f4e249
+    s_loop_terminated = 1;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+enum abrt_journal_watch_state
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    ABRT_JOURNAL_WATCH_READY,
Jakub Filak f4e249
+    ABRT_JOURNAL_WATCH_STOPPED,
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+struct abrt_journal_watch
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    abrt_journal_t *j;
Jakub Filak f4e249
+    int state;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    abrt_journal_watch_callback callback;
Jakub Filak f4e249
+    void *callback_data;
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_watch_new(abrt_journal_watch_t **watch, abrt_journal_t *journal, abrt_journal_watch_callback callback, void *callback_data)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    assert(callback != NULL || !"ABRT watch needs valid callback ptr");
Jakub Filak f4e249
+
Jakub Filak f4e249
+    *watch = xzalloc(sizeof(**watch));
Jakub Filak f4e249
+    (*watch)->j = journal;
Jakub Filak f4e249
+    (*watch)->callback = callback;
Jakub Filak f4e249
+    (*watch)->callback_data = callback_data;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return 0;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_watch_free(abrt_journal_watch_t *watch)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    watch->j = (void *)0xDEADBEAF;
Jakub Filak f4e249
+    free(watch);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+abrt_journal_t *abrt_journal_watch_get_journal(abrt_journal_watch_t *watch)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    return watch->j;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_watch_run_sync(abrt_journal_watch_t *watch)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    sigset_t mask;
Jakub Filak f4e249
+    sigfillset(&mask);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Exit gracefully: */
Jakub Filak f4e249
+    /* services usually exit on SIGTERM and SIGHUP */
Jakub Filak f4e249
+    sigdelset(&mask, SIGTERM);
Jakub Filak f4e249
+    signal(SIGTERM, signal_loop_to_terminate);
Jakub Filak f4e249
+    sigdelset(&mask, SIGHUP);
Jakub Filak f4e249
+    signal(SIGHUP, signal_loop_to_terminate);
Jakub Filak f4e249
+    /* Ctrl-C for easier debugging */
Jakub Filak f4e249
+    sigdelset(&mask, SIGINT);
Jakub Filak f4e249
+    signal(SIGINT, signal_loop_to_terminate);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* Die on kill $PID */
Jakub Filak f4e249
+    sigdelset(&mask, SIGKILL);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    struct pollfd pollfd;
Jakub Filak f4e249
+    pollfd.fd = sd_journal_get_fd(watch->j->j);
Jakub Filak f4e249
+    pollfd.events = sd_journal_get_events(watch->j->j);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int r = 0;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    while (!s_loop_terminated && watch->state == ABRT_JOURNAL_WATCH_READY)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        r = sd_journal_next(watch->j->j);
Jakub Filak f4e249
+        if (r < 0)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            log_warning("Failed to iterate to next entry: %s", strerror(-r));
Jakub Filak f4e249
+            break;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+        else if (r == 0)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            ppoll(&pollfd, 1, NULL, &mask);
Jakub Filak f4e249
+            r = sd_journal_process(watch->j->j);
Jakub Filak f4e249
+            if (r < 0)
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                log_warning("Failed to get journal changes: %s\n", strerror(-r));
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+            continue;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        watch->callback(watch, watch->callback_data);
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return r;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_watch_stop(abrt_journal_watch_t *watch)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    watch->state = ABRT_JOURNAL_WATCH_STOPPED;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * ABRT systemd-journal watch - end
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_watch_notify_strings(abrt_journal_watch_t *watch, void *data)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    struct abrt_journal_watch_notify_strings *conf = (struct abrt_journal_watch_notify_strings *)data;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const char *message = NULL;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (abrt_journal_get_string_field(abrt_journal_watch_get_journal(watch), "MESSAGE", &message) < 0)
Jakub Filak f4e249
+        error_msg_and_die("Cannot read journal data.");
Jakub Filak f4e249
+
Jakub Filak f4e249
+    GList *cur = conf->strings;
Jakub Filak f4e249
+    while (cur)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        if (strstr(message, cur->data) != NULL)
Jakub Filak f4e249
+            break;
Jakub Filak f4e249
+
Jakub Filak f4e249
+        cur = g_list_next(cur);
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (cur)
Jakub Filak f4e249
+        conf->decorated_cb(watch, conf->decorated_cb_data);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * ABRT systemd-journal strings notifier - end
Jakub Filak f4e249
+ */
Jakub Filak f4e249
diff --git a/src/plugins/abrt-journal.h b/src/plugins/abrt-journal.h
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..219cf60
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/src/plugins/abrt-journal.h
Jakub Filak f4e249
@@ -0,0 +1,110 @@
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Copyright (C) 2014  ABRT team
Jakub Filak f4e249
+ * Copyright (C) 2014  RedHat Inc
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
+ * it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
+ * the Free Software Foundation; either version 2 of the License, or
Jakub Filak f4e249
+ * (at your option) any later version.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is distributed in the hope that it will be useful,
Jakub Filak f4e249
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jakub Filak f4e249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Jakub Filak f4e249
+ * GNU General Public License for more details.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#ifndef _ABRT_JOURNAL_H_
Jakub Filak f4e249
+#define _ABRT_JOURNAL_H_
Jakub Filak f4e249
+
Jakub Filak f4e249
+#include <glib.h>
Jakub Filak f4e249
+
Jakub Filak f4e249
+#ifdef __cplusplus
Jakub Filak f4e249
+extern "C" {
Jakub Filak f4e249
+#endif
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * A systemd-journal wrapper
Jakub Filak f4e249
+ * (isolates systemd API in a single compile unit)
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+struct abrt_journal;
Jakub Filak f4e249
+typedef struct abrt_journal abrt_journal_t;
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_new(abrt_journal_t **journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_free(abrt_journal_t *journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_set_journal_filter(abrt_journal_t *journal,
Jakub Filak f4e249
+                                    const char *const *journal_filter_list);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_field(abrt_journal_t *journal,
Jakub Filak f4e249
+                           const char *field,
Jakub Filak f4e249
+                           const void **value,
Jakub Filak f4e249
+                           size_t *value_len);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_string_field(abrt_journal_t *journal,
Jakub Filak f4e249
+                                  const char *field,
Jakub Filak f4e249
+                                  const char **value);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_log_line(abrt_journal_t *journal, const char **line);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_get_cursor(abrt_journal_t *journal, char **cursor);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_set_cursor(abrt_journal_t *journal, const char *cursor);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_seek_tail(abrt_journal_t *journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_next(abrt_journal_t *journal);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * A systemd-journal listener which waits for new messages a loop and notifies
Jakub Filak f4e249
+ * them via a call back
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+struct abrt_journal_watch;
Jakub Filak f4e249
+typedef struct abrt_journal_watch abrt_journal_watch_t;
Jakub Filak f4e249
+
Jakub Filak f4e249
+typedef void (* abrt_journal_watch_callback)(struct abrt_journal_watch *watch,
Jakub Filak f4e249
+                                             void *data);
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_journal_watch_new(abrt_journal_watch_t **watch,
Jakub Filak f4e249
+                           abrt_journal_t *journal,
Jakub Filak f4e249
+                           abrt_journal_watch_callback callback,
Jakub Filak f4e249
+                           void *callback_data);
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_watch_free(abrt_journal_watch_t *watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Returns the watched journal.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+abrt_journal_t *abrt_journal_watch_get_journal(abrt_journal_watch_t *watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Starts reading journal messages and waiting for new messages in a loop.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * SIGTERM and SIGINT terminates the loop gracefully.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+int abrt_journal_watch_run_sync(abrt_journal_watch_t *watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Can be used to terminate the loop in abrt_journal_watch_run_sync()
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+void abrt_journal_watch_stop(abrt_journal_watch_t *watch);
Jakub Filak f4e249
+
Jakub Filak f4e249
+
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * A decorator for abrt_journal_watch call backs which calls the decorated call
Jakub Filak f4e249
+ * back in case where journal message contains a string from the interested
Jakub Filak f4e249
+ * list.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+struct abrt_journal_watch_notify_strings
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    abrt_journal_watch_callback decorated_cb;
Jakub Filak f4e249
+    void *decorated_cb_data;
Jakub Filak f4e249
+    GList *strings;
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_journal_watch_notify_strings(abrt_journal_watch_t *watch, void *data);
Jakub Filak f4e249
+
Jakub Filak f4e249
+#ifdef __cplusplus
Jakub Filak f4e249
+}
Jakub Filak f4e249
+#endif
Jakub Filak f4e249
+
Jakub Filak f4e249
+#endif /*_ABRT_JOURNAL_H_*/
Jakub Filak f4e249
diff --git a/src/plugins/oops-utils.c b/src/plugins/oops-utils.c
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..9e2355e
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/src/plugins/oops-utils.c
Jakub Filak f4e249
@@ -0,0 +1,279 @@
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Copyright (C) 2014  ABRT team
Jakub Filak f4e249
+ * Copyright (C) 2014  RedHat Inc
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
+ * it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
+ * the Free Software Foundation; either version 2 of the License, or
Jakub Filak f4e249
+ * (at your option) any later version.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is distributed in the hope that it will be useful,
Jakub Filak f4e249
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jakub Filak f4e249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Jakub Filak f4e249
+ * GNU General Public License for more details.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#include "oops-utils.h"
Jakub Filak f4e249
+#include "libabrt.h"
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_oops_process_list(GList *oops_list, const char *dump_location, int flags)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    unsigned errors = 0;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int oops_cnt = g_list_length(oops_list);
Jakub Filak f4e249
+    if (oops_cnt != 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        log("Found oopses: %d", oops_cnt);
Jakub Filak f4e249
+        if ((flags & ABRT_OOPS_PRINT_STDOUT))
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            int i = 0;
Jakub Filak f4e249
+            while (i < oops_cnt)
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                char *kernel_bt = (char*)g_list_nth_data(oops_list, i++);
Jakub Filak f4e249
+                char *tainted_short = kernel_tainted_short(kernel_bt);
Jakub Filak f4e249
+                if (tainted_short)
Jakub Filak f4e249
+                    log("Kernel is tainted '%s'", tainted_short);
Jakub Filak f4e249
+
Jakub Filak f4e249
+                free(tainted_short);
Jakub Filak f4e249
+                printf("\nVersion: %s", kernel_bt);
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+        if (dump_location != NULL)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            log("Creating problem directories");
Jakub Filak f4e249
+            errors = abrt_oops_create_dump_dirs(oops_list, dump_location, flags);
Jakub Filak f4e249
+            if (errors)
Jakub Filak f4e249
+                log("%d errors while dumping oopses", errors);
Jakub Filak f4e249
+            /*
Jakub Filak f4e249
+             * This marker in syslog file prevents us from
Jakub Filak f4e249
+             * re-parsing old oopses. The only problem is that we
Jakub Filak f4e249
+             * can't be sure here that the file we are watching
Jakub Filak f4e249
+             * is the same file where syslog(xxx) stuff ends up.
Jakub Filak f4e249
+             */
Jakub Filak f4e249
+            syslog(LOG_WARNING,
Jakub Filak f4e249
+                    "Reported %u kernel oopses to Abrt",
Jakub Filak f4e249
+                    oops_cnt
Jakub Filak f4e249
+            );
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* If we are run by a log watcher, this delays log rescan
Jakub Filak f4e249
+     * (because log watcher waits to us to terminate)
Jakub Filak f4e249
+     * and possibly prevents dreaded "abrt storm".
Jakub Filak f4e249
+     */
Jakub Filak f4e249
+    int unreported_cnt = oops_cnt - ABRT_OOPS_MAX_DUMPED_COUNT;
Jakub Filak f4e249
+    if (g_abrt_oops_sleep_woke_up_on_signal <= 0 &&
Jakub Filak f4e249
+            (unreported_cnt > 0 && (flags & ABRT_OOPS_THROTTLE_CREATION)))
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        /* Quadratic throttle time growth, but careful to not overflow in "n*n" */
Jakub Filak f4e249
+        int n = unreported_cnt > 30 ? 30 : unreported_cnt;
Jakub Filak f4e249
+        n = n * n;
Jakub Filak f4e249
+        if (n > 9)
Jakub Filak f4e249
+            log(_("Sleeping for %d seconds"), n);
Jakub Filak f4e249
+        abrt_oops_signaled_sleep(n); /* max 15 mins */
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return errors;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+/* returns number of errors */
Jakub Filak f4e249
+unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location, int flags)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    const int oops_cnt = g_list_length(oops_list);
Jakub Filak f4e249
+    unsigned countdown = ABRT_OOPS_MAX_DUMPED_COUNT; /* do not report hundreds of oopses */
Jakub Filak f4e249
+
Jakub Filak f4e249
+    log_notice("Saving %u oopses as problem dirs", oops_cnt >= countdown ? countdown : oops_cnt);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    char *cmdline_str = xmalloc_fopen_fgetline_fclose("/proc/cmdline");
Jakub Filak f4e249
+    char *fips_enabled = xmalloc_fopen_fgetline_fclose("/proc/sys/crypto/fips_enabled");
Jakub Filak f4e249
+    char *proc_modules = xmalloc_open_read_close("/proc/modules", /*maxsize:*/ NULL);
Jakub Filak f4e249
+    char *suspend_stats = xmalloc_open_read_close("/sys/kernel/debug/suspend_stats", /*maxsize:*/ NULL);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    time_t t = time(NULL);
Jakub Filak f4e249
+    const char *iso_date = iso_date_string(&t);
Jakub Filak f4e249
+    /* dump should be readable by all if we're run with -x */
Jakub Filak f4e249
+    uid_t my_euid = (uid_t)-1L;
Jakub Filak f4e249
+    mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH;
Jakub Filak f4e249
+    /* and readable only for the owner otherwise */
Jakub Filak f4e249
+    if (!(flags & ABRT_OOPS_WORLD_READABLE))
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        mode = DEFAULT_DUMP_DIR_MODE;
Jakub Filak f4e249
+        my_euid = geteuid();
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    pid_t my_pid = getpid();
Jakub Filak f4e249
+    unsigned idx = 0;
Jakub Filak f4e249
+    unsigned errors = 0;
Jakub Filak f4e249
+    while (idx < oops_cnt)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
Jakub Filak f4e249
+        sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
Jakub Filak f4e249
+        char *path = concat_path_file(dump_location, base);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode);
Jakub Filak f4e249
+        if (dd)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
Jakub Filak f4e249
+            abrt_oops_save_data_in_dump_dir(dd, (char*)g_list_nth_data(oops_list, idx++), proc_modules);
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_TYPE, "Kerneloops");
Jakub Filak f4e249
+            if (cmdline_str)
Jakub Filak f4e249
+                dd_save_text(dd, FILENAME_CMDLINE, cmdline_str);
Jakub Filak f4e249
+            if (proc_modules)
Jakub Filak f4e249
+                dd_save_text(dd, "proc_modules", proc_modules);
Jakub Filak f4e249
+            if (fips_enabled && strcmp(fips_enabled, "0") != 0)
Jakub Filak f4e249
+                dd_save_text(dd, "fips_enabled", fips_enabled);
Jakub Filak f4e249
+            if (suspend_stats)
Jakub Filak f4e249
+                dd_save_text(dd, "suspend_stats", suspend_stats);
Jakub Filak f4e249
+            dd_close(dd);
Jakub Filak f4e249
+            notify_new_path(path);
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+        else
Jakub Filak f4e249
+            errors++;
Jakub Filak f4e249
+
Jakub Filak f4e249
+        free(path);
Jakub Filak f4e249
+
Jakub Filak f4e249
+        if (--countdown == 0)
Jakub Filak f4e249
+            break;
Jakub Filak f4e249
+
Jakub Filak f4e249
+        if (dd && (flags & ABRT_OOPS_THROTTLE_CREATION))
Jakub Filak f4e249
+            if (abrt_oops_signaled_sleep(1) > 0)
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free(cmdline_str);
Jakub Filak f4e249
+    free(proc_modules);
Jakub Filak f4e249
+    free(fips_enabled);
Jakub Filak f4e249
+    free(suspend_stats);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return errors;
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+static char *abrt_oops_list_of_tainted_modules(const char *proc_modules)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    struct strbuf *result = strbuf_new();
Jakub Filak f4e249
+
Jakub Filak f4e249
+    const char *p = proc_modules;
Jakub Filak f4e249
+    for (;;)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        const char *end = strchrnul(p, '\n');
Jakub Filak f4e249
+        const char *paren = strchrnul(p, '(');
Jakub Filak f4e249
+        /* We look for a line with this format:
Jakub Filak f4e249
+         * "kvm_intel 126289 0 - Live 0xf829e000 (taint_flags)"
Jakub Filak f4e249
+         * where taint_flags have letters
Jakub Filak f4e249
+         * (flags '+' and '-' indicate (un)loading, we must ignore them).
Jakub Filak f4e249
+         */
Jakub Filak f4e249
+        while (++paren < end)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            if ((unsigned)(toupper(*paren) - 'A') <= 'Z'-'A')
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                strbuf_append_strf(result, result->len == 0 ? "%.*s" : ",%.*s",
Jakub Filak f4e249
+                        (int)(strchrnul(p,' ') - p), p
Jakub Filak f4e249
+                );
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+            if (*paren == ')')
Jakub Filak f4e249
+                break;
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+
Jakub Filak f4e249
+        if (*end == '\0')
Jakub Filak f4e249
+            break;
Jakub Filak f4e249
+        p = end + 1;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (result->len == 0)
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        strbuf_free(result);
Jakub Filak f4e249
+        return NULL;
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+    return strbuf_free_nobuf(result);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+void abrt_oops_save_data_in_dump_dir(struct dump_dir *dd, char *oops, const char *proc_modules)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    char *first_line = oops;
Jakub Filak f4e249
+    char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
Jakub Filak f4e249
+    *second_line++ = '\0';
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (first_line[0])
Jakub Filak f4e249
+        dd_save_text(dd, FILENAME_KERNEL, first_line);
Jakub Filak f4e249
+    dd_save_text(dd, FILENAME_BACKTRACE, second_line);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    /* check if trace doesn't have line: 'Your BIOS is broken' */
Jakub Filak f4e249
+    if (strstr(second_line, "Your BIOS is broken"))
Jakub Filak f4e249
+        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
Jakub Filak f4e249
+                _("A kernel problem occurred because of broken BIOS. "
Jakub Filak f4e249
+                  "Unfortunately, such problems are not fixable by kernel maintainers."));
Jakub Filak f4e249
+    /* check if trace doesn't have line: 'Your hardware is unsupported' */
Jakub Filak f4e249
+    else if (strstr(second_line, "Your hardware is unsupported"))
Jakub Filak f4e249
+        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
Jakub Filak f4e249
+                _("A kernel problem occurred, but your hardware is unsupported, "
Jakub Filak f4e249
+                  "therefore kernel maintainers are unable to fix this problem."));
Jakub Filak f4e249
+    else
Jakub Filak f4e249
+    {
Jakub Filak f4e249
+        char *tainted_short = kernel_tainted_short(second_line);
Jakub Filak f4e249
+        if (tainted_short)
Jakub Filak f4e249
+        {
Jakub Filak f4e249
+            log_notice("Kernel is tainted '%s'", tainted_short);
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
Jakub Filak f4e249
+
Jakub Filak f4e249
+            char *tnt_long = kernel_tainted_long(tainted_short);
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long);
Jakub Filak f4e249
+            free(tnt_long);
Jakub Filak f4e249
+
Jakub Filak f4e249
+            struct strbuf *reason = strbuf_new();
Jakub Filak f4e249
+            const char *fmt = _("A kernel problem occurred, but your kernel has been "
Jakub Filak f4e249
+                    "tainted (flags:%s). Kernel maintainers are unable to "
Jakub Filak f4e249
+                    "diagnose tainted reports.");
Jakub Filak f4e249
+            strbuf_append_strf(reason, fmt, tainted_short);
Jakub Filak f4e249
+
Jakub Filak f4e249
+            char *modlist = !proc_modules ? NULL : abrt_oops_list_of_tainted_modules(proc_modules);
Jakub Filak f4e249
+            if (modlist)
Jakub Filak f4e249
+            {
Jakub Filak f4e249
+                strbuf_append_strf(reason, _(" Tainted modules: %s."), modlist);
Jakub Filak f4e249
+                free(modlist);
Jakub Filak f4e249
+            }
Jakub Filak f4e249
+
Jakub Filak f4e249
+            dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason->buf);
Jakub Filak f4e249
+            strbuf_free(reason);
Jakub Filak f4e249
+            free(tainted_short);
Jakub Filak f4e249
+        }
Jakub Filak f4e249
+    }
Jakub Filak f4e249
+
Jakub Filak f4e249
+    // TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
Jakub Filak f4e249
+    // kernel oops 1st line may look quite puzzling otherwise...
Jakub Filak f4e249
+    strchrnul(second_line, '\n')[0] = '\0';
Jakub Filak f4e249
+    dd_save_text(dd, FILENAME_REASON, second_line);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_oops_signaled_sleep(int seconds)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    sigset_t set;
Jakub Filak f4e249
+    sigemptyset(&set);
Jakub Filak f4e249
+    sigaddset(&set, SIGTERM);
Jakub Filak f4e249
+    sigaddset(&set, SIGINT);
Jakub Filak f4e249
+    sigaddset(&set, SIGHUP);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    struct timespec timeout;
Jakub Filak f4e249
+    timeout.tv_sec = seconds;
Jakub Filak f4e249
+    timeout.tv_nsec = 0;
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return g_abrt_oops_sleep_woke_up_on_signal = sigtimedwait(&set, NULL, &timeout);
Jakub Filak f4e249
+}
Jakub Filak f4e249
+
Jakub Filak f4e249
+char *abrt_oops_string_filter_regex(void)
Jakub Filak f4e249
+{
Jakub Filak f4e249
+    map_string_t *settings = new_map_string();
Jakub Filak f4e249
+
Jakub Filak f4e249
+    load_abrt_plugin_conf_file("oops.conf", settings);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    int only_fatal_mce = 1;
Jakub Filak f4e249
+    try_get_map_string_item_as_bool(settings, "OnlyFatalMCE", &only_fatal_mce);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    free_map_string(settings);
Jakub Filak f4e249
+
Jakub Filak f4e249
+    if (only_fatal_mce)
Jakub Filak f4e249
+        return xstrdup("^Machine .*$");
Jakub Filak f4e249
+
Jakub Filak f4e249
+    return NULL;
Jakub Filak f4e249
+}
Jakub Filak f4e249
diff --git a/src/plugins/oops-utils.h b/src/plugins/oops-utils.h
Jakub Filak f4e249
new file mode 100644
Jakub Filak f4e249
index 0000000..947f652
Jakub Filak f4e249
--- /dev/null
Jakub Filak f4e249
+++ b/src/plugins/oops-utils.h
Jakub Filak f4e249
@@ -0,0 +1,48 @@
Jakub Filak f4e249
+/*
Jakub Filak f4e249
+ * Copyright (C) 2014  ABRT team
Jakub Filak f4e249
+ * Copyright (C) 2014  RedHat Inc
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is free software; you can redistribute it and/or modify
Jakub Filak f4e249
+ * it under the terms of the GNU General Public License as published by
Jakub Filak f4e249
+ * the Free Software Foundation; either version 2 of the License, or
Jakub Filak f4e249
+ * (at your option) any later version.
Jakub Filak f4e249
+ *
Jakub Filak f4e249
+ * This program is distributed in the hope that it will be useful,
Jakub Filak f4e249
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jakub Filak f4e249
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Jakub Filak f4e249
+ * GNU General Public License for more details.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#ifndef _ABRT_OOPS_UTILS_H_
Jakub Filak f4e249
+#define _ABRT_OOPS_UTILS_H_
Jakub Filak f4e249
+
Jakub Filak f4e249
+#include "libabrt.h"
Jakub Filak f4e249
+
Jakub Filak f4e249
+/* How many problem dirs to create at most?
Jakub Filak f4e249
+ * Also causes cooldown sleep with -t if exceeded -
Jakub Filak f4e249
+ * useful when called from a log watcher.
Jakub Filak f4e249
+ */
Jakub Filak f4e249
+#define ABRT_OOPS_MAX_DUMPED_COUNT  5
Jakub Filak f4e249
+
Jakub Filak f4e249
+#ifdef __cplusplus
Jakub Filak f4e249
+extern "C" {
Jakub Filak f4e249
+#endif
Jakub Filak f4e249
+
Jakub Filak f4e249
+enum {
Jakub Filak f4e249
+    ABRT_OOPS_THROTTLE_CREATION = 1 << 0,
Jakub Filak f4e249
+    ABRT_OOPS_WORLD_READABLE    = 1 << 1,
Jakub Filak f4e249
+    ABRT_OOPS_PRINT_STDOUT      = 1 << 2,
Jakub Filak f4e249
+};
Jakub Filak f4e249
+
Jakub Filak f4e249
+int g_abrt_oops_sleep_woke_up_on_signal;
Jakub Filak f4e249
+
Jakub Filak f4e249
+int abrt_oops_process_list(GList *oops_list, const char *dump_location, int flags);
Jakub Filak f4e249
+unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location, int flags);
Jakub Filak f4e249
+void abrt_oops_save_data_in_dump_dir(struct dump_dir *dd, char *oops, const char *proc_modules);
Jakub Filak f4e249
+int abrt_oops_signaled_sleep(int seconds);
Jakub Filak f4e249
+char *abrt_oops_string_filter_regex(void);
Jakub Filak f4e249
+
Jakub Filak f4e249
+#ifdef __cplusplus
Jakub Filak f4e249
+}
Jakub Filak f4e249
+#endif
Jakub Filak f4e249
+
Jakub Filak f4e249
+#endif /*_ABRT_OOPS_UTILS_H_*/
Jakub Filak f4e249
-- 
Jakub Filak f4e249
1.9.3
Jakub Filak f4e249