From 865f7b88b391f2fbd71baa1aa3d6320455d4f519 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko 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 Signed-off-by: Martin Milata --- 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