abrt-cli conversion to local processing
by Denys Vlasenko
Hi,
After a quick look at abrt-cli source, I think this can be approached
like this:
We add -D DIR option which specifies which directory to list.
It can be used more than once. If it is not specified,
abrt-cli defaults to -D /var/spool/abrt -D $HOME/abrt/spool.
With "abrt-cli --list", dumps from all these directories
are shown.
When "abrt-cli --report DUMP_DIR" is run and abrt-cli detects
that it can't lock DUMP_DIR for writing, it informs the user:
DUMP_DIR is not writable.
Do you want to copy it to $HOME/abrt/spool? (y/n)
(The directory to copy to can be specified by another option,
-W DIR; or we can have a convention that the DIR from the
first -D DIR option is used)
When "abrt-cli --delete DUMP_DIR" is run and abrt-cli detects
that it can't lock DUMP_DIR for writing, it tries to delete
the directory through dbus call to abrtd.
I am proceeding with implementing it. But don't hesitate
to provide your comments on the above.
Maybe I miss some problem?
--
vda
13 years, 1 month
[PATCH 1/2] load_plugin_settings.c: remove unused variable
by Nikola Pajkovsky
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
src/lib/load_plugin_settings.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/src/lib/load_plugin_settings.c b/src/lib/load_plugin_settings.c
index 0f38906..1e6b31e 100644
--- a/src/lib/load_plugin_settings.c
+++ b/src/lib/load_plugin_settings.c
@@ -35,7 +35,6 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
while ((line = xmalloc_fgetline(fp)) != NULL)
{
unsigned ii;
- bool is_value = false;
bool valid = false;
bool in_quote = false;
/* We are reusing line buffer to form temporary
@@ -61,7 +60,6 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
}
if (line[ii] == '=' && !in_quote)
{
- is_value = true;
valid = true;
*cur++ = '\0'; /* terminate key */
value = cur; /* remember where value starts */
--
1.7.4.rc2.3.g60a2e
13 years, 1 month
Retrace Server ToDo list
by Michal Toman
Hi,
we have made (together with Karel) some todo list for retrace server. If
you find any part interesting, let us know, but you are basically free
to go :).
At the moment, I'm working on:
Task cleanup
Reporting statistics
Incomplete backtraces - a little
HTTPS certificates
In the future, I'd like to work on remote GDB sessions.
Michal
Here's the list:
--- What NEEDS to be done for F15 ---
* CLI - Command line tool providing retrace client functionality: create
new task, ask about status, log, backtrace.
* GUI - Integrate retrace server with ABRT GUI.
* Task cleanup - A tool cleaning /var/spool/abrt-retrace directory from
tasks older than some threshold (5 days?). Periodically called from cron.
* Trusted HTTPS certificates - Get trusted HTTPS certificates from
Fedora infrastructure.
* Incomplete backtraces - Find out why some packages do not generate
full backtraces and deal with the differences between backtraces
generated on F14 and RHEL6 hosts.
* Reporting statistics - Retrace worker should save some statistics.
What information exactly do we want to save? (package name, duration,
version, parallel tasks?)
* Manual - Convert design document to manual.
* Security audit - Look the code for possible security holes - running
file contents in shell etc. :).
--- What SHOULD be done in the future ---
* Only use coredump - Do not require additional files (architecture,
package etc.), coredump should contain all necessary information.
* Support different archive formats - Accept gz, bz2 (...?) comressed
archives and also archives with no compression - fastest on LAN.
* Calculate estimated time - When enough statistics are gathered, try to
estimate retrace duration and send it to the client. Client does not
need to ask about status before.
* Support keep-alive HTTP connection - Status script should not close
HTTP connection, but send task status to the client every ~10 seconds.
The connection is closed once retrace job is complete.
* Handle specific crashes (gdb, libc etc.) - Handle crashes from
binaries and libraries required by the retrace server itself.
* Coredump stripping - Only send some smaller part of (possibly large)
coredump, the one really required by GDB.
* Write SELinux policy - Do we really need it?
* Support rawhide - Deal with the problem of enormous number of packages.
* User authentication - Mostly for corporate use, every retrace job has
an owner, who is able to re-run, delete, modify... it. Impossible in Fedora.
* Multiarch support - Support multiple architectures (i386, x86_64, ppc,
ppc64 etc.) on the same machine.
* Providing GDB debugging sessions - Allow users to debug their crashes
remotely.
* Statistics cleanup - Delete old statistics from stats database. Do we
really need it?
* 3rd party packages support - Allow users to add their own packages and
debuginfos to the retrace request. Allow also to process non-official
repositories like rpmfusion?
* WebUI - Provide the statistics and even the possibility of uploading
coredump from web browser. Do we really need it?
* Speed optimizations:
** RPM package stripping - Discard all unnecessary information from
RPMs. Store only binaries, libraries and debuginfos. Would be very useful.
** Jobs planning - Change the priority of retrace jobs to gain better
efficiency.
** Updates-testing cleanup - Do not store packages in updates and
updates-testing repositories twice.
** Integrate with DebuginfoFS - Once DebuginfoFS is complete.
13 years, 2 months
Retrace server: two interface changes
by Karel Klic
Michal,
I'd like to propose two changes to the interface code:
(1) Currently the status can be obtained by accessing
"https://server/2222/", where 2222 = task id. We should support URLs
without the ending '/' - just "https://server/2222".
When doing this change I also updated the URL matching in the Apache
config file, to match our task ids (numbers only).
See paths.patch.
(2) Every client access to '/2222', '/2222/log', '/2222/backtrace'
changes the task password. I think it's ok to generate the password only
in /create, and use the same password for all GET requests. It also
simplifies the client a lot.
See keep-initial-password.patch.
Please consider the changes for inclusion.
Thank you.
Karel
13 years, 2 months
Retrace server: 413 Request Entity Too Large
by Karel Klic
Hi Michal,
Our retrace server responded "413 Request Entity Too Large" instead of
accepting a pretty common Firefox crash (~15 tabs opened). The .tar.xz
archive with the crash has 41 MB, and the coredump inside has 366 MB.
In the design doc a 30 MB limit is mentioned, and I see the limit is
configurable in /etc/abrt/retrace.conf: MaxPackedSize = 30.
We want to support retracing of Firefox crashes. So I have increased the
value on the retrace server to 50 MB.
I'll increase the limit to 50 MB in git and docs as well, so it becomes
the new default value, if you have no objection.
Karel
13 years, 2 months
[PATCH] install ccpp hook using a separate service
by Denys Vlasenko
As discussed, here is the patch
which moves (de)installation of abrt-hook-ccpp
into abrt-ccpp service. It is packaged and installed with
abrt-addon-ccpp package.
In order to not install it twice, "old" plugin loading in abrtd
is disabled (pending deletion of entire "old" plugin machinery).
Run-tested.
--
vda
diff -x '*.po' -d -urpN abrt.3/abrt-ccpp.init abrt.4/abrt-ccpp.init
--- abrt.3/abrt-ccpp.init 1970-01-01 01:00:00.000000000 +0100
+++ abrt.4/abrt-ccpp.init 2011-01-19 16:05:27.592566646 +0100
@@ -0,0 +1,122 @@
+#!/bin/bash
+# Install abrt coredump hook
+#
+# chkconfig: 35 82 16
+# description: Installs coredump handler which saves segfault data
+### BEGIN INIT INFO
+# Provides: abrt-ccpp
+# Required-Start: $abrtd
+# Default-Stop: 0 1 2 6
+# Default-Start: 3 5
+# Short-Description: Installs coredump handler which saves segfault data
+# Description: Installs coredump handler which saves segfault data
+### END INIT INFO
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# For debugging
+dry_run=false
+verbose=false
+
+PATTERN_FILE="/proc/sys/kernel/core_pattern"
+SAVED_PATTERN_FILE="/var/run/abrt/saved_core_pattern"
+HOOK_BIN="/usr/libexec/abrt-hook-ccpp"
+PATTERN="|$HOOK_BIN /var/spool/abrt %s %c %p %u %g %t %h %e"
+
+RETVAL=0
+
+check() {
+ # Check that we're a privileged user
+ [ "`id -u`" = 0 ] || exit 4
+}
+
+start() {
+ check
+
+ cur=`cat "$PATTERN_FILE"`
+ cur_first=`printf "%s" "$cur" | sed 's/ .*//'`
+
+ $verbose && printf "cur:'%s'\n" "$cur"
+ # Is it already installed?
+ if test x"$cur_first" != x"|$HOOK_BIN"; then # no
+ # It is not installed
+ printf "%s\n" "$cur" >"$SAVED_PATTERN_FILE"
+ OLD_PATTERN=""
+ # Does old pattern start with '|'?
+ if test x"${cur#|}" = x"$cur"; then # no
+ # Encode it as hex string, NUL terminated
+ OLD_PATTERN=`printf "%s" "$cur" | od -tx1 | sed 's/000[^ ]*//' | xargs | sed 's/ //g'`
+ $verbose && printf "OLD_PATTERN:'%s'\n" "$OLD_PATTERN"
+ OLD_PATTERN=" ${OLD_PATTERN}00"
+ fi
+ # Install new handler
+ $verbose && printf "Installing to %s:'%s'\n" "$PATTERN_FILE" "${PATTERN}${OLD_PATTERN}"
+ $dry_run || echo "${PATTERN}${OLD_PATTERN}" >"$PATTERN_FILE"
+ fi
+ return $RETVAL
+}
+
+stop() {
+ check
+
+ if test -f "$SAVED_PATTERN_FILE"; then
+ $verbose && printf "Restoring to %s:'%s'\n" "$PATTERN_FILE" "`cat "$SAVED_PATTERN_FILE"`"
+ $dry_run || cat "$SAVED_PATTERN_FILE" >"$PATTERN_FILE"
+ fi
+ return $RETVAL
+}
+
+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)
+ cur=`cat "$PATTERN_FILE"`
+ cur_first=`printf "%s" "$cur" | sed 's/ .*//'`
+ # Is it already installed?
+ if test x"$cur_first" = x"|$HOOK_BIN"; then # yes
+ $verbose && printf "Installed, re-installing\n"
+ restart
+ fi
+ ;;
+status)
+ cur=`cat "$PATTERN_FILE"`
+ cur_first=`printf "%s" "$cur" | sed 's/ .*//'`
+ # Is it already installed?
+ if test x"$cur_first" = x"|$HOOK_BIN"; then # yes
+ $verbose && printf "Installed\n"
+ RETVAL=0
+ else
+ $verbose && printf "Not installed\n"
+ RETVAL=3 # "stopped normally"
+ fi
+ ;;
+*)
+ echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload}"
+ RETVAL=2
+esac
+
+exit $RETVAL
diff -x '*.po' -d -urpN abrt.3/abrt.spec abrt.4/abrt.spec
--- abrt.3/abrt.spec 2011-01-17 16:42:11.797308103 +0100
+++ abrt.4/abrt.spec 2011-01-19 15:50:32.850816651 +0100
@@ -28,6 +28,7 @@ Group: Applications/System
URL: https://fedorahosted.org/abrt/
Source: https://fedorahosted.org/released/%{name}/%{name}-%{version}.tar.gz
Source1: abrt.init
+Source2: abrt-ccpp.init
BuildRequires: dbus-devel
BuildRequires: gtk2-devel
BuildRequires: curl-devel
@@ -250,6 +251,7 @@ make install DESTDIR=$RPM_BUILD_ROOT man
find $RPM_BUILD_ROOT -name '*.la' -or -name '*.a' | xargs rm -f
mkdir -p ${RPM_BUILD_ROOT}/%{_initrddir}
install -m 755 %SOURCE1 ${RPM_BUILD_ROOT}/%{_initrddir}/abrtd
+install -m 755 %SOURCE2 ${RPM_BUILD_ROOT}/%{_initrddir}/abrt-ccpp
# /var/cache/abrt is to be removed in 1.3.x timeframe
mkdir -p $RPM_BUILD_ROOT/var/cache/abrt
mkdir -p $RPM_BUILD_ROOT/var/cache/abrt-di
@@ -354,7 +356,7 @@ fi
%config(noreplace) %{_sysconfdir}/%{name}/abrt_event.conf
%config(noreplace) %{_sysconfdir}/%{name}/gpg_keys
%config(noreplace) %{_sysconfdir}/dbus-1/system.d/dbus-abrt.conf
-%{_initrddir}/%{name}d
+%{_initrddir}/abrtd
# /var/cache/abrt is to be removed in 1.3.x timeframe
%dir %attr(0755, abrt, abrt) %{_localstatedir}/cache/%{name}
%dir %attr(0755, abrt, abrt) %{_localstatedir}/spool/%{name}
@@ -414,6 +416,7 @@ fi
%defattr(-,root,root,-)
%config(noreplace) %{_sysconfdir}/%{name}/plugins/CCpp.conf
%dir %{_localstatedir}/cache/abrt-di
+%{_initrddir}/abrt-ccpp
%{_libdir}/%{name}/libCCpp.so*
%{_libexecdir}/abrt-hook-ccpp
%{_bindir}/abrt-action-analyze-c
diff -x '*.po' -d -urpN abrt.3/src/daemon/Daemon.cpp abrt.4/src/daemon/Daemon.cpp
--- abrt.3/src/daemon/Daemon.cpp 2011-01-17 17:07:14.011558651 +0100
+++ abrt.4/src/daemon/Daemon.cpp 2011-01-19 15:51:09.153816135 +0100
@@ -676,10 +676,6 @@ int main(int argc, char** argv)
handle_inotify_cb,
NULL);
- VERB1 log("Loading plugins from "PLUGINS_LIB_DIR);
- g_pPluginManager = new CPluginManager();
- g_pPluginManager->LoadPlugins();
-
/* Add an event source which waits for INT/TERM signal */
VERB1 log("Adding signal pipe watch to glib main loop");
channel_signal = g_io_channel_unix_new(s_signal_pipe[0]);
@@ -771,12 +767,7 @@ int main(int argc, char** argv)
g_io_channel_unref(channel_inotify);
delete g_pCommLayer;
- if (g_pPluginManager)
- {
- /* This restores /proc/sys/kernel/core_pattern, among other things: */
- g_pPluginManager->UnLoadPlugins();
- delete g_pPluginManager;
- }
+
if (pMainloop)
g_main_loop_unref(pMainloop);
13 years, 2 months
[PATCH] remove "old plugin" infrastructure
by Denys Vlasenko
Finally, we can remove old plugins.
This only requires moving ccpp hook (de)installation
from last existing plugin, CCpp, to abrtd.
This moves us closer to dropping all remaining C++ bits.
Deleted source files:
src/daemon/PluginManager.cpp
src/daemon/PluginManager.h
src/include/action.h
src/include/analyzer.h
src/lib/Plugin.cpp
src/plugins/CCpp.cpp
src/plugins/CCpp.h
abrtd lose libdl dependency and 10k of code:
text data bss dec hex filename
89731 2612 496 92839 16aa7 abrtd.old
77341 2580 504 80425 13a29 abrtd
Run tested.
Please review.
--
vda
diff -x '*.po' -d -urpN abrt.3/abrt.spec abrt.4/abrt.spec
--- abrt.3/abrt.spec 2011-01-17 16:42:11.797308103 +0100
+++ abrt.4/abrt.spec 2011-01-17 17:12:18.889558699 +0100
@@ -414,7 +414,6 @@ fi
%defattr(-,root,root,-)
%config(noreplace) %{_sysconfdir}/%{name}/plugins/CCpp.conf
%dir %{_localstatedir}/cache/abrt-di
-%{_libdir}/%{name}/libCCpp.so*
%{_libexecdir}/abrt-hook-ccpp
%{_bindir}/abrt-action-analyze-c
%{_bindir}/abrt-action-install-debuginfo.py*
diff -x '*.po' -d -urpN abrt.3/configure.ac abrt.4/configure.ac
--- abrt.3/configure.ac 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/configure.ac 2011-01-17 17:10:24.067558532 +0100
@@ -108,7 +108,6 @@ AC_SUBST(PLUGINS_CONF_DIR)
AC_SUBST(PLUGINS_LIB_DIR)
AC_SUBST(DEBUG_DUMPS_DIR)
AC_SUBST(DEBUG_INFO_DIR)
-AC_SUBST(DL_LIBS, -ldl)
AC_SUBST(LIBEXEC_DIR)
# Initialize the test suite.
diff -x '*.po' -d -urpN abrt.3/src/daemon/Daemon.cpp abrt.4/src/daemon/Daemon.cpp
--- abrt.3/src/daemon/Daemon.cpp 2011-01-17 17:07:14.011558651 +0100
+++ abrt.4/src/daemon/Daemon.cpp 2011-01-17 17:26:23.354559010 +0100
@@ -203,6 +203,222 @@ static void dumpsocket_shutdown()
}
}
+
+/* CCpp hook handling */
+
+#define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern"
+/*
+ * %s - signal number
+ * %c - ulimit -c value
+ * %p - pid
+ * %u - uid
+ * %g - gid
+ * %t - UNIX time of dump
+ * %h - hostname
+ * %e - executable filename
+ * %% - output one "%"
+ */
+#define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %s %c %p %u %g %t %h %e"
+
+#define CORE_PIPE_LIMIT_IFACE "/proc/sys/kernel/core_pipe_limit"
+/* core_pipe_limit specifies how many dump_helpers might run at the same time
+ * 0 - means unlimited, but it's not guaranteed that /proc/<pid> of crashing
+ * process will be available for dump_helper.
+ * 4 - means that 4 dump_helpers can run at the same time (the rest will also
+ * run, but they will fail to read /proc/<pid>).
+ * This should be enough for ABRT, we can miss some crashes, but what are
+ * the odds that more processes crash at the same time?
+ * The value of 4 has been recommended by nhorman.
+ */
+#define CORE_PIPE_LIMIT "4"
+
+#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di"
+
+static char *old_core_pattern = NULL;
+
+/*
+ * this is just a workaround until kernel changes it's behavior
+ * when handling pipes in core_pattern
+ */
+#ifdef HOSTILE_KERNEL
+#define CORE_SIZE_PATTERN "Max core file size=1:unlimited"
+static int isdigit_str(char *str)
+{
+ do {
+ if (*str < '0' || *str > '9')
+ return 0;
+ } while (*++str);
+ return 1;
+}
+
+static int set_limits()
+{
+ DIR *dir = opendir("/proc");
+ if (!dir) {
+ /* this shouldn't fail, but to be safe.. */
+ return 1;
+ }
+
+ struct dirent *ent;
+ while ((ent = readdir(dir)) != NULL) {
+ if (!isdigit_str(ent->d_name))
+ continue;
+
+ char limits_name[sizeof("/proc/%s/limits") + sizeof(long)*3];
+ snprintf(limits_name, sizeof(limits_name), "/proc/%s/limits", ent->d_name);
+ FILE *limits_fp = fopen(limits_name, "r");
+ if (!limits_fp) {
+ break;
+ }
+
+ char line[128];
+ char *ulimit_c = NULL;
+ while (1) {
+ if (fgets(line, sizeof(line)-1, limits_fp) == NULL)
+ break;
+ if (strncmp(line, "Max core file size", sizeof("Max core file size")-1) == 0) {
+ ulimit_c = skip_whitespace(line + sizeof("Max core file size")-1);
+ skip_non_whitespace(ulimit_c)[0] = '\0';
+ break;
+ }
+ }
+ fclose(limits_fp);
+ if (!ulimit_c || ulimit_c[0] != '0' || ulimit_c[1] != '\0') {
+ /*process has nonzero ulimit -c, so need to modify it*/
+ continue;
+ }
+ /* echo -n 'Max core file size=1:unlimited' >/proc/PID/limits */
+ int fd = open(limits_name, O_WRONLY);
+ if (fd >= 0) {
+ errno = 0;
+ /*full_*/
+ ssize_t n = write(fd, CORE_SIZE_PATTERN, sizeof(CORE_SIZE_PATTERN)-1);
+ if (n < sizeof(CORE_SIZE_PATTERN)-1)
+ log("warning: can't write core_size limit to: %s", limits_name);
+ close(fd);
+ }
+ else
+ {
+ log("warning: can't open %s for writing", limits_name);
+ }
+ }
+ closedir(dir);
+ return 0;
+}
+#endif /* HOSTILE_KERNEL */
+
+static void ccpp_hook_init(void)
+{
+ FILE *fp = fopen(CORE_PATTERN_IFACE, "r");
+ if (fp)
+ {
+ old_core_pattern = xmalloc_fgetline(fp);
+ fclose(fp);
+ }
+ if (old_core_pattern && old_core_pattern[0] == '|')
+ {
+ if (strncmp(old_core_pattern, CORE_PATTERN, strlen(CORE_PATTERN)) == 0)
+ {
+ log("warning: %s already contains %s, "
+ "did abrt daemon crash recently?",
+ CORE_PATTERN_IFACE, CORE_PATTERN);
+ /* There is no point in "restoring" CORE_PATTERN_IFACE
+ * to CORE_PATTERN on exit. Will restore to a default value:
+ */
+ free(old_core_pattern);
+ old_core_pattern = xstrdup("core");
+ } else {
+ log("warning: %s was already set to run a crash analyser (%s), "
+ "abrt may interfere with it",
+ CORE_PATTERN_IFACE, CORE_PATTERN);
+ }
+ }
+#ifdef HOSTILE_KERNEL
+ if (set_limits() != 0)
+ log("warning: failed to set core_size limit, abrt won't detect crashes in"
+ "compiled apps");
+#endif
+
+ fp = fopen(CORE_PATTERN_IFACE, "w");
+ if (fp)
+ {
+ if (old_core_pattern && old_core_pattern[0] != '|')
+ {
+ const char *old = old_core_pattern;
+ unsigned len = strchrnul(old, '\n') - old;
+ char *hex_old = (char*)xmalloc(len * 2 + 1);
+ bin2hex(hex_old, old, len)[0] = '\0';
+ /* Trailing 00 is a sentinel. Decoder in the hook will check it.
+ * If it won't see it, then kernel has truncated the argument:
+ */
+ char *pattern = xasprintf("%s %s00", CORE_PATTERN, hex_old);
+ //log("old:'%s'->'%s'", old, hex_old);
+ //log("pattern:'%s'", pattern);
+
+ fputs(pattern, fp);
+
+ free(pattern);
+ free(hex_old);
+ }
+ else
+ {
+ fputs(CORE_PATTERN, fp);
+ }
+ fclose(fp);
+ }
+
+ /* Read the core_pipe_limit and change it if it is 0,
+ * otherwise the abrt-hook-ccpp won't be able to read /proc/<pid>
+ * of the crashing process.
+ */
+ fp = fopen(CORE_PIPE_LIMIT_IFACE, "r");
+ if (fp)
+ {
+ /* we care only about the first char, if it's
+ * not '0' then we don't have to change it,
+ * because it means that it's already != 0
+ */
+ char pipe_limit[2];
+ if (!fgets(pipe_limit, sizeof(pipe_limit), fp))
+ pipe_limit[0] = '1'; /* not 0 */
+ fclose(fp);
+ if (pipe_limit[0] == '0')
+ {
+ fp = fopen(CORE_PIPE_LIMIT_IFACE, "w");
+ if (fp)
+ {
+ fputs(CORE_PIPE_LIMIT, fp);
+ fclose(fp);
+ }
+ else
+ {
+ log("warning: failed to set core_pipe_limit, ABRT won't detect"
+ "crashes in compiled apps if kernel > 2.6.31");
+ }
+ }
+ }
+}
+
+static void ccpp_hook_deinit(void)
+{
+ /* no need to restore the core_pipe_limit, because it's only used
+ * when there is s pipe in core_pattern
+ */
+
+ if (old_core_pattern)
+ {
+ FILE *fp = fopen(CORE_PATTERN_IFACE, "w");
+ if (fp)
+ {
+ fputs(old_core_pattern, fp);
+ fclose(fp);
+ }
+ }
+}
+
+
+/* Misc init functions */
+
static int CreatePidFile()
{
int fd;
@@ -245,6 +461,10 @@ static int Lock()
/* we leak opened lfd intentionally */
}
+
+/* Misc handlers */
+
+/* Signal handler */
static void handle_signal(int signo)
{
int save_errno = errno;
@@ -653,8 +873,9 @@ int main(int argc, char** argv)
VERB1 log("Creating glib main loop");
pMainloop = g_main_loop_new(NULL, FALSE);
- VERB1 log("Initializing inotify");
sanitize_dump_dir_rights();
+
+ VERB1 log("Initializing inotify");
errno = 0;
int inotify_fd = inotify_init();
if (inotify_fd == -1)
@@ -676,9 +897,8 @@ int main(int argc, char** argv)
handle_inotify_cb,
NULL);
- VERB1 log("Loading plugins from "PLUGINS_LIB_DIR);
- g_pPluginManager = new CPluginManager();
- g_pPluginManager->LoadPlugins();
+ VERB1 log("Installing core dump hook");
+ ccpp_hook_init();
/* Add an event source which waits for INT/TERM signal */
VERB1 log("Adding signal pipe watch to glib main loop");
@@ -771,12 +991,9 @@ int main(int argc, char** argv)
g_io_channel_unref(channel_inotify);
delete g_pCommLayer;
- if (g_pPluginManager)
- {
- /* This restores /proc/sys/kernel/core_pattern, among other things: */
- g_pPluginManager->UnLoadPlugins();
- delete g_pPluginManager;
- }
+
+ ccpp_hook_deinit();
+
if (pMainloop)
g_main_loop_unref(pMainloop);
diff -x '*.po' -d -urpN abrt.3/src/daemon/Daemon.h abrt.4/src/daemon/Daemon.h
--- abrt.3/src/daemon/Daemon.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/Daemon.h 2011-01-17 17:05:35.010558752 +0100
@@ -25,12 +25,8 @@
class CCrashWatcher;
class CCommLayerServer;
-class CPluginManager;
/* Used for sending dbus signals */
extern CCommLayerServer *g_pCommLayer;
-/* Collection of loaded plugins */
-extern CPluginManager* g_pPluginManager;
-
#endif
diff -x '*.po' -d -urpN abrt.3/src/daemon/Makefile.am abrt.4/src/daemon/Makefile.am
--- abrt.3/src/daemon/Makefile.am 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/Makefile.am 2011-01-17 17:29:10.939558611 +0100
@@ -10,7 +10,6 @@ sbin_PROGRAMS = \
abrt-server
abrtd_SOURCES = \
- PluginManager.h PluginManager.cpp \
MiddleWare.h MiddleWare.cpp \
CrashWatcher.h CrashWatcher.cpp \
CommLayerServer.h CommLayerServer.cpp \
@@ -28,6 +27,7 @@ abrtd_CPPFLAGS = \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-DLIBEXEC_DIR=\"$(LIBEXEC_DIR)\" \
+ -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
$(ENABLE_SOCKET_OR_DBUS) \
diff -x '*.po' -d -urpN abrt.3/src/daemon/MiddleWare.cpp abrt.4/src/daemon/MiddleWare.cpp
--- abrt.3/src/daemon/MiddleWare.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/MiddleWare.cpp 2011-01-17 17:21:23.813558211 +0100
@@ -19,6 +19,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "abrtlib.h"
+#include "plugin.h"
#include "Daemon.h"
#include "Settings.h"
#include "comm_layer_inner.h"
@@ -28,14 +29,6 @@
using namespace std;
/**
- * An instance of CPluginManager. When MiddleWare wants to do something
- * with plugins, it calls the plugin manager.
- * @see PluginManager.h
- */
-CPluginManager* g_pPluginManager;
-
-
-/**
* Get one crash info. If getting is successful,
* then crash info is filled.
* @param dump_dir_name A dump dir containing all necessary data.
@@ -179,19 +172,6 @@ static mw_result_t CreateCrashReport(con
return r;
}
-void RunAction(const char *pActionDir,
- const char *pPluginName,
- const char *pPluginArgs)
-{
- CAction* action = g_pPluginManager->GetAction(pPluginName);
- if (!action)
- {
- /* GetAction() already complained */
- return;
- }
- action->Run(pActionDir, pPluginArgs, /*force:*/ 0);
-}
-
struct logging_state {
char *last_line;
};
diff -x '*.po' -d -urpN abrt.3/src/daemon/MiddleWare.h abrt.4/src/daemon/MiddleWare.h
--- abrt.3/src/daemon/MiddleWare.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/MiddleWare.h 2011-01-17 17:05:38.916559022 +0100
@@ -23,7 +23,6 @@
#define MIDDLEWARE_H_
#include "abrt_types.h"
-#include "PluginManager.h"
/**
* An enum contains all return codes.
@@ -46,15 +45,6 @@ typedef enum {
/**
- * Activates particular action plugin.
- * @param pActionDir A directory, which is passed as working to a action plugin.
- * @param pPluginName An action plugin name.
- * @param pPluginArgs Action plugin's arguments.
- */
-void RunAction(const char *pActionDir,
- const char *pPluginName,
- const char *pPluginArgs);
-/**
* Reports a crash report to particular receiver. It
* takes an user uid, tries to find user config file and load it. If it
* fails, then default config is used. If pUID is emply string, default
diff -x '*.po' -d -urpN abrt.3/src/daemon/PluginManager.cpp abrt.4/src/daemon/PluginManager.cpp
--- abrt.3/src/daemon/PluginManager.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/PluginManager.cpp 1970-01-01 01:00:00.000000000 +0100
@@ -1,264 +0,0 @@
-/*
- PluginManager.cpp
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <dlfcn.h>
-#include "abrtlib.h"
-#include "PluginManager.h"
-
-using namespace std;
-
-
-/**
- * CLoadedModule class. A class which contains a loaded plugin.
- */
-class CLoadedModule
-{
- private:
- /* dlopen'ed library */
- void *m_pHandle;
- const plugin_info_t *m_pPluginInfo;
- CPlugin* (*m_pFnPluginNew)();
-
- public:
- CLoadedModule(void *handle, const char *mod_name);
- ~CLoadedModule() { dlclose(m_pHandle); }
- int GetMagicNumber() { return m_pPluginInfo->m_nMagicNumber; }
- const char *GetVersion() { return m_pPluginInfo->m_sVersion; }
- const char *GetName() { return m_pPluginInfo->m_sName; }
- const char *GetDescription() { return m_pPluginInfo->m_sDescription; }
- const char *GetEmail() { return m_pPluginInfo->m_sEmail; }
- const char *GetWWW() { return m_pPluginInfo->m_sWWW; }
- const char *GetGTKBuilder() { return m_pPluginInfo->m_sGTKBuilder; }
- plugin_type_t GetType() { return m_pPluginInfo->m_Type; }
- CPlugin *PluginNew() { return m_pFnPluginNew(); }
-};
-CLoadedModule::CLoadedModule(void *handle, const char *mod_name)
-{
- m_pHandle = handle;
- /* All errors are fatal */
-#define LOADSYM(fp, handle, name) \
- do { \
- fp = (typeof(fp)) (dlsym(handle, name)); \
- if (!fp) \
- error_msg_and_die("'%s' has no %s entry", mod_name, name); \
- } while (0)
-
- LOADSYM(m_pPluginInfo, handle, "plugin_info");
- LOADSYM(m_pFnPluginNew, handle, "plugin_new");
-#undef LOADSYM
-}
-
-
-/**
- * Text representation of plugin types.
- */
-static const char *const plugin_type_str[] = {
- "Analyzer",
- "Action",
- "Reporter",
- "Database"
-};
-
-
-CPluginManager::CPluginManager()
-{}
-
-CPluginManager::~CPluginManager()
-{}
-
-void CPluginManager::LoadPlugins()
-{
- DIR *dir = opendir(PLUGINS_LIB_DIR);
- if (dir != NULL)
- {
- struct dirent *dent;
- while ((dent = readdir(dir)) != NULL)
- {
- if (!is_regular_file(dent, PLUGINS_LIB_DIR))
- continue;
- char *ext = strrchr(dent->d_name, '.');
- if (!ext || strcmp(ext + 1, PLUGINS_LIB_EXTENSION) != 0)
- continue;
- *ext = '\0';
- if (strncmp(dent->d_name, PLUGINS_LIB_PREFIX, sizeof(PLUGINS_LIB_PREFIX)-1) != 0)
- continue;
- LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1, /*enabled_only:*/ true);
- }
- closedir(dir);
- }
-}
-
-void CPluginManager::UnLoadPlugins()
-{
- map_loaded_module_t::iterator it_module;
- while ((it_module = m_mapLoadedModules.begin()) != m_mapLoadedModules.end())
- {
- UnLoadPlugin(it_module->first.c_str());
- }
-}
-
-CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only)
-{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin != m_mapPlugins.end())
- {
- return it_plugin->second; /* ok */
- }
-
- map_string_t plugin_info;
- plugin_info["Name"] = pName;
-
- const char *conf_name = pName;
- if (strncmp(pName, "Kerneloops", sizeof("Kerneloops")-1) == 0)
- {
- /* Kerneloops{,Scanner,Reporter} share the same .conf file */
- conf_name = "Kerneloops";
- }
- char *conf_fullname = xasprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name);
- map_string_h *pluginSettings = new_map_string();
- if (load_conf_file(conf_fullname, pluginSettings, /*skip key w/o values:*/ true))
- VERB3 log("Loaded %s.conf", conf_name);
- free(conf_fullname);
-
- if (enabled_only)
- {
- if (!string_to_bool(get_map_string_item_or_empty(pluginSettings, "Enabled")))
- {
- plugin_info["Enabled"] = "no";
- string empty;
- plugin_info["Type"] = empty;
- plugin_info["Version"] = empty;
- plugin_info["Description"] = empty;
- plugin_info["Email"] = empty;
- plugin_info["WWW"] = empty;
- plugin_info["GTKBuilder"] = empty;
- VERB3 log("Plugin %s: 'Enabled' is not set, not loading it (yet)", pName);
- free_map_string(pluginSettings);
- return NULL; /* error */
- }
- }
-
- char *libPath = xasprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName);
- void *handle = dlopen(libPath, RTLD_NOW);
- if (!handle)
- {
- error_msg("Can't load '%s': %s", libPath, dlerror());
- free(libPath);
- free_map_string(pluginSettings);
- return NULL; /* error */
- }
- free(libPath);
- CLoadedModule *module = new CLoadedModule(handle, pName);
- if (module->GetMagicNumber() != PLUGINS_MAGIC_NUMBER
- || module->GetType() < 0
- || module->GetType() > MAX_PLUGIN_TYPE
- ) {
- error_msg("Can't load non-compatible plugin %s: magic %d != %d or type %d is not in [0,%d]",
- pName,
- module->GetMagicNumber(), PLUGINS_MAGIC_NUMBER,
- module->GetType(), MAX_PLUGIN_TYPE);
- delete module;
- free_map_string(pluginSettings);
- return NULL; /* error */
- }
- VERB3 log("Loaded plugin %s v.%s", pName, module->GetVersion());
-
- CPlugin *plugin = NULL;
- plugin = module->PluginNew();
- plugin->Init();
- /* Need to convert pluginSettings from map_string_h container
- * to map_string_t, since plugin->SetSettings() needs that type.
- * To be removed when remaining uses of map_string_t
- * are globally converted to map_string_h.
- */
- {
- map_string_t pluginSettings2;
- GHashTableIter iter;
- char *name;
- char *value;
- g_hash_table_iter_init(&iter, pluginSettings);
- while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
- {
- pluginSettings2[name] = value;
- }
- plugin->SetSettings(pluginSettings2);
- }
- free_map_string(pluginSettings);
-
- plugin_info["Enabled"] = "yes";
- plugin_info["Type"] = plugin_type_str[module->GetType()];
- //plugin_info["Name"] = module->GetName();
- plugin_info["Version"] = module->GetVersion();
- plugin_info["Description"] = module->GetDescription();
- plugin_info["Email"] = module->GetEmail();
- plugin_info["WWW"] = module->GetWWW();
- plugin_info["GTKBuilder"] = module->GetGTKBuilder();
-
- m_mapLoadedModules[pName] = module;
- m_mapPlugins[pName] = plugin;
- log("Registered %s plugin '%s'", plugin_type_str[module->GetType()], pName);
- return plugin; /* ok */
-}
-
-void CPluginManager::UnLoadPlugin(const char *pName)
-{
- map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName);
- if (it_module != m_mapLoadedModules.end())
- {
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin != m_mapPlugins.end()) /* always true */
- {
- it_plugin->second->DeInit();
- delete it_plugin->second;
- m_mapPlugins.erase(it_plugin);
- }
- log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName);
- delete it_module->second;
- m_mapLoadedModules.erase(it_module);
- }
-}
-
-CAction* CPluginManager::GetAction(const char *pName, bool silent)
-{
- CPlugin *plugin = LoadPlugin(pName);
- if (!plugin)
- {
- error_msg("Plugin '%s' is not registered", pName);
- return NULL;
- }
- if (m_mapLoadedModules[pName]->GetType() != ACTION)
- {
- if (!silent)
- error_msg("Plugin '%s' is not an action plugin", pName);
- return NULL;
- }
- return (CAction*)plugin;
-}
-
-plugin_type_t CPluginManager::GetPluginType(const char *pName)
-{
- CPlugin *plugin = LoadPlugin(pName);
- if (!plugin)
- {
- return INVALID_PLUGIN_TYPE;
- }
- map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName);
- return it_module->second->GetType();
-}
diff -x '*.po' -d -urpN abrt.3/src/daemon/PluginManager.h abrt.4/src/daemon/PluginManager.h
--- abrt.3/src/daemon/PluginManager.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/daemon/PluginManager.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,95 +0,0 @@
-/*
- PluginManager.h - header file for plugin manager. it takes care about
- (un)loading plugins
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#ifndef PLUGINMANAGER_H_
-#define PLUGINMANAGER_H_
-
-#include "abrt_types.h"
-#include "plugin.h"
-#include "analyzer.h"
-#include "action.h"
-
-class CLoadedModule; /* opaque */
-
-/**
- * A class. It takes care of loading, registering and manipulating with
- * plugins. When a plugin is loaded, its library is opened, but no plugin
- * instance is created. It is possible after plugin registration.
- */
-class CPluginManager
-{
- private:
- typedef std::map<std::string, CLoadedModule*> map_loaded_module_t;
- typedef std::map<std::string, CPlugin*> map_plugin_t;
-
- /**
- * Loaded plugins. A key is a plugin name.
- */
- map_loaded_module_t m_mapLoadedModules;
- /**
- * Registered plugins. A key is a plugin name.
- */
- map_plugin_t m_mapPlugins;
-
- public:
- /**
- * A constructor.
- * @param pPluginsConfDir A plugins configuration directory.
- * @param pPluginsLibDir A plugins library directory.
- */
- CPluginManager();
- /**
- * A destructor.
- */
- ~CPluginManager();
- /**
- * A method, which loads all plugins in plugins library direcotry.
- */
- void LoadPlugins();
- /**
- * A method, which unregister and unload all loaded plugins.
- */
- void UnLoadPlugins();
- /**
- * A method, which loads particular plugin.
- * @param pName A plugin name.
- */
- CPlugin* LoadPlugin(const char *pName, bool enabled_only = false);
- /**
- * A method, which unloads particular plugin.
- * @param pName A plugin name.
- */
- void UnLoadPlugin(const char *pName);
- /**
- * A method, which returns instance of particular action plugin.
- * @param pName A plugin name.
- * @return An action plugin.
- */
- CAction* GetAction(const char *pName, bool silent = false);
- /**
- * A method, which returns type of particular plugin.
- * @param pName A plugin name.
- * @return A plugin type.
- */
- plugin_type_t GetPluginType(const char *pName);
-};
-
-#endif /*PLUGINMANAGER_H_*/
diff -x '*.po' -d -urpN abrt.3/src/include/action.h abrt.4/src/include/action.h
--- abrt.3/src/include/action.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/include/action.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,44 +0,0 @@
-/*
- Action.h - header file for action plugin
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#ifndef ACTION_H_
-#define ACTION_H_
-
-#include "plugin.h"
-
-/**
- * An abstract class. The class defines an action plugin interface.
- */
-class CAction : public CPlugin
-{
- public:
- /**
- * A Method which performs particular action. As the first parameter it
- * takes an action directory. It could be either a directory of actual
- * crash or it could be a directory contains all crashes. It depends on
- * who call the plugin. The plugin can takes arguments, but the plugin
- * has to parse them by itself.
- * @param pActionDir An actual directory.
- * @param pArgs Plugin's arguments.
- */
- virtual void Run(const char *pActionDir, const char *pArgs, int force) = 0;
-};
-
-#endif
diff -x '*.po' -d -urpN abrt.3/src/include/analyzer.h abrt.4/src/include/analyzer.h
--- abrt.3/src/include/analyzer.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/include/analyzer.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,34 +0,0 @@
-/*
- Analyzer.h - header file for analyzer plugin
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#ifndef ANALYZER_H_
-#define ANALYZER_H_
-
-#include <string>
-#include "plugin.h"
-
-/**
- * An abstract class. The class defines an analyzer plugin interface.
- */
-class CAnalyzer : public CPlugin
-{
-};
-
-#endif /*ANALYZER_H_*/
diff -x '*.po' -d -urpN abrt.3/src/include/Makefile.am abrt.4/src/include/Makefile.am
--- abrt.3/src/include/Makefile.am 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/include/Makefile.am 2011-01-17 17:13:41.754308126 +0100
@@ -13,6 +13,4 @@ libabrt_include_HEADERS = \
dbus_common.h \
observer.h \
plugin.h \
- action.h \
- analyzer.h \
xfuncs.h
diff -x '*.po' -d -urpN abrt.3/src/include/plugin.h abrt.4/src/include/plugin.h
--- abrt.3/src/include/plugin.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/include/plugin.h 2011-01-17 17:23:38.054558760 +0100
@@ -25,90 +25,6 @@
#include "abrt_types.h"
#include "abrt_crash_data.h"
-#define PLUGINS_MAGIC_NUMBER 6
-
#define PLUGINS_CONF_EXTENSION "conf"
-#define PLUGINS_LIB_EXTENSION "so"
-#define PLUGINS_LIB_PREFIX "lib"
-
-/**
- * An abstract class. The class defines a common plugin interface. If a plugin
- * has some settings, then a *Settings(*) method has to be written.
- */
-class CPlugin
-{
- protected:
- map_plugin_settings_t m_pSettings;
-
- public:
- CPlugin();
- /**
- * A destructor.
- */
- virtual ~CPlugin();
- /**
- * A method, which initializes a plugin. It is not mandatory method.
- */
- virtual void Init();
- /**
- * A method, which deinitializes a plugin. It is not mandatory method.
- */
- virtual void DeInit();
- /**
- * A method, which takes a settings and apply them. It is not a mandatory method.
- * @param pSettings Plugin's settings
- */
- virtual void SetSettings(const map_plugin_settings_t& pSettings);
- /**
- * A method, which return current settings. It is not mandatory method.
- * @return Plugin's settings
- */
-///
-// virtual const map_plugin_settings_t& GetSettings();
-};
-
-/**
- * An enum of plugin types.
- */
-typedef enum {
- ANALYZER, /**< An analyzer plugin*/
- ACTION, /**< An action plugin*/
- REPORTER, /**< A reporter plugin*/
- DATABASE, /**< A database plugin*/
- MAX_PLUGIN_TYPE = DATABASE,
- INVALID_PLUGIN_TYPE
-} plugin_type_t;
-
-/**
- * A struct contains all needed data about particular plugin.
- */
-typedef struct SPluginInfo
-{
- const plugin_type_t m_Type; /**< Plugin type.*/
- const char *const m_sName; /**< Plugin name.*/
- const char *const m_sVersion; /**< Plugin version.*/
- const char *const m_sDescription; /**< Plugin description.*/
- const char *const m_sEmail; /**< Plugin author's email.*/
- const char *const m_sWWW; /**< Plugin's home page.*/
- const char *const m_sGTKBuilder; /**< Plugin's gui description.*/
- const int m_nMagicNumber; /**< Plugin magical number.*/
-} plugin_info_t;
-
-#define PLUGIN_INFO(type, plugin_class, name, version, description, email, www, gtk_builder)\
- extern "C" CPlugin* plugin_new()\
- {\
- return new plugin_class();\
- }\
- extern "C" const plugin_info_t plugin_info =\
- {\
- type,\
- name,\
- version,\
- description,\
- email,\
- www,\
- gtk_builder,\
- PLUGINS_MAGIC_NUMBER,\
- };
#endif
diff -x '*.po' -d -urpN abrt.3/src/lib/Makefile.am abrt.4/src/lib/Makefile.am
--- abrt.3/src/lib/Makefile.am 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/lib/Makefile.am 2011-01-17 17:14:50.028558324 +0100
@@ -78,8 +78,7 @@ libabrt_dbus_la_LIBADD = \
$(DBUS_LIBS)
libabrt_daemon_la_SOURCES = \
- CommLayerInner.cpp \
- Plugin.cpp
+ CommLayerInner.cpp
libabrt_daemon_la_CPPFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
@@ -93,8 +92,7 @@ libabrt_daemon_la_CPPFLAGS = \
-D_GNU_SOURCE
libabrt_daemon_la_LDFLAGS = \
-version-info 0:1:0
-libabrt_daemon_la_LIBADD = \
- -ldl
+libabrt_daemon_la_LIBADD =
libabrt_web_la_SOURCES = \
abrt_curl.h abrt_curl.c \
diff -x '*.po' -d -urpN abrt.3/src/lib/Plugin.cpp abrt.4/src/lib/Plugin.cpp
--- abrt.3/src/lib/Plugin.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/lib/Plugin.cpp 1970-01-01 01:00:00.000000000 +0100
@@ -1,41 +0,0 @@
-/*
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include "plugin.h"
-#include "abrtlib.h"
-
-CPlugin::CPlugin() {}
-
-/* class CPlugin's virtuals */
-CPlugin::~CPlugin() {}
-void CPlugin::Init() {}
-void CPlugin::DeInit() {}
-void CPlugin::SetSettings(const map_plugin_settings_t& pSettings)
-{
- m_pSettings = pSettings;
- VERB3
- {
- log("SetSettings:");
- map_plugin_settings_t::const_iterator it = m_pSettings.begin();
- while (it != m_pSettings.end())
- {
- log(" settings[%s]='%s'", it->first.c_str(), it->second.c_str());
- it++;
- }
- }
-}
diff -x '*.po' -d -urpN abrt.3/src/plugins/CCpp.cpp abrt.4/src/plugins/CCpp.cpp
--- abrt.3/src/plugins/CCpp.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/plugins/CCpp.cpp 1970-01-01 01:00:00.000000000 +0100
@@ -1,301 +0,0 @@
-/*
- CCpp.cpp
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <set>
-#include "abrtlib.h"
-#include "CCpp.h"
-#include "comm_layer_inner.h"
-
-using namespace std;
-
-#define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern"
-/*
- * %s - signal number
- * %c - ulimit -c value
- * %p - pid
- * %u - uid
- * %g - gid
- * %t - UNIX time of dump
- * %h - hostname
- * %e - executable filename
- * %% - output one "%"
- */
-#define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %s %c %p %u %g %t %h %e"
-
-#define CORE_PIPE_LIMIT_IFACE "/proc/sys/kernel/core_pipe_limit"
-/* core_pipe_limit specifies how many dump_helpers might run at the same time
- * 0 - means unlimited, but it's not guaranteed that /proc/<pid> of crashing
- * process will be available for dump_helper.
- * 4 - means that 4 dump_helpers can run at the same time (the rest will also
- * run, but they will fail to read /proc/<pid>).
- * This should be enough for ABRT, we can miss some crashes, but what are
- * the odds that more processes crash at the same time?
- * The value of 4 has been recommended by nhorman.
- */
-#define CORE_PIPE_LIMIT "4"
-
-#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di"
-
-CAnalyzerCCpp::CAnalyzerCCpp() :
- m_bBacktrace(true),
- m_bBacktraceRemotes(false),
- m_bMemoryMap(false),
- m_bInstallDebugInfo(true),
- m_nDebugInfoCacheMB(4000),
- m_nGdbTimeoutSec(60)
-{}
-
-/*
- this is just a workaround until kernel changes it's behavior
- when handling pipes in core_pattern
-*/
-#ifdef HOSTILE_KERNEL
-#define CORE_SIZE_PATTERN "Max core file size=1:unlimited"
-static int isdigit_str(char *str)
-{
- do {
- if (*str < '0' || *str > '9')
- return 0;
- } while (*++str);
- return 1;
-}
-
-static int set_limits()
-{
- DIR *dir = opendir("/proc");
- if (!dir) {
- /* this shouldn't fail, but to be safe.. */
- return 1;
- }
-
- struct dirent *ent;
- while ((ent = readdir(dir)) != NULL) {
- if (!isdigit_str(ent->d_name))
- continue;
-
- char limits_name[sizeof("/proc/%s/limits") + sizeof(long)*3];
- snprintf(limits_name, sizeof(limits_name), "/proc/%s/limits", ent->d_name);
- FILE *limits_fp = fopen(limits_name, "r");
- if (!limits_fp) {
- break;
- }
-
- char line[128];
- char *ulimit_c = NULL;
- while (1) {
- if (fgets(line, sizeof(line)-1, limits_fp) == NULL)
- break;
- if (strncmp(line, "Max core file size", sizeof("Max core file size")-1) == 0) {
- ulimit_c = skip_whitespace(line + sizeof("Max core file size")-1);
- skip_non_whitespace(ulimit_c)[0] = '\0';
- break;
- }
- }
- fclose(limits_fp);
- if (!ulimit_c || ulimit_c[0] != '0' || ulimit_c[1] != '\0') {
- /*process has nonzero ulimit -c, so need to modify it*/
- continue;
- }
- /* echo -n 'Max core file size=1:unlimited' >/proc/PID/limits */
- int fd = open(limits_name, O_WRONLY);
- if (fd >= 0) {
- errno = 0;
- /*full_*/
- ssize_t n = write(fd, CORE_SIZE_PATTERN, sizeof(CORE_SIZE_PATTERN)-1);
- if (n < sizeof(CORE_SIZE_PATTERN)-1)
- log("warning: can't write core_size limit to: %s", limits_name);
- close(fd);
- }
- else
- {
- log("warning: can't open %s for writing", limits_name);
- }
- }
- closedir(dir);
- return 0;
-}
-#endif /* HOSTILE_KERNEL */
-
-void CAnalyzerCCpp::Init()
-{
- FILE *fp = fopen(CORE_PATTERN_IFACE, "r");
- if (fp)
- {
- char line[PATH_MAX];
- if (fgets(line, sizeof(line), fp))
- m_sOldCorePattern = line;
- fclose(fp);
- }
- if (m_sOldCorePattern[0] == '|')
- {
- if (strncmp(m_sOldCorePattern.c_str(), CORE_PATTERN, strlen(CORE_PATTERN)) == 0)
- {
- log("warning: %s already contains %s, "
- "did abrt daemon crash recently?",
- CORE_PATTERN_IFACE, CORE_PATTERN);
- /* There is no point in "restoring" CORE_PATTERN_IFACE
- * to CORE_PATTERN on exit. Will restore to a default value:
- */
- m_sOldCorePattern = "core";
- } else {
- log("warning: %s was already set to run a crash analyser (%s), "
- "abrt may interfere with it",
- CORE_PATTERN_IFACE, CORE_PATTERN);
- }
- }
-#ifdef HOSTILE_KERNEL
- if (set_limits() != 0)
- log("warning: failed to set core_size limit, ABRT won't detect crashes in"
- "compiled apps");
-#endif
-
- fp = fopen(CORE_PATTERN_IFACE, "w");
- if (fp)
- {
- if (m_sOldCorePattern[0] != '|')
- {
- const char *old = m_sOldCorePattern.c_str();
- unsigned len = strchrnul(old, '\n') - old;
- char *hex_old = (char*)xmalloc(len * 2 + 1);
- bin2hex(hex_old, old, len)[0] = '\0';
- /* Trailing 00 is a sentinel. Decoder in the hook will check it.
- * If it won't see it, then kernel has truncated the argument:
- */
- char *pattern = xasprintf("%s %s00", CORE_PATTERN, hex_old);
- //log("old:'%s'->'%s'", old, hex_old);
- //log("pattern:'%s'", pattern);
-
- fputs(pattern, fp);
-
- free(pattern);
- free(hex_old);
- }
- else
- {
- fputs(CORE_PATTERN, fp);
- }
- fclose(fp);
- }
-
- /* read the core_pipe_limit and change it if it's == 0
- * otherwise the abrt-hook-ccpp won't be able to read /proc/<pid>
- * of the crashing process
- */
- fp = fopen(CORE_PIPE_LIMIT_IFACE, "r");
- if (fp)
- {
- /* we care only about the first char, if it's
- * not '0' then we don't have to change it,
- * because it means that it's already != 0
- */
- char pipe_limit[2];
- if (!fgets(pipe_limit, sizeof(pipe_limit), fp))
- pipe_limit[0] = '1'; /* not 0 */
- fclose(fp);
- if (pipe_limit[0] == '0')
- {
- fp = fopen(CORE_PIPE_LIMIT_IFACE, "w");
- if (fp)
- {
- fputs(CORE_PIPE_LIMIT, fp);
- fclose(fp);
- }
- else
- {
- log("warning: failed to set core_pipe_limit, ABRT won't detect"
- "crashes in compiled apps if kernel > 2.6.31");
- }
- }
- }
-}
-
-void CAnalyzerCCpp::DeInit()
-{
- /* no need to restore the core_pipe_limit, because it's only used
- when there is s pipe in core_pattern
- */
- FILE *fp = fopen(CORE_PATTERN_IFACE, "w");
- if (fp)
- {
- fputs(m_sOldCorePattern.c_str(), fp);
- fclose(fp);
- }
-}
-
-void CAnalyzerCCpp::SetSettings(const map_plugin_settings_t& pSettings)
-{
- m_pSettings = pSettings;
-
- map_plugin_settings_t::const_iterator end = pSettings.end();
- map_plugin_settings_t::const_iterator it;
- it = pSettings.find("Backtrace");
- if (it != end)
- {
- m_bBacktrace = string_to_bool(it->second.c_str());
- }
- it = pSettings.find("BacktraceRemotes");
- if (it != end)
- {
- m_bBacktraceRemotes = string_to_bool(it->second.c_str());
- }
- it = pSettings.find("MemoryMap");
- if (it != end)
- {
- m_bMemoryMap = string_to_bool(it->second.c_str());
- }
- it = pSettings.find("DebugInfo");
- if (it != end)
- {
- m_sDebugInfo = it->second;
- }
- it = pSettings.find("DebugInfoCacheMB");
- if (it != end)
- {
- m_nDebugInfoCacheMB = xatou(it->second.c_str());
- }
- it = pSettings.find("GdbTimeoutSec");
- if (it != end)
- {
- m_nGdbTimeoutSec = xatoi_positive(it->second.c_str());
- }
- it = pSettings.find("InstallDebugInfo");
- if (it == end) //compat, remove after 0.0.11
- it = pSettings.find("InstallDebuginfo");
- if (it != end)
- {
- m_bInstallDebugInfo = string_to_bool(it->second.c_str());
- }
- m_sDebugInfoDirs = DEBUGINFO_CACHE_DIR;
- it = pSettings.find("ReadonlyLocalDebugInfoDirs");
- if (it != end)
- {
- m_sDebugInfoDirs += ':';
- m_sDebugInfoDirs += it->second;
- }
-}
-
-PLUGIN_INFO(ANALYZER,
- CAnalyzerCCpp,
- "CCpp",
- "0.0.1",
- _("Analyzes crashes in C/C++ programs"),
- "zprikryl(a)redhat.com",
- "https://fedorahosted.org/abrt/wiki",
- "");
diff -x '*.po' -d -urpN abrt.3/src/plugins/CCpp.h abrt.4/src/plugins/CCpp.h
--- abrt.3/src/plugins/CCpp.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.4/src/plugins/CCpp.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,49 +0,0 @@
-/*
- CCpp.h - header file for C/C++ analyzer plugin
- - it can get UUID and memory maps from core files
-
- Copyright (C) 2009 Zdenek Prikryl (zprikryl(a)redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#ifndef CCPP_H_
-#define CCPP_H_
-
-#include <string>
-#include "plugin.h"
-#include "analyzer.h"
-
-class CAnalyzerCCpp : public CAnalyzer
-{
- private:
- bool m_bBacktrace;
- bool m_bBacktraceRemotes;
- bool m_bMemoryMap;
- bool m_bInstallDebugInfo;
- unsigned m_nDebugInfoCacheMB;
- unsigned m_nGdbTimeoutSec;
- std::string m_sOldCorePattern;
- std::string m_sDebugInfo;
- std::string m_sDebugInfoDirs;
-
- public:
- CAnalyzerCCpp();
- virtual void Init();
- virtual void DeInit();
- virtual void SetSettings(const map_plugin_settings_t& pSettings);
-};
-
-#endif /* CCPP */
diff -x '*.po' -d -urpN abrt.3/src/plugins/Makefile.am abrt.4/src/plugins/Makefile.am
--- abrt.3/src/plugins/Makefile.am 2011-01-17 16:44:02.656557812 +0100
+++ abrt.4/src/plugins/Makefile.am 2011-01-17 17:11:50.118308270 +0100
@@ -16,9 +16,6 @@ bin_PROGRAMS = \
abrt-action-mailx \
abrt-action-print
-pluginslib_LTLIBRARIES = \
- libCCpp.la
-
dist_pluginslib_DATA = \
Logger.glade \
Mailx.glade \
@@ -58,22 +55,6 @@ install-data-hook: $(DESTDIR)/$(DEBUG_IN
sed 's: = /var/: = $(localstatedir)/:g' -i \
$(DESTDIR)$(sysconfdir)/abrt/plugins/Logger.conf
-# CCpp
-libCCpp_la_SOURCES = \
- CCpp.cpp CCpp.h
-libCCpp_la_CPPFLAGS = \
- -I$(srcdir)/../include/report -I$(srcdir)/../include \
- -I$(srcdir)/../lib \
- -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- $(GLIB_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Werror
-# -DHOSTILE_KERNEL
-libCCpp_la_LDFLAGS = \
- -avoid-version
-
abrt_dump_oops_SOURCES = \
abrt-dump-oops.c
abrt_dump_oops_CPPFLAGS = \
13 years, 2 months
[PATCH] replace KerneloopsScanner plugin and dumpoops with abrt-dump-oops, use it in abrtd
by Denys Vlasenko
Patch adds new tool:
$ abrt-dump-oops
Usage: abrt-dump-oops [-vsrdow] FILE
Extract oops from syslog/dmesg file
-v, --verbose Be verbose
-s Log to syslog
-r Parse kernel's message buffer before parsing FILE
-d Create ABRT dump for every oops found
-o Print found oopses on standard output
-w Do not exit, watch the file for new oopses
It extends dumpoops. Extensions:
* it can watch the syslog using -w option (uses inotify)
* it can scan dmesg buffer too
In this way, it also becomes a replacement for KerneloopsScanner plugin:
oops-detecting logic is taken verbatim from KerneloopsScanner source.
abrtd is changed to start it if it sees this directive in abrt.conf:
KerneloopsScanner = /var/log/messages
Default abrt.conf is changed to have such line.
Patch doesn't remove KerneloopsScanner plugin and dumpoops binary yet,
I will do it in a separate trivial patch if/when this one is ACKed.
Run-tested.
Please review.
--
vda
diff -urpN abrt.0/abrt.spec abrt.2/abrt.spec
--- abrt.0/abrt.spec 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/abrt.spec 2011-01-13 23:13:00.321500055 +0100
@@ -428,6 +428,7 @@ fi
%{_mandir}/man7/abrt-KerneloopsScanner.7.gz
%{_libdir}/%{name}/KerneloopsReporter.glade
%{_mandir}/man7/abrt-KerneloopsReporter.7.gz
+%{_bindir}/abrt-dump-oops
%{_bindir}/abrt-action-analyze-oops
%{_bindir}/abrt-action-kerneloops
diff -urpN abrt.0/examples/cut_here.right abrt.2/examples/cut_here.right
--- abrt.0/examples/cut_here.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/cut_here.right 2011-01-14 12:55:13.464850802 +0100
@@ -1,4 +1,4 @@
-dumpoops: found oopses: 1
+abrt-dump-oops: Found oopses: 1
Version: 2.6.32-19.el6.x86_64
WARNING: at arch/x86/kernel/cpu/mtrr/generic.c:467
diff -urpN abrt.0/examples/not_oops1.right abrt.2/examples/not_oops1.right
--- abrt.0/examples/not_oops1.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/not_oops1.right 2011-01-14 12:55:06.904851036 +0100
@@ -1 +1 @@
-dumpoops: found oopses: 0
+abrt-dump-oops: Found oopses: 0
diff -urpN abrt.0/examples/not_oops2.right abrt.2/examples/not_oops2.right
--- abrt.0/examples/not_oops2.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/not_oops2.right 2011-01-14 12:55:03.512851273 +0100
@@ -1 +1 @@
-dumpoops: found oopses: 0
+abrt-dump-oops: Found oopses: 0
diff -urpN abrt.0/examples/not_oops3.right abrt.2/examples/not_oops3.right
--- abrt.0/examples/not_oops3.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/not_oops3.right 2011-01-14 12:55:10.231850838 +0100
@@ -1 +1 @@
-dumpoops: found oopses: 0
+abrt-dump-oops: Found oopses: 0
diff -urpN abrt.0/examples/oops1.right abrt.2/examples/oops1.right
--- abrt.0/examples/oops1.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/oops1.right 2011-01-14 12:54:59.818601165 +0100
@@ -1,4 +1,4 @@
-dumpoops: found oopses: 1
+abrt-dump-oops: Found oopses: 1
Version: 2.6.27.9-159.fc10.i686 #1
BUG: unable to handle kernel NULL pointer dereference at 00000000
diff -urpN abrt.0/examples/oops2.right abrt.2/examples/oops2.right
--- abrt.0/examples/oops2.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/oops2.right 2011-01-14 12:54:56.378601018 +0100
@@ -1,4 +1,4 @@
-dumpoops: found oopses: 1
+abrt-dump-oops: Found oopses: 1
Version: 2.6.33.1-19.fc13.x86_64
[ INFO: possible recursive locking detected ]
diff -urpN abrt.0/examples/oops3.right abrt.2/examples/oops3.right
--- abrt.0/examples/oops3.right 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/oops3.right 2011-01-14 12:54:52.779850810 +0100
@@ -1,4 +1,4 @@
-dumpoops: found oopses: 3
+abrt-dump-oops: Found oopses: 3
Version: 2.6.32-0.51.rc7.git2.fc13.x86_64
general protection fault: 0000 [#1] SMP
diff -urpN abrt.0/examples/test.sh abrt.2/examples/test.sh
--- abrt.0/examples/test.sh 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/examples/test.sh 2011-01-14 12:54:13.807601166 +0100
@@ -1,7 +1,7 @@
for f in *.test; do
- b="${f%%.test}"
- dumpoops -s "$f" >"$b".out 2>&1
- if diff -u "$b".right "$b".out >"$b".diff 2>&1; then
- rm "$b".out "$b".diff
- fi
+ b="${f%%.test}"
+ abrt-dump-oops -o "$f" >"$b".out 2>&1
+ if diff -u "$b".right "$b".out >"$b".diff 2>&1; then
+ rm "$b".out "$b".diff
+ fi
done
diff -urpN abrt.0/src/daemon/abrt.conf abrt.2/src/daemon/abrt.conf
--- abrt.0/src/daemon/abrt.conf 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/src/daemon/abrt.conf 2011-01-14 13:06:39.678723624 +0100
@@ -29,6 +29,8 @@ BlackListedPaths = /usr/share/doc/*, */e
#
MaxCrashReportsSize = 1000
+KerneloopsScanner = /var/log/messages
+
# Which Action plugins to run repeatedly
#
@@ -36,6 +38,4 @@ MaxCrashReportsSize = 1000
# h:m - at h:m
# s - every s seconds
-120 = KerneloopsScanner
-
#02:00 = FileTransfer
diff -urpN abrt.0/src/daemon/Daemon.cpp abrt.2/src/daemon/Daemon.cpp
--- abrt.0/src/daemon/Daemon.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/src/daemon/Daemon.cpp 2011-01-14 13:43:20.272732389 +0100
@@ -90,6 +90,7 @@ static volatile sig_atomic_t s_sig_caugh
static int s_signal_pipe[2];
static int s_signal_pipe_write = -1;
static int s_upload_watch = -1;
+static pid_t oops_scanner_pid = -1;
static unsigned s_timeout;
static bool s_exiting;
@@ -879,6 +880,23 @@ int main(int argc, char** argv)
/* Only now we want signal pipe to work */
s_signal_pipe_write = s_signal_pipe[1];
+ if (g_settings_sKerneloopsScanner)
+ {
+ const char *oops_scanner_argv[] = {
+ "abrt-dump-oops", "-drw",
+ g_settings_sKerneloopsScanner,
+ (logmode == LOGMODE_SYSLOG ? "-s" : NULL),
+ NULL
+ };
+ oops_scanner_pid = fork_execv_on_steroids(EXECFLG_INPUT_NUL,
+ (char**)oops_scanner_argv,
+ /*pipefds:*/ NULL,
+ /*unsetenv_vec:*/ NULL,
+ /*dir:*/ NULL,
+ /*uid:*/ 0);
+ VERB1 log("Started abrt-dump-oops, pid:%d", (int)oops_scanner_pid);
+ }
+
/* Enter the event loop */
log("Init complete, entering main loop");
run_main_loop(pMainloop);
@@ -916,9 +934,13 @@ int main(int argc, char** argv)
/* Exiting */
if (s_sig_caught && s_sig_caught != SIGALRM && s_sig_caught != SIGCHLD)
{
- error_msg_and_die("Got signal %d, exiting", s_sig_caught);
+ error_msg("Got signal %d, exiting", s_sig_caught);
+ if (oops_scanner_pid > 0)
+ kill(oops_scanner_pid, SIGTERM);
signal(s_sig_caught, SIG_DFL);
raise(s_sig_caught);
}
+ if (oops_scanner_pid > 0)
+ kill(oops_scanner_pid, SIGTERM);
error_msg_and_die("Exiting");
}
diff -urpN abrt.0/src/daemon/Settings.cpp abrt.2/src/daemon/Settings.cpp
--- abrt.0/src/daemon/Settings.cpp 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/src/daemon/Settings.cpp 2011-01-14 13:08:55.657723624 +0100
@@ -47,11 +47,12 @@ static map_string_t s_mapSectionCron;
/* one line: "OpenGPGCheck = value" */
bool g_settings_bOpenGPGCheck = false;
/* one line: "OpenGPGPublicKeys = value1,value2" */
-GList *g_settings_setOpenGPGPublicKeys = NULL;
-GList *g_settings_setBlackListedPkgs = NULL;
-GList *g_settings_setBlackListedPaths = NULL;
-char *g_settings_sWatchCrashdumpArchiveDir = NULL;
+GList * g_settings_setOpenGPGPublicKeys = NULL;
+GList * g_settings_setBlackListedPkgs = NULL;
+GList * g_settings_setBlackListedPaths = NULL;
+char * g_settings_sWatchCrashdumpArchiveDir = NULL;
unsigned int g_settings_nMaxCrashReportsSize = 1000;
+char * g_settings_sKerneloopsScanner = NULL;
bool g_settings_bProcessUnpackaged = false;
/* [ Cron ] */
@@ -209,6 +210,11 @@ static int ParseCommon()
{
g_settings_nMaxCrashReportsSize = xatoi_positive(it->second.c_str());
}
+ it = s_mapSectionCommon.find("KerneloopsScanner");
+ if (it != end)
+ {
+ g_settings_sKerneloopsScanner = xstrdup(it->second.c_str());
+ }
it = s_mapSectionCommon.find("ProcessUnpackaged");
if (it != end)
{
diff -urpN abrt.0/src/daemon/Settings.h abrt.2/src/daemon/Settings.h
--- abrt.0/src/daemon/Settings.h 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/src/daemon/Settings.h 2011-01-14 13:06:17.422473647 +0100
@@ -31,7 +31,8 @@ extern GList *g_settings_setBlackListedP
extern unsigned int g_settings_nMaxCrashReportsSize;
extern bool g_settings_bOpenGPGCheck;
extern bool g_settings_bProcessUnpackaged;
-extern char *g_settings_sWatchCrashdumpArchiveDir;
+extern char * g_settings_sKerneloopsScanner;
+extern char * g_settings_sWatchCrashdumpArchiveDir;
extern map_cron_t g_settings_mapCron;
int LoadSettings();
diff -urpN abrt.0/src/plugins/abrt-dump-oops.c abrt.2/src/plugins/abrt-dump-oops.c
--- abrt.0/src/plugins/abrt-dump-oops.c 1970-01-01 01:00:00.000000000 +0100
+++ abrt.2/src/plugins/abrt-dump-oops.c 2011-01-14 14:00:02.775847894 +0100
@@ -0,0 +1,709 @@
+/*
+ Copyright (C) 2011 ABRT team
+ Copyright (C) 2011 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Authors:
+ Anton Arapov <anton(a)redhat.com>
+ Arjan van de Ven <arjan(a)linux.intel.com>
+ */
+#include <syslog.h>
+#include <asm/unistd.h> /* __NR_syslog */
+#include <sys/inotify.h>
+#include <sys/ioctl.h> /* ioctl(FIONREAD) */
+#include "abrtlib.h"
+#include "parse_options.h"
+
+#define PROGNAME "abrt-dump-oops"
+
+static void queue_oops(GList **vec, const char *data, const char *version)
+{
+ char *ver_data = xasprintf("%s\n%s", version, data);
+ *vec = g_list_append(*vec, ver_data);
+}
+
+/*
+ * extract_version tries to find the kernel version in given data
+ */
+static char *extract_version(const char *linepointer)
+{
+ if (strstr(linepointer, "Pid")
+ || strstr(linepointer, "comm")
+ || strstr(linepointer, "CPU")
+ || strstr(linepointer, "REGS")
+ || strstr(linepointer, "EFLAGS")
+ ) {
+ char* start;
+ char* end;
+
+ start = strstr((char*)linepointer, "2.6.");
+ if (start)
+ {
+ end = strchr(start, ')');
+ if (!end)
+ end = strchrnul(start, ' ');
+ return xstrndup(start, end-start);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * extract_oops tries to find oops signatures in a log
+ */
+struct line_info {
+ char *ptr;
+ char level;
+};
+
+static int record_oops(GList **oopses, struct line_info* lines_info, int oopsstart, int oopsend)
+{
+ int q;
+ int len;
+ char *oops;
+ char *version;
+
+ len = 2;
+ for (q = oopsstart; q <= oopsend; q++)
+ len += strlen(lines_info[q].ptr) + 1;
+
+ oops = (char*)xzalloc(len);
+
+ version = NULL;
+ for (q = oopsstart; q <= oopsend; q++)
+ {
+ if (!version)
+ version = extract_version(lines_info[q].ptr);
+
+ if (lines_info[q].ptr[0])
+ {
+ strcat(oops, lines_info[q].ptr);
+ strcat(oops, "\n");
+ }
+ }
+ int rv = 1;
+ /* too short oopses are invalid */
+ if (strlen(oops) > 100)
+ queue_oops(oopses, oops, version ? version : "undefined");
+ else
+ {
+ VERB3 log("Dropped oops: too short");
+ rv = 0;
+ }
+ free(oops);
+ free(version);
+ return rv;
+}
+
+#define REALLOC_CHUNK 1000
+static int extract_oopses(GList **oopses, char *buffer, size_t buflen)
+{
+ char *c;
+ int linecount = 0;
+ int lines_info_alloc = 0;
+ struct line_info *lines_info = NULL;
+
+ /* Split buffer into lines */
+
+ if (buflen != 0)
+ buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */
+ c = buffer;
+ while (c < buffer + buflen)
+ {
+ char linelevel;
+ char *c9;
+ char *colon;
+
+ c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */
+ assert(c9);
+ *c9 = '\0'; /* turn the \n into a string termination */
+ if (c9 == c)
+ goto next_line;
+
+ /* Is it a syslog file (/var/log/messages or similar)?
+ * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx",
+ * some users run syslog in non-C locale:
+ * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah"
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!!
+ * We detect it by checking for N:NN:NN pattern in first 15 chars
+ * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled")
+ */
+ colon = strchr(c, ':');
+ if (colon && colon > c && colon < c + 15
+ && isdigit(colon[-1]) /* N:... */
+ && isdigit(colon[1]) /* ...N:NN:... */
+ && isdigit(colon[2])
+ && colon[3] == ':'
+ && isdigit(colon[4]) /* ...N:NN:NN... */
+ && isdigit(colon[5])
+ ) {
+ /* It's syslog file, not a bare dmesg */
+
+ /* Skip non-kernel lines */
+ char *kernel_str = strstr(c, "kernel: ");
+ if (kernel_str == NULL)
+ {
+ /* if we see our own marker:
+ * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt"
+ * we know we submitted everything upto here already */
+ if (strstr(c, "abrt:") && strstr(c, "Abrt"))
+ {
+ VERB3 log("Found our marker at line %d, restarting line count from 0", linecount);
+ linecount = 0;
+ lines_info_alloc = 0;
+ free(lines_info);
+ lines_info = NULL;
+ }
+ goto next_line;
+ }
+ c = kernel_str + sizeof("kernel: ")-1;
+ }
+
+ linelevel = 0;
+ /* store and remove kernel log level */
+ if (*c == '<' && c[1] && c[2] == '>')
+ {
+ linelevel = c[1];
+ c += 3;
+ }
+ /* remove jiffies time stamp counter if present */
+ if (*c == '[')
+ {
+ char *c2 = strchr(c, '.');
+ char *c3 = strchr(c, ']');
+ if (c2 && c3 && (c2 < c3) && (c3-c) < 14 && (c2-c) < 8)
+ {
+ c = c3 + 1;
+ if (*c == ' ')
+ c++;
+ }
+ }
+ if (linecount >= lines_info_alloc)
+ {
+ lines_info_alloc += REALLOC_CHUNK;
+ lines_info = (struct line_info*)xrealloc(lines_info,
+ lines_info_alloc * sizeof(lines_info[0]));
+ }
+ lines_info[linecount].ptr = c;
+ lines_info[linecount].level = linelevel;
+ linecount++;
+next_line:
+ c = c9 + 1;
+ }
+
+ /* Analyze lines */
+
+ int i;
+ char prevlevel = 0;
+ int oopsstart = -1;
+ int inbacktrace = 0;
+ int oopsesfound = 0;
+
+ i = 0;
+ while (i < linecount)
+ {
+ char *curline = lines_info[i].ptr;
+
+ if (curline == NULL)
+ {
+ i++;
+ continue;
+ }
+ while (*curline == ' ')
+ curline++;
+
+ if (oopsstart < 0)
+ {
+ /* Find start-of-oops markers */
+ /* In some comparisons, we skip 1st letter, to avoid dealing with
+ * changes in capitalization in kernel. For example, I see that
+ * current kernel git (at 2011-01-01) has both "kernel BUG at ..."
+ * and "Kernel BUG at ..." messages, and I don't want to change
+ * the code below whenever kernel is changed to use "K" (or "k")
+ * uniformly.
+ */
+ if (strstr(curline, /*g*/ "eneral protection fault:"))
+ oopsstart = i;
+ else if (strstr(curline, "BUG:"))
+ oopsstart = i;
+ else if (strstr(curline, /*k*/ "ernel BUG at"))
+ oopsstart = i;
+ else if (strstr(curline, "do_IRQ: stack overflow:"))
+ oopsstart = i;
+ else if (strstr(curline, "RTNL: assertion failed"))
+ oopsstart = i;
+ else if (strstr(curline, /*e*/ "eek! page_mapcount(page) went negative!"))
+ oopsstart = i;
+ else if (strstr(curline, /*n*/ "ear stack overflow (cur:"))
+ oopsstart = i;
+ else if (strstr(curline, /*d*/ "ouble fault:"))
+ oopsstart = i;
+ else if (strstr(curline, /*b*/ "adness at"))
+ oopsstart = i;
+ else if (strstr(curline, "NETDEV WATCHDOG"))
+ oopsstart = i;
+ else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated message */
+ oopsstart = i;
+ else if (strstr(curline, /*u*/ "nable to handle kernel"))
+ oopsstart = i;
+ else if (strstr(curline, /*s*/ "ysctl table check failed"))
+ oopsstart = i;
+ else if (strstr(curline, "INFO: possible recursive locking detected"))
+ oopsstart = i;
+ // Not needed: "--[ cut here ]--" is always followed
+ // by "Badness at", "kernel BUG at", or "WARNING: at" string
+ //else if (strstr(curline, "------------[ cut here ]------------"))
+ // oopsstart = i;
+ else if (strstr(curline, "list_del corruption"))
+ oopsstart = i;
+ else if (strstr(curline, "list_add corruption"))
+ oopsstart = i;
+
+ if (i >= 3 && strstr(curline, "Oops:"))
+ oopsstart = i-3;
+
+ if (oopsstart >= 0)
+ {
+ /* debug information */
+ VERB3 {
+ log("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr);
+ if (oopsstart != i)
+ log("Trigger line is %d: '%s'", i, c);
+ }
+ /* try to find the end marker */
+ int i2 = i + 1;
+ while (i2 < linecount && i2 < (i+50))
+ {
+ if (strstr(lines_info[i2].ptr, "---[ end trace"))
+ {
+ inbacktrace = 1;
+ i = i2;
+ break;
+ }
+ i2++;
+ }
+ }
+ }
+
+ /* Are we entering a call trace part? */
+ /* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */
+ if (oopsstart >= 0 && !inbacktrace)
+ {
+ if (strstr(curline, "Call Trace:"))
+ inbacktrace = 1;
+ else
+ if (strnlen(curline, 9) > 8
+ && curline[0] == '[' && curline[1] == '<'
+ && strstr(curline, ">]")
+ && strstr(curline, "+0x")
+ && strstr(curline, "/0x")
+ ) {
+ inbacktrace = 1;
+ }
+ }
+
+ /* Are we at the end of an oops? */
+ else if (oopsstart >= 0 && inbacktrace)
+ {
+ int oopsend = INT_MAX;
+
+ /* line needs to start with " [" or have "] [" if it is still a call trace */
+ /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */
+ if (curline[0] != '['
+ && !strstr(curline, "] [")
+ && !strstr(curline, "--- Exception")
+ && !strstr(curline, "LR =")
+ && !strstr(curline, "<#DF>")
+ && !strstr(curline, "<IRQ>")
+ && !strstr(curline, "<EOI>")
+ && !strstr(curline, "<<EOE>>")
+ && strncmp(curline, "Code: ", 6) != 0
+ && strncmp(curline, "RIP ", 4) != 0
+ && strncmp(curline, "RSP ", 4) != 0
+ ) {
+ oopsend = i-1; /* not a call trace line */
+ }
+ /* oops lines are always more than 8 chars long */
+ else if (strnlen(curline, 8) < 8)
+ oopsend = i-1;
+ /* single oopses are of the same loglevel */
+ else if (lines_info[i].level != prevlevel)
+ oopsend = i-1;
+ else if (strstr(curline, "Instruction dump:"))
+ oopsend = i;
+ /* if a new oops starts, this one has ended */
+ else if (strstr(curline, "WARNING: at ") && oopsstart != i) /* WARN_ON() generated message */
+ oopsend = i-1;
+ else if (strstr(curline, "Unable to handle") && oopsstart != i)
+ oopsend = i-1;
+ /* kernel end-of-oops marker (not including marker itself) */
+ else if (strstr(curline, "---[ end trace"))
+ oopsend = i-1;
+
+ if (oopsend <= i)
+ {
+ VERB3 log("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr);
+ if (record_oops(oopses, lines_info, oopsstart, oopsend))
+ oopsesfound++;
+ oopsstart = -1;
+ inbacktrace = 0;
+ }
+ }
+
+ prevlevel = lines_info[i].level;
+ i++;
+
+ if (oopsstart >= 0)
+ {
+ /* Do we have a suspiciously long oops? Cancel it */
+ if (i-oopsstart > 60)
+ {
+ inbacktrace = 0;
+ oopsstart = -1;
+ VERB3 log("Dropped oops, too long");
+ continue;
+ }
+ if (!inbacktrace && i-oopsstart > 40)
+ {
+ /*inbacktrace = 0; - already is */
+ oopsstart = -1;
+ VERB3 log("Dropped oops, too long");
+ continue;
+ }
+ }
+ } /* while (i < linecount) */
+
+ /* process last oops if we have one */
+ if (oopsstart >= 0 && inbacktrace)
+ {
+ int oopsend = i-1;
+ VERB3 log("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr);
+ if (record_oops(oopses, lines_info, oopsstart, oopsend))
+ oopsesfound++;
+ }
+
+ free(lines_info);
+ return oopsesfound;
+}
+
+#define MAX_SCAN_BLOCK (4*1024*1024)
+#define READ_AHEAD (10*1024)
+
+static void scan_dmesg(GList **oops_list)
+{
+ VERB1 log("Scanning dmesg");
+
+ /* syslog(3) - read the last len bytes from the log buffer
+ * (non-destructively), but dont read more than was written
+ * into the buffer since the last "clear ring buffer" cmd.
+ * Returns the number of bytes read.
+ */
+ char *buffer = xzalloc(16*1024);
+ syscall(__NR_syslog, 3, buffer, 16*1024 - 1); /* always NUL terminated */
+ extract_oopses(oops_list, buffer, strlen(buffer));
+ free(buffer);
+}
+
+static int scan_syslog_file(GList **oops_list, int fd, struct stat *statbuf, int partial_line_len)
+{
+ /* fstat(fd, &statbuf) was just done by caller */
+
+ off_t cur_pos = lseek(fd, 0, SEEK_CUR);
+ if (statbuf->st_size <= cur_pos)
+ return partial_line_len; /* we are at EOF, nothing to do */
+
+ VERB3 log("File grew by %lu bytes to %lu",
+ (long)(statbuf->st_size - cur_pos), (long)(statbuf->st_size));
+
+ /* Do not try to allocate an absurd amount of memory. */
+ int sz = MAX_SCAN_BLOCK - READ_AHEAD;
+ if (sz > statbuf->st_size - cur_pos)
+ sz = statbuf->st_size - cur_pos;
+
+ /* Rewind to the beginning of the current line */
+ if (partial_line_len > 0 && lseek(fd, -partial_line_len, SEEK_CUR) != (off_t)-1)
+ {
+ VERB3 log("Went back %u bytes", partial_line_len);
+ cur_pos -= partial_line_len;
+ sz += partial_line_len;
+ }
+
+ /*
+ * In theory we have a race here, since someone can spew
+ * to /var/log/messages before we read it in...
+ * We try to deal with it by reading READ_AHEAD extra.
+ */
+ sz += READ_AHEAD;
+ char *buffer = xzalloc(sz);
+
+ partial_line_len = 0;
+ do {
+ int r = full_read(fd, buffer, sz-1);
+ if (r <= 0)
+ break;
+ VERB3 log("Read %u bytes", r);
+
+ /* For future scans, try to find where last (incomplete) line starts */
+ partial_line_len = 0;
+ char *last_newline = memrchr(buffer, '\n', r) ? : buffer-1;
+ partial_line_len = buffer+r - (last_newline+1);
+ if (partial_line_len > 500) /* cap it */
+ partial_line_len = 500;
+
+ extract_oopses(oops_list, buffer, r);
+ cur_pos += r;
+ } while (cur_pos < statbuf->st_size);
+
+ free(buffer);
+
+ return partial_line_len;
+}
+
+/* returns number of errors */
+static int save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
+{
+ unsigned countdown = 16; /* do not report hundreds of oopses */
+ unsigned idx = oops_cnt;
+ time_t t = time(NULL);
+ pid_t my_pid = getpid();
+
+ VERB1 log("Saving %u oopses as crash dump dirs", idx >= countdown ? countdown-1 : idx);
+
+ char *tainted_str = NULL;
+ /* once tainted flag is set to 1, only restart can reset the flag to 0 */
+ FILE *tainted_fp = fopen("/proc/sys/kernel/tainted", "r");
+ if (tainted_fp)
+ {
+ tainted_str = xmalloc_fgetline(tainted_fp);
+ fclose(tainted_fp);
+ }
+ else
+ error_msg("/proc/sys/kernel/tainted does not exist");
+
+ int errors = 0;
+
+ while (idx != 0 && --countdown != 0)
+ {
+ char path[sizeof(DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu") + 3 * sizeof(long)*3];
+ sprintf(path, DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu", (long)t, (long)my_pid, (long)idx);
+
+ char *first_line = (char*)g_list_nth_data(oops_list, --idx);
+ char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
+ *second_line++ = '\0';
+
+ struct dump_dir *dd = dd_create(path, /*uid:*/ 0);
+ if (dd)
+ {
+ dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
+ dd_save_text(dd, FILENAME_EXECUTABLE, "kernel");
+ dd_save_text(dd, FILENAME_KERNEL, first_line);
+ dd_save_text(dd, FILENAME_CMDLINE, "not_applicable");
+ dd_save_text(dd, FILENAME_BACKTRACE, second_line);
+ /* Optional, makes generated bz more informative */
+ strchrnul(second_line, '\n')[0] = '\0';
+ dd_save_text(dd, FILENAME_REASON, second_line);
+
+ if (tainted_str && tainted_str[0] != '0')
+ dd_save_text(dd, FILENAME_TAINTED, tainted_str);
+
+ free(tainted_str);
+ dd_close(dd);
+ }
+ else
+ errors++;
+ }
+
+ return errors;
+}
+
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
+ const char *filename = "/var/log/messages";
+
+ const char *program_usage = _(
+ PROGNAME" [-vsrdow] FILE\n"
+ "\n"
+ "Extract oops from syslog/dmesg file"
+ );
+ enum {
+ OPT_v = 1 << 0,
+ OPT_s = 1 << 1,
+ OPT_r = 1 << 2,
+ OPT_d = 1 << 3,
+ OPT_o = 1 << 4,
+ OPT_w = 1 << 5,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_BOOL('s', NULL, NULL, _("Log to syslog")),
+ OPT_BOOL('r', NULL, NULL, _("Parse kernel's message buffer before parsing FILE")),
+ OPT_BOOL('d', NULL, NULL, _("Create ABRT dump for every oops found")),
+ OPT_BOOL('o', NULL, NULL, _("Print found oopses on standard output")),
+ OPT_BOOL('w', NULL, NULL, _("Do not exit, watch the file for new oopses")),
+ OPT_END()
+ };
+
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage);
+ argv += optind;
+ if (!argv[0])
+ show_usage_and_die(program_usage, program_options);
+ filename = argv[0];
+
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+ msg_prefix = PROGNAME;
+ if (opts & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ int inotify_fd = -1;
+ if (opts & OPT_w)
+ {
+ inotify_fd = inotify_init();
+ if (inotify_fd == -1)
+ perror_msg_and_die("inotify_init failed");
+ //close_on_exec_on(inotify_fd);
+ }
+
+ GList *oops_list = NULL;
+ if (opts & OPT_r)
+ /* Scan dmesg (only once even with -w) */
+ scan_dmesg(&oops_list);
+
+ int partial_line_len = 0;
+ struct stat statbuf;
+ int file_fd = -1;
+ int wd = -1;
+
+ while (1) /* loops only if -w */
+ {
+ /* If file is already opened, parse oopses from current pos */
+ if (file_fd >= 0)
+ {
+ memset(&statbuf, 0, sizeof(statbuf));
+ fstat(file_fd, &statbuf);
+ partial_line_len = scan_syslog_file(&oops_list, file_fd, &statbuf, partial_line_len);
+
+ /* Was file deleted or replaced? */
+ ino_t fd_ino = statbuf.st_ino;
+ if (stat(filename, &statbuf) != 0 || statbuf.st_ino != fd_ino) /* yes */
+ {
+ VERB2 log("Can't stat '%s', closing fd", filename);
+ close(file_fd);
+ if (wd >= 0)
+ inotify_rm_watch(inotify_fd, wd);
+ file_fd = -1;
+ wd = -1;
+ partial_line_len = 0;
+ }
+ }
+
+ /* If file isn't opened, try to open it and parse oopses */
+ if (file_fd < 0)
+ {
+ file_fd = open(filename, O_RDONLY);
+ if (file_fd < 0)
+ {
+ if (!(opts & OPT_w))
+ perror_msg_and_die("Can't open '%s'", filename);
+ /* with -w, we ignore open errors */
+ }
+ else
+ {
+ VERB2 log("Opened '%s'", filename);
+ /* For -w case, if we don't have inotify watch yet, open one */
+ if ((opts & OPT_w) && wd < 0)
+ {
+ wd = inotify_add_watch(inotify_fd, filename, IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF);
+ if (wd < 0)
+ perror_msg("inotify_add_watch failed on '%s'", filename);
+ else
+ VERB2 log("Added inotify watch for '%s'", filename);
+ }
+ if (fstat(file_fd, &statbuf) == 0)
+ {
+ /* If file is large, skip the beginning.
+ * IOW: ignore old log messages because they are unlikely
+ * to have sufficiently recent data to be useful.
+ */
+ if (statbuf.st_size > (MAX_SCAN_BLOCK - READ_AHEAD))
+ lseek(file_fd, statbuf.st_size - (MAX_SCAN_BLOCK - READ_AHEAD), SEEK_SET);
+ /* Note that statbuf is filled by fstat by now,
+ * scan_syslog_file needs that
+ */
+ partial_line_len = scan_syslog_file(&oops_list, file_fd, &statbuf, partial_line_len);
+ }
+ }
+ }
+
+ /* Print and/or save oopses */
+ int oops_cnt = g_list_length(oops_list);
+ if (!(opts & OPT_w) || oops_cnt != 0 || g_verbose)
+ log("Found oopses: %d", oops_cnt);
+ if (oops_cnt != 0)
+ {
+ if (opts & OPT_o)
+ {
+ int i = 0;
+ while (i < oops_cnt)
+ printf("\nVersion: %s", (char*)g_list_nth_data(oops_list, i++));
+ }
+ if (opts & OPT_d)
+ {
+ log("Creating dump directories");
+ int errors = save_oops_to_dump_dir(oops_list, oops_cnt);
+ if (errors > 0)
+ log("%d errors while dumping oopses", errors);
+ }
+ }
+ for (GList *li = oops_list; li; li = g_list_next(li))
+ free((char*)li->data);
+ g_list_free(oops_list);
+ oops_list = NULL;
+
+ /* Done if no -w */
+ if (!(opts & OPT_w))
+ break;
+
+ /* Even if log file grows all the time, say, a new line every 5 ms,
+ * we don't want to scan it all the time. Sleep a bit and let it grow
+ * in bigger increments.
+ * Sleep longer if file does not exist.
+ */
+ sleep(file_fd >= 0 ? 1 : 59);
+
+ /* Now wait for it to change, be moved or deleted */
+ if (wd >= 0)
+ {
+ char buf[4096];
+ VERB3 log("Waiting for '%s' to change", filename);
+ /* We block here: */
+ int len = read(inotify_fd, buf, sizeof(buf));
+ if (len < 0)
+ perror_msg("Error reading inotify fd");
+ /* we don't actually check what happened to file -
+ * the code will handle all possibilities.
+ */
+ VERB3 log("Change in '%s' detected", filename);
+ }
+
+ } /* while (1) */
+
+ return 0;
+}
diff -urpN abrt.0/src/plugins/Makefile.am abrt.2/src/plugins/Makefile.am
--- abrt.0/src/plugins/Makefile.am 2011-01-13 17:59:21.000000000 +0100
+++ abrt.2/src/plugins/Makefile.am 2011-01-13 23:00:28.024773812 +0100
@@ -4,6 +4,7 @@ bin_SCRIPTS = \
abrt-action-install-debuginfo.py
bin_PROGRAMS = \
+ abrt-dump-oops \
abrt-action-analyze-c \
abrt-action-analyze-python \
abrt-action-analyze-oops \
@@ -90,6 +91,25 @@ libKerneloopsScanner_la_LDFLAGS = \
-avoid-version \
$(GLIB_LIBS)
+abrt_dump_oops_SOURCES = \
+ abrt-dump-oops.c
+abrt_dump_oops_CPPFLAGS = \
+ -I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_dump_oops_LDADD = \
+ ../lib/libreport.la
+
abrt_action_analyze_c_SOURCES = \
abrt-action-analyze-c.c
abrt_action_analyze_c_CPPFLAGS = \
13 years, 2 months
ABRT 2.0 feature: log file scanning
by Denys Vlasenko
On Fri, 2011-01-07 at 15:29 +0100, Jiri Moskovcak wrote:
> = ABRT 2.0 Features (what we need) =
> == need to be done features ==
> plugins free daemon
> -> add a generic log scanner
I would like to work on this one. Here's my
"How to implement log scanning?" brainstorm.
Proposal (1): daemon watches log files, whenever one of them changes,
it runs a program which parses the log file. It can give the offset
in the log from where parsing should start.
Table of files to watch and helpers to run should be somewhere in config
file:
# Specialized log watcher programs
/var/log/messages abrt-scan-oops -f $FNAME -o $OFF
/var/log/Xorg.0.log abrt-scan-xserver -f $FNAME -o $OFF
# generic log watcher program
/some/other.log abrt-scan-log -f $FNAME -o $OFF -start-regex='ALERT' -end-regex='END' -maxlines=50
...
I see one problem with this setup.
We need to consider a case when watched logfile gets flooded
(growing continuously and quickly). This means daemon
will be starting the parser all the time, and will have
hard time determining where exactly parser stopped parsing
last time: say, /var/log/messages was 100M long. We started parser.
Parser finished. We look at /var/log/messages and it's 110M long now.
How can we be sure that parser read until the very end of 110th meg,
that it did not hit EOF at, say, 109M? IOW: where to restart
next parsing?
Seems like this problem can be solved if we keep an open fd
to the log file in question, and use that fd to read the file.
This way, we always know where we stopped.
Smaller problems of proposal (1) are increasing complexity
in the daemon - it needs to have many (and of additional kind)
inotify watches, needs to suspend watching while parser child
is running, and may need some mechanism for adding/deleting
new log files to watch.
This leads me to proposal (2): every log file is watched by
a separate "log watching daemon". Basically, we just start:
# Specialized log watcher programs
abrt-scan-oops -f /var/log/messages &
abrt-scan-xserver -f /var/log/Xorg.0.log &
# generic log watcher program
abrt-scan-log -f /some/other.log -start-regex='ALERT' -end-regex='END' -maxlines=50 &
...
in background, and every one of these watches and processes
one log file.
Which proposal do you like more? Do you have other ideas
or see other problems to watch for?
--
vda
13 years, 2 months