summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--abrt.spec1
-rw-r--r--inc/CrashTypes.h3
-rw-r--r--src/Daemon/Daemon.cpp90
-rw-r--r--src/Daemon/Makefile.am4
-rw-r--r--src/Daemon/Settings.cpp6
-rw-r--r--src/Daemon/Settings.h1
-rw-r--r--src/Daemon/abrt-handle-upload71
-rw-r--r--src/Daemon/abrt.conf5
8 files changed, 155 insertions, 26 deletions
diff --git a/abrt.spec b/abrt.spec
index 6f9e4847..5b3a74f6 100644
--- a/abrt.spec
+++ b/abrt.spec
@@ -315,6 +315,7 @@ fi
%doc README COPYING
%{_sbindir}/%{name}d
%{_bindir}/%{name}-debuginfo-install
+%{_bindir}/%{name}-handle-upload
%{_bindir}/%{name}-backtrace
%config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf
%config(noreplace) %{_sysconfdir}/%{name}/gpg_keys
diff --git a/inc/CrashTypes.h b/inc/CrashTypes.h
index 8b9fda93..25dbcd46 100644
--- a/inc/CrashTypes.h
+++ b/inc/CrashTypes.h
@@ -49,6 +49,9 @@
#define FILENAME_REPRODUCE "reproduce"
#define FILENAME_RATING "rating"
#define FILENAME_HOSTNAME "hostname"
+// Optional. Set to "1" by abrt-handle-upload for every unpacked crashdump
+#define FILENAME_REMOTE "remote"
+// TODO: TicketUploader also has open-coded "TICKET", "CUSTOMER" files
// Apart from CD_UID, which is also stored as a file in dump directory,
// these items only exist in db. (CD_UID is also a file because
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
index 331de4cf..e9db034d 100644
--- a/src/Daemon/Daemon.cpp
+++ b/src/Daemon/Daemon.cpp
@@ -21,6 +21,7 @@
#include <resolv.h> /* res_init */
#include <string>
#include <sys/inotify.h>
+#include <sys/ioctl.h> /* ioctl(FIONREAD) */
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>
#include <glib.h>
@@ -111,6 +112,7 @@ typedef struct cron_callback_data_t
static volatile sig_atomic_t s_sig_caught;
static int s_signal_pipe[2];
static int s_signal_pipe_write = -1;
+static int s_upload_watch = -1;
static unsigned s_timeout;
static bool s_exiting;
@@ -430,41 +432,76 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint
/* Inotify handler */
static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
{
- /* 128 simultaneous actions */
-//TODO: use ioctl(FIONREAD) to determine how much to read
-#define INOTIFY_BUFF_SIZE ((sizeof(struct inotify_event) + FILENAME_MAX)*128)
- char *buf = (char*)xmalloc(INOTIFY_BUFF_SIZE);
- gsize len;
- gsize i = 0;
+ /* Default size: 128 simultaneous actions (about 1/2 meg) */
+#define INOTIFY_BUF_SIZE ((sizeof(struct inotify_event) + FILENAME_MAX)*128)
+ /* Determine how much to read (it usually is much smaller) */
+ /* NB: this variable _must_ be int-sized, ioctl expects that! */
+ int inotify_bytes = INOTIFY_BUF_SIZE;
+ if (ioctl(g_io_channel_unix_get_fd(gio), FIONREAD, &inotify_bytes) != 0
+ || inotify_bytes < sizeof(struct inotify_event)
+ || inotify_bytes > INOTIFY_BUF_SIZE
+ ) {
+ inotify_bytes = INOTIFY_BUF_SIZE;
+ }
+ VERB3 log("FIONREAD:%d", inotify_bytes);
+
+ char *buf = (char*)xmalloc(inotify_bytes);
errno = 0;
- GIOError err = g_io_channel_read(gio, buf, INOTIFY_BUFF_SIZE, &len);
+ gsize len;
+ GIOError err = g_io_channel_read(gio, buf, inotify_bytes, &len);
if (err != G_IO_ERROR_NONE)
{
perror_msg("Error reading inotify fd");
free(buf);
return FALSE;
}
- /* reconstruct each event and send message to the dbus */
+
+ /* Reconstruct each event and send message to the dbus */
+ gsize i = 0;
while (i < len)
{
+ struct inotify_event *event = (struct inotify_event *) &buf[i];
const char *name = NULL;
- struct inotify_event *event;
-
- event = (struct inotify_event *) &buf[i];
if (event->len)
- name = &buf[i] + sizeof (*event);
- i += sizeof (*event) + event->len;
+ name = event->name;
+ //log("i:%d len:%d event->mask:%x IN_ISDIR:%x IN_CLOSE_WRITE:%x event->len:%d",
+ // i, len, event->mask, IN_ISDIR, IN_CLOSE_WRITE, event->len);
+ i += sizeof(*event) + event->len;
+
+ if (event->wd == s_upload_watch)
+ {
+ /* Was the (presumable newly created) file closed in upload dir,
+ * or a file moved to upload dir? */
+ if (!(event->mask & IN_ISDIR)
+ && event->mask & (IN_CLOSE_WRITE|IN_MOVED_TO)
+ && name
+ ) {
+ const char *ext = strrchr(name, '.');
+ if (ext && strcmp(ext + 1, "working") == 0)
+ continue;
+
+ const char *dir = g_settings_sWatchCrashdumpArchiveDir.c_str();
+ log("Detected creation of file '%s' in upload directory '%s'", name, dir);
+ if (fork() == 0)
+ {
+ xchdir(dir);
+ execlp("abrt-handle-upload", "abrt-handle-upload", DEBUG_DUMPS_DIR, dir, name, (char*)NULL);
+ error_msg_and_die("Can't execute '%s'", "abrt-handle-upload");
+ }
+ }
+ continue;
+ }
- /* ignore lock files and such */
- if (!(event->mask & IN_ISDIR))
+ if (!(event->mask & IN_ISDIR) || !name)
{
+ /* ignore lock files and such */
// Happens all the time during normal run
//VERB3 log("File '%s' creation detected, ignoring", name);
continue;
}
if (strcmp(strchrnul(name, '.'), ".new") == 0)
{
- VERB3 log("Directory '%s' creation detected, ignoring", name);
+ //VERB3 log("Directory '%s' creation detected, ignoring", name);
continue;
}
log("Directory '%s' creation detected", name);
@@ -797,6 +834,9 @@ int main(int argc, char** argv)
{
init_daemon_logging(&watcher);
+ VERB1 log("Loading settings");
+ LoadSettings();
+
VERB1 log("Initializing XML-RPC library");
xmlrpc_env env;
xmlrpc_env_init(&env);
@@ -815,26 +855,28 @@ int main(int argc, char** argv)
if (inotify_fd == -1)
perror_msg_and_die("inotify_init failed");
close_on_exec_on(inotify_fd);
- if (inotify_add_watch(inotify_fd, DEBUG_DUMPS_DIR, IN_CREATE | IN_MOVED_TO) == -1)
+ if (inotify_add_watch(inotify_fd, DEBUG_DUMPS_DIR, IN_CREATE | IN_MOVED_TO) < 0)
perror_msg_and_die("inotify_add_watch failed on '%s'", DEBUG_DUMPS_DIR);
+ if (!g_settings_sWatchCrashdumpArchiveDir.empty())
+ {
+ s_upload_watch = inotify_add_watch(inotify_fd, g_settings_sWatchCrashdumpArchiveDir.c_str(), IN_CLOSE_WRITE|IN_MOVED_TO);
+ if (s_upload_watch < 0)
+ perror_msg_and_die("inotify_add_watch failed on '%s'", g_settings_sWatchCrashdumpArchiveDir.c_str());
+ }
+ VERB1 log("Adding inotify watch to glib main loop");
+ pGiochannel_inotify = g_io_channel_unix_new(inotify_fd);
+ g_io_add_watch(pGiochannel_inotify, G_IO_IN, handle_inotify_cb, NULL);
VERB1 log("Loading plugins from "PLUGINS_LIB_DIR);
g_pPluginManager = new CPluginManager();
g_pPluginManager->LoadPlugins();
- VERB1 log("Loading settings");
- LoadSettings();
-
if (SetUpMW() != 0) /* logging is inside */
throw 1;
if (SetUpCron() != 0)
throw 1;
- VERB1 log("Adding inotify watch to glib main loop");
- pGiochannel_inotify = g_io_channel_unix_new(inotify_fd);
- g_io_add_watch(pGiochannel_inotify, G_IO_IN, handle_inotify_cb, NULL);
/* Add an event source which waits for INT/TERM signal */
-
VERB1 log("Adding signal pipe watch to glib main loop");
pGiochannel_signal = g_io_channel_unix_new(s_signal_pipe[0]);
g_io_add_watch(pGiochannel_signal, G_IO_IN, handle_signal_cb, NULL);
diff --git a/src/Daemon/Makefile.am b/src/Daemon/Makefile.am
index 56292150..34243b1d 100644
--- a/src/Daemon/Makefile.am
+++ b/src/Daemon/Makefile.am
@@ -1,4 +1,4 @@
-bin_SCRIPTS = abrt-debuginfo-install
+bin_SCRIPTS = abrt-debuginfo-install abrt-handle-upload
sbin_PROGRAMS = abrtd
@@ -52,7 +52,7 @@ dist_comredhatabrtservice_DATA = com.redhat.abrt.service
man_MANS = abrtd.8 abrt.conf.5
-EXTRA_DIST = $(man_MANS) abrt-debuginfo-install
+EXTRA_DIST = $(man_MANS) abrt-debuginfo-install abrt-handle-upload
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/src/Daemon/Settings.cpp b/src/Daemon/Settings.cpp
index 24cce59b..a57cf0c7 100644
--- a/src/Daemon/Settings.cpp
+++ b/src/Daemon/Settings.cpp
@@ -56,6 +56,7 @@ set_string_t g_settings_setOpenGPGPublicKeys;
set_string_t g_settings_setBlackListedPkgs;
set_string_t g_settings_setBlackListedPaths;
std::string g_settings_sDatabase;
+std::string g_settings_sWatchCrashdumpArchiveDir;
unsigned int g_settings_nMaxCrashReportsSize = 1000;
bool g_settings_bProcessUnpackaged = false;
@@ -203,6 +204,11 @@ static void ParseCommon()
{
g_settings_sDatabase = it->second;
}
+ it = s_mapSectionCommon.find("WatchCrashdumpArchiveDir");
+ if (it != end)
+ {
+ g_settings_sWatchCrashdumpArchiveDir = it->second;
+ }
it = s_mapSectionCommon.find("MaxCrashReportsSize");
if (it != end)
{
diff --git a/src/Daemon/Settings.h b/src/Daemon/Settings.h
index 0395ed72..6dd964c9 100644
--- a/src/Daemon/Settings.h
+++ b/src/Daemon/Settings.h
@@ -32,6 +32,7 @@ extern unsigned int g_settings_nMaxCrashReportsSize;
extern bool g_settings_bOpenGPGCheck;
extern bool g_settings_bProcessUnpackaged;
extern std::string g_settings_sDatabase;
+extern std::string g_settings_sWatchCrashdumpArchiveDir;
extern map_cron_t g_settings_mapCron;
extern vector_pair_string_string_t g_settings_vectorActionsAndReporters;
extern map_analyzer_actions_and_reporters_t g_settings_mapAnalyzerActionsAndReporters;
diff --git a/src/Daemon/abrt-handle-upload b/src/Daemon/abrt-handle-upload
new file mode 100644
index 00000000..82f52692
--- /dev/null
+++ b/src/Daemon/abrt-handle-upload
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Called by abrtd when a new file is noticed in upload directory.
+# The task of this script is to unpack the file and move
+# crashdump(s) found in it to abrt's crashdump directory.
+#
+# Usage: abrt-handle-upload ABRT_DIR UPLOAD_DIR FILENAME
+
+#echo "Started: $0 $*"
+
+print_clean_and_die()
+{
+ printf "%s\n" "$*"
+ #echo delete_on_exit="$delete_on_exit"
+ test "$delete_on_exit" && rm -rf -- $delete_on_exit
+ exit $die_exitcode
+}
+
+die_exitcode=1
+delete_on_exit=""
+
+abrt_dir="$1"
+upload_dir="$2"
+archive="$3"
+
+test -d "$abrt_dir" || print_clean_and_die "Not a directory: '$abrt_dir'"
+test -d "$upload_dir" || print_clean_and_die "Not a directory: '$upload_dir'"
+test x"${archive%.working}" != x"$archive" && print_clean_and_die "Skipping: '$archive'"
+test x"${archive#/}" != x"$archive" && print_clean_and_die "Skipping: '$archive' (starts with slash)"
+test x"${archive#.}" != x"$archive" && print_clean_and_die "Skipping: '$archive' (starts with dot)"
+test x"${archive#*..}" != x"$archive" && print_clean_and_die "Skipping: '$archive' (contains ..)"
+test x"${archive#* }" != x"$archive" && print_clean_and_die "Skipping: '$archive' (contains space)"
+# Note: next line has a tab!
+test x"${archive#* }" != x"$archive" && print_clean_and_die "Skipping: '$archive' (contains tab)"
+
+cd -- "$upload_dir" || print_clean_and_die "Can't chdir to '$upload_dir'"
+
+unpacker=""
+test x"${archive%.tar.gz}" != x"$archive" && unpacker="gunzip"
+test x"${archive%.tar.bz2}" != x"$archive" && unpacker="bunzip2"
+test x"${archive%.tar.xz}" != x"$archive" && unpacker="unxz"
+
+test "$unpacker" || print_clean_and_die "Unknown file type: '$archive'"
+
+tempdir="remote.`date +%Y-%m-%d-%H:%M:%S.%N`.$$"
+
+mv -- "$archive" "$archive.working" || print_clean_and_die "Can't lock '$archive'"
+
+delete_on_exit="$archive.working"
+$unpacker -t -- "$archive.working" || print_clean_and_die "Verification error on '$archive'"
+
+echo "Unpacking '$archive'"
+mkdir "$tempdir" || print_clean_and_die "Can't create '$tempdir' directory"
+delete_on_exit="$archive.working $tempdir"
+$unpacker <"$archive.working" | tar xf - -C "$tempdir" || print_clean_and_die "Can't unpack '$archive'"
+
+# The archive can contain either plain dump files
+# or one or more complete crashdump directories.
+# Checking second possibility first.
+if test -f "$tempdir/analyzer" && test -f "$tempdir/time" && test -f "$tempdir/uid"; then
+ printf "1" >"$tempdir/remote"
+ mv -- "$tempdir" "$abrt_dir"
+else
+ for d in "$tempdir"/*; do
+ test -d "$d" || continue
+ printf "1" >"$tempdir/$d/remote"
+ mv -- "$d" "$abrt_dir"
+ done
+fi
+
+die_exitcode=0
+print_clean_and_die "'$archive' processed successfully"
diff --git a/src/Daemon/abrt.conf b/src/Daemon/abrt.conf
index 1bed49ca..6a70b820 100644
--- a/src/Daemon/abrt.conf
+++ b/src/Daemon/abrt.conf
@@ -12,6 +12,11 @@ ProcessUnpackaged = no
BlackListedPaths = /usr/share/doc/*, */example*
# Which database plugin to use
Database = SQLite3
+# Enable this if you want abrtd to auto-unpack crashdump tarballs which appear
+# in this directory (for example, uploaded via ftp, scp etc).
+# Note: you must ensure that whatever directory you specify here exists
+# and is writable for abrtd. abrtd will not create it automatically.
+#WatchCrashdumpArchiveDir = /var/spool/abrt-upload
# Max size for crash storage [MiB]
MaxCrashReportsSize = 1000
# Vector of actions and reporters which are activated immediately