Blob Blame History Raw
From 865f7b88b391f2fbd71baa1aa3d6320455d4f519 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <dvlasenk@redhat.com>
Date: Fri, 26 Apr 2013 17:33:17 +0200
Subject: [ABRT PATCH 2/5] abrt-uefioops: new service

This service, once per boot, scans /sys/fs/pstore/* and crates
oops problem dirs from this data.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Signed-off-by: Martin Milata <mmilata@redhat.com>
---
 Makefile.am                        |   6 +-
 init-scripts/abrt-uefioops         |  79 ++++++++++++++++++++
 init-scripts/abrt-uefioops.service |  12 +++
 po/POTFILES.in                     |   4 +-
 src/hooks/Makefile.am              |  37 +++++++++-
 src/hooks/abrt-harvest-uefioops.in |  24 ++++++
 src/hooks/abrt-merge-uefioops.c    | 148 +++++++++++++++++++++++++++++++++++++
 7 files changed, 304 insertions(+), 6 deletions(-)
 create mode 100644 init-scripts/abrt-uefioops
 create mode 100644 init-scripts/abrt-uefioops.service
 create mode 100644 src/hooks/abrt-harvest-uefioops.in
 create mode 100644 src/hooks/abrt-merge-uefioops.c

diff --git a/Makefile.am b/Makefile.am
index cc820ee..0eecc60 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,14 +34,16 @@ if HAVE_SYSTEMD
                                   init-scripts/abrt-ccpp.service \
                                   init-scripts/abrt-oops.service \
                                   init-scripts/abrt-xorg.service \
-                                  init-scripts/abrt-vmcore.service
+                                  init-scripts/abrt-vmcore.service \
+                                  init-scripts/abrt-uefioops.service
 else
     sysv_initdir = $(sysconfdir)/rc.d/init.d/
     sysv_init_SCRIPTS = init-scripts/abrtd \
                         init-scripts/abrt-ccpp \
                         init-scripts/abrt-oops \
                         init-scripts/abrt-xorg \
-                        init-scripts/abrt-vmcore
+                        init-scripts/abrt-vmcore \
+                        init-scripts/abrt-uefioops
 endif
 
 RPM_DIRS = --define "_sourcedir `pwd`" \
diff --git a/init-scripts/abrt-uefioops b/init-scripts/abrt-uefioops
new file mode 100644
index 0000000..663e24a
--- /dev/null
+++ b/init-scripts/abrt-uefioops
@@ -0,0 +1,79 @@
+#!/bin/bash
+# Harvest UEFI-saved oopses for ABRT
+#
+# chkconfig: 35 82 16
+# description: Collects UEFI-saved oopses for ABRT
+### BEGIN INIT INFO
+# Provides: abrt-uefioops
+# Required-Start: $abrtd
+# Default-Stop: 0 1 2 6
+# Default-Start: 3 5
+# Short-Description: Collects UEFI-saved oopses for ABRT
+# Description: Collects UEFI-saved oopses for ABRT
+### END INIT INFO
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+LOCK="/var/lock/subsys/abrt-uefioops"
+HARVEST_CMD="/usr/sbin/abrt-harvest-uefioops"
+
+RETVAL=0
+
+check() {
+	# Check that we're a privileged user
+	[ "`id -u`" = 0 ] || exit 4
+}
+
+start() {
+	check
+	"$HARVEST_CMD"
+	RETVAL=$?
+	[ $RETVAL -eq 0 ] && touch -- "$LOCK"
+	return $RETVAL
+}
+
+stop() {
+	check
+	rm -f -- "$LOCK"
+	return 0
+}
+
+restart() {
+	stop
+	start
+}
+
+reload() {
+	restart
+}
+
+case "$1" in
+start)
+	start
+	;;
+stop)
+	stop
+	;;
+reload)
+	reload
+	;;
+force-reload)
+	echo "$0: Unimplemented feature."
+	RETVAL=3
+	;;
+restart)
+	restart
+	;;
+condrestart)
+	test -f "$LOCK" && restart
+	;;
+status)
+	test -f "$LOCK" && RETVAL=0 || RETVAL=3
+	;;
+*)
+	echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload}"
+	RETVAL=2
+esac
+
+exit $RETVAL
diff --git a/init-scripts/abrt-uefioops.service b/init-scripts/abrt-uefioops.service
new file mode 100644
index 0000000..cee4296
--- /dev/null
+++ b/init-scripts/abrt-uefioops.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Collect UEFI-saved oopses for ABRT
+After=abrtd.service
+Requisite=abrtd.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/abrt-harvest-uefioops
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b057a3d..26b595e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -35,13 +35,15 @@ src/plugins/collect_xsession_errors.xml.in
 src/plugins/https-utils.c
 src/plugins/bodhi.c
 
+src/hooks/abrt-merge-uefioops.c
+
 src/cli/abrt-cli.c
 src/cli/list.c
 src/cli/status.c
+
 src/plugins/analyze_CCpp.xml.in
 src/plugins/analyze_VMcore.xml.in
 src/plugins/collect_GConf.xml.in
 src/plugins/collect_vimrc_system.xml.in
 src/plugins/collect_vimrc_user.xml.in
 src/plugins/post_report.xml.in
-
diff --git a/src/hooks/Makefile.am b/src/hooks/Makefile.am
index 9f65d62..de97a88 100644
--- a/src/hooks/Makefile.am
+++ b/src/hooks/Makefile.am
@@ -12,7 +12,11 @@ dist_pluginsconf_DATA = \
 
 sbin_SCRIPTS = \
     abrt-install-ccpp-hook \
-    abrt-harvest-vmcore
+    abrt-harvest-vmcore \
+    abrt-harvest-uefioops
+
+bin_PROGRAMS = \
+    abrt-merge-uefioops
 
 libexec_PROGRAMS = abrt-hook-ccpp
 
@@ -32,10 +36,32 @@ abrt_hook_ccpp_LDADD = \
     ../lib/libabrt.la \
     $(LIBREPORT_LIBS)
 
-pyhook_PYTHON = abrt_exception_handler.py abrt.pth
+# abrt-merge-uefioops
+abrt_merge_uefioops_SOURCES = \
+    abrt-merge-uefioops.c
+abrt_merge_uefioops_CPPFLAGS = \
+    -I$(srcdir)/../include \
+    -I$(srcdir)/../lib \
+    -DVAR_RUN=\"$(VAR_RUN)\" \
+    -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+    -DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \
+    $(GLIB_CFLAGS) \
+    $(LIBREPORT_CFLAGS) \
+    -D_GNU_SOURCE
+abrt_merge_uefioops_LDADD = \
+    ../lib/libabrt.la \
+    $(LIBREPORT_LIBS)
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+
+pyhook_PYTHON = \
+	abrt_exception_handler.py \
+	abrt.pth
+
 EXTRA_DIST = abrt_exception_handler.py.in \
 	abrt-install-ccpp-hook.in \
-	abrt-harvest-vmcore.in
+	abrt-harvest-vmcore.in \
+	abrt-harvest-uefioops.in
 
 CLEANFILES := $(notdir $(wildcard *~)) $(notdir $(wildcard *\#)) $(notdir $(wildcard \.\#*)) $(notdir $(wildcard *.pyc)) $(man1_MANS)
 
@@ -63,3 +89,8 @@ abrt-harvest-vmcore: abrt-harvest-vmcore.in
 	sed -e s,\@CONF_DIR\@,\$(CONF_DIR)\,g \
 	    -e s,\@DEFAULT_DUMP_LOCATION\@,$(DEFAULT_DUMP_LOCATION),g \
 		$< >$@
+
+abrt-harvest-uefioops: abrt-harvest-uefioops.in
+	sed -e s,\@CONF_DIR\@,\$(CONF_DIR)\,g \
+	    -e s,\@DEFAULT_DUMP_LOCATION\@,$(DEFAULT_DUMP_LOCATION),g \
+		$< >$@
diff --git a/src/hooks/abrt-harvest-uefioops.in b/src/hooks/abrt-harvest-uefioops.in
new file mode 100644
index 0000000..9f63256
--- /dev/null
+++ b/src/hooks/abrt-harvest-uefioops.in
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# This script is meant to be run once at system startup after abrtd is up
+# and running. It scans /sys/fs/pstore/*, reconstructs oops text(s)
+# from these files, creates ABRT problem directories from them,
+# then removes the files (UEFI storage is a limited resource).
+#
+
+# Wait for abrtd to start. Give it at least 1 second to initialize.
+i=10
+while ! pidof abrtd >/dev/null; do
+	if test $((i--)) = 0; then
+		exit 1
+	fi
+	sleep 1
+done
+sleep 1
+
+cd /sys/fs/pstore 2>/dev/null || exit 0
+
+abrt-merge-uefioops -o * | abrt-dump-oops -D
+if test $? = 0; then
+	abrt-merge-uefioops -d *
+fi
diff --git a/src/hooks/abrt-merge-uefioops.c b/src/hooks/abrt-merge-uefioops.c
new file mode 100644
index 0000000..6fc3109
--- /dev/null
+++ b/src/hooks/abrt-merge-uefioops.c
@@ -0,0 +1,148 @@
+/*
+    Copyright (C) 2013  Red Hat, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "libabrt.h"
+
+struct oops_text {
+    unsigned panic_no;
+    unsigned part_no;
+    const char *filename;
+    char *text;
+};
+
+static
+struct oops_text *parse_file(const char *filename)
+{
+    FILE *fp = fopen(filename, "r");
+    if (!fp)
+        return NULL;
+
+    char buffer[16 * 1024];
+
+    struct oops_text *ot = NULL;
+
+    if (!fgets(buffer, sizeof(buffer), fp))
+        goto ret;
+    unsigned n1, n2;
+    int n = sscanf(buffer, "Panic#%u Part%u\n", &n1, &n2);
+    if (n != 2)
+        goto ret;
+
+    ot = xzalloc(sizeof(*ot));
+    ot->filename = filename;
+    ot->panic_no = n1;
+    ot->part_no = n2;
+
+    size_t sz = fread(buffer, 1, sizeof(buffer), fp);
+    ot->text = strndup(buffer, sz);
+
+ ret:
+    fclose(fp);
+    return ot;
+}
+
+static
+int compare_oops_texts(const void *a, const void *b)
+{
+    struct oops_text *aa = *(struct oops_text **)a;
+    struct oops_text *bb = *(struct oops_text **)b;
+    if (aa->panic_no < bb->panic_no)
+        return -1;
+    if (aa->panic_no > bb->panic_no)
+        return 1;
+    if (aa->part_no < bb->part_no)
+        return -1;
+    return (aa->part_no > bb->part_no);
+}
+
+int main(int argc, char **argv)
+{
+    /* I18n */
+    setlocale(LC_ALL, "");
+#if ENABLE_NLS
+    bindtextdomain(PACKAGE, LOCALEDIR);
+    textdomain(PACKAGE);
+#endif
+
+    abrt_init(argv);
+
+    /* Can't keep these strings/structs static: _() doesn't support that */
+    const char *program_usage_string = _(
+        "& [-v] [-od] FILE...\n"
+        "\n"
+        "Scans files for split oops message. Can print and/or delete them."
+    );
+    enum {
+        OPT_v = 1 << 0,
+        OPT_o = 1 << 1,
+        OPT_d = 1 << 2,
+    };
+    /* Keep enum above and order of options below in sync! */
+    struct options program_options[] = {
+        OPT__VERBOSE(&g_verbose),
+        OPT_BOOL('o', NULL, NULL, _("Print found oopses")),
+        OPT_BOOL('d', NULL, NULL, _("Delete files with found oopses")),
+        OPT_END()
+    };
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+
+    export_abrt_envvars(0);
+
+    struct oops_text **v = xzalloc(sizeof(v[0]));
+    int i = 0;
+
+    while (*argv)
+    {
+        v[i] = parse_file(*argv);
+        if (v[i])
+        {
+            v = xrealloc(v, (++i + 1) * sizeof(v[0]));
+            v[i] = NULL;
+        }
+        argv++;
+    }
+
+    if (i == 0) /* nothing was found */
+        return 0;
+
+    qsort(v, i, sizeof(v[0]), compare_oops_texts);
+
+    if (opts & OPT_o)
+    {
+        struct oops_text **vv = v;
+        while (*vv)
+        {
+            struct oops_text *cur_oops = *vv;
+            fputs(cur_oops->text, stdout);
+            vv++;
+        }
+    }
+
+    if (opts & OPT_d)
+    {
+        struct oops_text **vv = v;
+        while (*vv)
+        {
+            struct oops_text *cur_oops = *vv;
+            if (unlink(cur_oops->filename) != 0)
+                perror_msg("Can't unlink '%s'", cur_oops->filename);
+            vv++;
+        }
+    }
+
+    return 0;
+}
-- 
1.8.1.4