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