Hi,

This patch splits abrt-dump-oops into a generic log watcher tool,
abrt-watch-log, and oops finder, which retains the name
abrt-dump-oops:

$ abrt-watch-log --help
Usage: abrt-watch-log [-vsw] FILE PROG [ARGS]

Watch log file FILE, run PROG when it grows or is replaced

    -v, --verbose               Be verbose
    -s                          Log to syslog
    -w                          Do not exit, watch FILE for changes

$ abrt-dump-oops --help
Usage: abrt-dump-oops [-vsox] [-d DIR]/[-D]

Extract oops from standard input

    -v, --verbose               Be verbose
    -s                          Log to syslog
    -o                          Print found oopses on standard output
    -d DIR                      Create ABRT dump in DIR for every oops found
    -D                          Same as -d DumpLocation, DumpLocation is 
specified in abrt.conf
    -x                          Make the problem directory world readable

Instead of running

    abrt-dump-oops -rwxD /var/log/messages

about the same effect is achieved by

    abrt-watch-log -w /var/log/messages -- abrt-dump-oops -xD

This opens up a possibility to have other log files watched,
with different processing apps.

Problems:
* How to kill a log watcher which watches particular file?

Ideas:
* Add --match='STR' and --match-regex='REGEX' switches to limit the frequency
  of executions of the helper.
* Remove -w switch as redundant?
* Retain optional FILE parameter of abrt-dump-oops?

1.patch is preparatory, it removes old abrt-dump-oops.c -
otherwise it's hard to read the changes.
2.patch is the gist of the change.

Please review.
--
vda
diff -x '*.po' -d -urpN abrt.0/examples/oops_recursive_locking1-no-jiffies.right abrt.1/examples/oops_recursive_locking1-no-jiffies.right
--- abrt.0/examples/oops_recursive_locking1-no-jiffies.right	1970-01-01 01:00:00.000000000 +0100
+++ abrt.1/examples/oops_recursive_locking1-no-jiffies.right	2012-03-14 13:39:47.694636974 +0100
@@ -0,0 +1,64 @@
+abrt-dump-oops: Found oopses: 1
+
+Version: 3.1.0-0.rc0.git19.1.fc17.x86_64
+[ INFO: possible recursive locking detected ]
+3.1.0-0.rc0.git19.1.fc17.x86_64 #1
+---------------------------------------------
+modprobe/684 is trying to acquire lock:
+ (&hdl->lock){+.+...}, at: [<ffffffffa02919ba>] find_ref_lock+0x24/0x46 [videodev]
+but task is already holding lock:
+ (&hdl->lock){+.+...}, at: [<ffffffffa029380f>] v4l2_ctrl_add_handler+0x49/0x97 [videodev]
+other info that might help us debug this:
+ Possible unsafe locking scenario:
+       CPU0
+       ----
+  lock(&hdl->lock);
+  lock(&hdl->lock);
+ *** DEADLOCK ***
+ May be due to missing lock nesting notation
+3 locks held by modprobe/684:
+ #0:  (&__lockdep_no_validate__){......}, at: [<ffffffff81314d0c>] __driver_attach+0x3b/0x82
+ #1:  (&__lockdep_no_validate__){......}, at: [<ffffffff81314d1a>] __driver_attach+0x49/0x82
+ #2:  (&hdl->lock){+.+...}, at: [<ffffffffa029380f>] v4l2_ctrl_add_handler+0x49/0x97 [videodev]
+stack backtrace:
+Pid: 684, comm: modprobe Not tainted 3.1.0-0.rc0.git19.1.fc17.x86_64 #1
+Call Trace:
+ [<ffffffff8108eb06>] __lock_acquire+0x917/0xcf7
+ [<ffffffff81014fbe>] ? sched_clock+0x9/0xd
+ [<ffffffff8108dffc>] ? mark_lock+0x2d/0x220
+ [<ffffffffa02919ba>] ? find_ref_lock+0x24/0x46 [videodev]
+ [<ffffffff8108f3dc>] lock_acquire+0xf3/0x13e
+ [<ffffffffa02919ba>] ? find_ref_lock+0x24/0x46 [videodev]
+ [<ffffffffa02919ba>] ? find_ref_lock+0x24/0x46 [videodev]
+ [<ffffffff814f2523>] __mutex_lock_common+0x5d/0x39a
+ [<ffffffffa02919ba>] ? find_ref_lock+0x24/0x46 [videodev]
+ [<ffffffff8108f6db>] ? mark_held_locks+0x6d/0x95
+ [<ffffffff814f282f>] ? __mutex_lock_common+0x369/0x39a
+ [<ffffffff8108f830>] ? trace_hardirqs_on_caller+0x12d/0x164
+ [<ffffffff814f296f>] mutex_lock_nested+0x40/0x45
+ [<ffffffffa02919ba>] find_ref_lock+0x24/0x46 [videodev]
+ [<ffffffffa029367e>] handler_new_ref+0x42/0x18a [videodev]
+ [<ffffffffa0293833>] v4l2_ctrl_add_handler+0x6d/0x97 [videodev]
+ [<ffffffffa028f71b>] v4l2_device_register_subdev+0x16c/0x257 [videodev]
+ [<ffffffffa02ddfe9>] ivtv_gpio_init+0x14e/0x159 [ivtv]
+ [<ffffffffa02ebd57>] ivtv_probe+0xdc4/0x1662 [ivtv]
+ [<ffffffff8108f6c3>] ? mark_held_locks+0x55/0x95
+ [<ffffffff814f41df>] ? _raw_spin_unlock_irqrestore+0x4d/0x61
+ [<ffffffff8126a12b>] local_pci_probe+0x44/0x75
+ [<ffffffff8126acb1>] pci_device_probe+0xd0/0xff
+ [<ffffffff81314bef>] driver_probe_device+0x131/0x213
+ [<ffffffff81314d2f>] __driver_attach+0x5e/0x82
+ [<ffffffff81314cd1>] ? driver_probe_device+0x213/0x213
+ [<ffffffff81313c30>] bus_for_each_dev+0x59/0x8f
+ [<ffffffff813147c3>] driver_attach+0x1e/0x20
+ [<ffffffff813143db>] bus_add_driver+0xd4/0x22a
+ [<ffffffffa02ff000>] ? 0xffffffffa02fefff
+ [<ffffffff813151f2>] driver_register+0x98/0x105
+ [<ffffffffa02ff000>] ? 0xffffffffa02fefff
+ [<ffffffff8126b584>] __pci_register_driver+0x66/0xd2
+ [<ffffffffa02ff000>] ? 0xffffffffa02fefff
+ [<ffffffffa02ff078>] module_start+0x78/0x1000 [ivtv]
+ [<ffffffff81002099>] do_one_initcall+0x7f/0x13a
+ [<ffffffffa02ff000>] ? 0xffffffffa02fefff
+ [<ffffffff8109a864>] sys_init_module+0x114/0x267
+ [<ffffffff814fafc2>] system_call_fastpath+0x16/0x1b
diff -x '*.po' -d -urpN abrt.0/src/plugins/abrt-dump-oops.c abrt.1/src/plugins/abrt-dump-oops.c
--- abrt.0/src/plugins/abrt-dump-oops.c	2012-03-07 11:38:56.000000000 +0100
+++ abrt.1/src/plugins/abrt-dump-oops.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,441 +0,0 @@
-/*
-    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 <[email protected]>
-       Arjan van de Ven <[email protected]>
- */
-#include <syslog.h>
-#include <asm/unistd.h> /* __NR_syslog */
-#include <sys/inotify.h>
-#include "libabrt.h"
-
-
-static bool world_readable_dump = false;
-static const char *debug_dumps_dir = ".";
-
-#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 */
-    koops_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)
-    {
-        /* If file was truncated, treat it as a new file.
-         * (changing inode# causes caller to think that file was closed or renamed)
-         */
-        if (statbuf->st_size < cur_pos)
-            statbuf->st_ino++;
-        return partial_line_len; /* we are at EOF, nothing to do */
-    }
-
-    VERB3 log("File grew by %llu bytes, from %llu to %llu",
-        (long long)(statbuf->st_size - cur_pos),
-        (long long)(cur_pos),
-        (long 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;
-
-        koops_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 unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
-{
-    unsigned countdown = 16; /* do not report hundreds of oopses */
-    unsigned idx = oops_cnt;
-
-    VERB1 log("Saving %u oopses as dump dirs", idx >= countdown ? countdown-1 : idx);
-
-    char *cmdline_str = NULL;
-    FILE *cmdline_fp = fopen("/proc/cmdline", "r");
-    if (cmdline_fp)
-    {
-        cmdline_str = xmalloc_fgetline(cmdline_fp);
-        fclose(cmdline_fp);
-    }
-
-    time_t t = time(NULL);
-    const char *iso_date = iso_date_string(&t);
-    /* dump should be readable by all if we're run with -x */
-    uid_t my_euid = (uid_t)-1L;
-    mode_t mode = 0644;
-    /* and readable only for the owner otherwise */
-    if (!world_readable_dump)
-    {
-        mode = 0640;
-        my_euid = geteuid();
-    }
-
-    pid_t my_pid = getpid();
-    unsigned errors = 0;
-    while (idx != 0 && --countdown != 0)
-    {
-        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;
-        {
-            char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
-            sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
-            char *path = concat_path_file(debug_dumps_dir, base);
-            dd = dd_create(path, /*uid:*/ my_euid, mode);
-            free(path);
-        }
-
-        if (dd)
-        {
-            dd_create_basic_files(dd, /*uid:*/ my_euid);
-            dd_save_text(dd, "abrt_version", VERSION);
-            dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
-            dd_save_text(dd, FILENAME_KERNEL, first_line);
-            if (cmdline_str)
-                dd_save_text(dd, FILENAME_CMDLINE, cmdline_str);
-            dd_save_text(dd, FILENAME_BACKTRACE, second_line);
-
-            /* check if trace doesn't have line: 'Your BIOS is broken' */
-            char *broken_bios = strstr(second_line, "Your BIOS is broken");
-            if (broken_bios)
-                dd_save_text(dd, FILENAME_NOT_REPORTABLE, "Your BIOS is broken");
-
-            char *tainted_short = kernel_tainted_short(second_line);
-            if (tainted_short && !broken_bios)
-            {
-                VERB1 log("Kernel is tainted '%s'", tainted_short);
-                dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
-                const char *fmt = _("A kernel problem occurred, but your kernel has been"
-                             "tainted (flags:%s). Kernel maintainers are unable to"
-                             "diagnose tainted reports.");
-
-                char *reason = xasprintf(fmt, tainted_short);
-
-                dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason);
-                free(reason);
-            }
-// TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
-// kernel oops 1st line may look quite puzzling otherwise...
-            strchrnul(second_line, '\n')[0] = '\0';
-            dd_save_text(dd, FILENAME_REASON, second_line);
-
-/*
-            GList *tainted_long = kernel_tainted_long(tainted);
-
-            struct strbuf *tnt_long = strbuf_new();
-            for (GList *li = tainted_long; li; li = li->next)
-                strbuf_append_strf(tnt_long, "%s\n", (char*) li->data);
-
-            dd_save_text(dd, FILENAME_TAINTED, tainted_str);
-            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
-            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long->buf);
-            strbuf_free(tnt_long);
-            list_free_with_free(tainted_long);
-*/
-            dd_close(dd);
-        }
-        else
-            errors++;
-    }
-
-    free(cmdline_str);
-
-    return errors;
-}
-
-int main(int argc, char **argv)
-{
-    /* I18n */
-    setlocale(LC_ALL, "");
-#if ENABLE_NLS
-    bindtextdomain(PACKAGE, LOCALEDIR);
-    textdomain(PACKAGE);
-#endif
-
-    abrt_init(argv);
-
-    /* Can't keep these strings/structs static: _() doesn't support that */
-    const char *program_usage_string = _(
-        "& [-vsrowx] [-d DIR] FILE\n"
-        "or: & [-vsrowx] -D FILE\n"
-        "\n"
-        "Extract oops from syslog/dmesg file"
-    );
-    enum {
-        OPT_v = 1 << 0,
-        OPT_s = 1 << 1,
-        OPT_r = 1 << 2,
-        OPT_o = 1 << 3,
-        OPT_w = 1 << 4,
-        OPT_d = 1 << 5,
-        OPT_x = 1 << 6,
-        OPT_D = 1 << 7,
-    };
-    /* 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(  'o', NULL, NULL, _("Print found oopses on standard output")),
-        OPT_BOOL(  'w', NULL, NULL, _("Do not exit, watch the file for new oopses")),
-        /* oopses don't contain any sensitive info, and even
-         * the old koops app was showing the oopses to all users
-         */
-        OPT_STRING('d', NULL, &debug_dumps_dir, "DIR", _("Create ABRT dump in DIR for every oops found")),
-        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
-        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
-        OPT_END()
-    };
-    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
-
-    if ((opts & OPT_d) && (opts & OPT_D))
-        show_usage_and_die(program_usage_string, program_options);
-
-    export_abrt_envvars(0);
-
-    msg_prefix = g_progname;
-    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
-    {
-        openlog(msg_prefix, 0, LOG_DAEMON);
-        logmode = LOGMODE_SYSLOG;
-    }
-
-    argv += optind;
-    if (!argv[0])
-        show_usage_and_die(program_usage_string, program_options);
-    const char *filename = argv[0];
-
-    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);
-
-    world_readable_dump = (opts & OPT_x);
-
-    int partial_line_len = 0;
-    struct stat statbuf;
-    int file_fd = -1;
-    int wd = -1;
-    unsigned errors = 0;
-
-    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("Inode# changed, closing fd");
-                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)
-            log("Found oopses: %d", oops_cnt);
-        if (oops_cnt != 0)
-        {
-            if (opts & OPT_o)
-            {
-                int i = 0;
-                while (i < oops_cnt)
-                {
-                    char *kernel_bt = (char*)g_list_nth_data(oops_list, i++);
-                    char *tainted_short = kernel_tainted_short(kernel_bt);
-                    if (tainted_short)
-                        log("Kernel is tainted '%s'", tainted_short);
-
-                    free(tainted_short);
-                    printf("\nVersion: %s", kernel_bt);
-                }
-            }
-            if ((opts & OPT_d) || (opts & OPT_D))
-            {
-                if (opts & OPT_D)
-                {
-                    load_abrt_conf();
-                    debug_dumps_dir = g_settings_dump_location;
-                }
-
-                log("Creating dump directories");
-                errors += save_oops_to_dump_dir(oops_list, oops_cnt);
-                if (errors > 0)
-                    log("%d errors while dumping oopses", errors);
-                /*
-                 * This marker in syslog file prevents us from
-                 * re-parsing old oopses. The only problem is that we
-                 * can't be sure here that the file we are watching
-                 * is the same file where syslog(xxx) stuff ends up.
-                 */
-                syslog(LOG_WARNING,
-                        "Reported %u kernel oopses to Abrt",
-                        oops_cnt
-                );
-
-                if (opts & OPT_D)
-                    free_abrt_conf_data();
-            }
-        }
-        list_free_with_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 && errno != EINTR) /* I saw EINTR here on strace attach */
-                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);
-            /* Let them finish writing to the log file. otherwise
-             * we may end up trying to analyze partial oops.
-             */
-            sleep(1);
-        }
-
-    } /* while (1) */
-
-    return errors;
-}
diff -x '*.po' -d -urpN abrt.1/abrt.spec.in abrt.2/abrt.spec.in
--- abrt.1/abrt.spec.in	2012-02-28 14:29:11.000000000 +0100
+++ abrt.2/abrt.spec.in	2012-03-14 03:14:52.446107757 +0100
@@ -505,6 +505,7 @@ gtk-update-icon-cache %{_datadir}/icons/
 %else
 %{_initrddir}/abrt-oops
 %endif
+%{_bindir}/abrt-watch-log
 %{_bindir}/abrt-dump-oops
 %{_bindir}/abrt-action-analyze-oops
 %{_mandir}/man1/abrt-action-analyze-oops.1*
diff -x '*.po' -d -urpN abrt.1/examples/not_oops1.right abrt.2/examples/not_oops1.right
--- abrt.1/examples/not_oops1.right	2011-10-27 19:11:55.000000000 +0200
+++ abrt.2/examples/not_oops1.right	2012-03-14 12:52:44.784907917 +0100
@@ -1 +0,0 @@
-abrt-dump-oops: Found oopses: 0
diff -x '*.po' -d -urpN abrt.1/examples/not_oops2.right abrt.2/examples/not_oops2.right
--- abrt.1/examples/not_oops2.right	2011-10-27 19:11:55.000000000 +0200
+++ abrt.2/examples/not_oops2.right	2012-03-14 12:52:49.088877135 +0100
@@ -1 +0,0 @@
-abrt-dump-oops: Found oopses: 0
diff -x '*.po' -d -urpN abrt.1/examples/not_oops3.right abrt.2/examples/not_oops3.right
--- abrt.1/examples/not_oops3.right	2011-10-27 19:11:55.000000000 +0200
+++ abrt.2/examples/not_oops3.right	2012-03-14 12:52:52.861850154 +0100
@@ -1 +0,0 @@
-abrt-dump-oops: Found oopses: 0
diff -x '*.po' -d -urpN abrt.1/examples/test.sh abrt.2/examples/test.sh
--- abrt.1/examples/test.sh	2011-10-27 19:11:55.000000000 +0200
+++ abrt.2/examples/test.sh	2012-03-14 13:19:49.482350537 +0100
@@ -1,7 +1,10 @@
 for f in *.test; do
         b="${f%%.test}"
-        abrt-dump-oops -o "$f" >"$b".out 2>&1
+        abrt-dump-oops -o <"$f" >"$b".out 2>&1
         if diff -u "$b".right "$b".out >"$b".diff 2>&1; then
+                echo "Tested $f: ok"
                 rm "$b".out "$b".diff
+        else
+                echo "Tested $f: BAD"
         fi
 done
diff -x '*.po' -d -urpN abrt.1/.gitignore abrt.2/.gitignore
--- abrt.1/.gitignore	2012-02-28 14:29:11.000000000 +0100
+++ abrt.2/.gitignore	2012-03-14 03:15:04.891070662 +0100
@@ -23,6 +23,7 @@ src/plugins/abrt-action-analyze-vmcore
 src/plugins/abrt-action-generate-backtrace
 src/plugins/abrt-action-install-debuginfo-to-abrt-cache
 src/plugins/abrt-action-trim-files
+src/plugins/abrt-watch-log
 src/plugins/abrt-dump-oops
 src/plugins/abrt-dedup-client
 src/plugins/abrt-retrace-client
diff -x '*.po' -d -urpN abrt.1/init-scripts/abrt-oops abrt.2/init-scripts/abrt-oops
--- abrt.1/init-scripts/abrt-oops	2011-10-27 19:11:55.000000000 +0200
+++ abrt.2/init-scripts/abrt-oops	2012-03-14 12:40:03.241409684 +0100
@@ -33,14 +33,19 @@ check() {
 
 start() {
 	check
-	killall abrt-dump-oops 2>/dev/null
-	setsid abrt-dump-oops -rwxD /var/log/messages </dev/null >/dev/null 2>&1 &
+#FIXME: need to kill only abrt-watch-log which watches /var/log/messages!
+	killall abrt-watch-log 2>/dev/null
+	# Scan dmesg
+	dmesg | abrt-dump-oops -xD
+	# Watch and scan /var/log/messages
+	setsid abrt-watch-log -w /var/log/messages -- abrt-dump-oops -xD </dev/null >/dev/null 2>&1 &
 	$dry_run || touch -- "$LOCK"
 	return $RETVAL
 }
 
 stop() {
 	check
+#FIXME: need to kill only abrt-watch-log which watches /var/log/messages!
 	killall abrt-dump-oops
 	$dry_run || rm -f -- "$LOCK"
 	return $RETVAL
diff -x '*.po' -d -urpN abrt.1/init-scripts/abrt-oops.service abrt.2/init-scripts/abrt-oops.service
--- abrt.1/init-scripts/abrt-oops.service	2011-11-11 13:54:02.000000000 +0100
+++ abrt.2/init-scripts/abrt-oops.service	2012-03-14 13:32:11.168794069 +0100
@@ -4,7 +4,7 @@ After=abrtd.service
 Requires=abrtd.service
 
 [Service]
-ExecStart=/usr/bin/abrt-dump-oops -rwxD /var/log/messages
+ExecStart=/usr/bin/abrt-watch-log -w /var/log/messages -- /usr/bin/abrt-dump-oops -xD
 
 [Install]
 WantedBy=multi-user.target
diff -x '*.po' -d -urpN abrt.1/po/POTFILES.in abrt.2/po/POTFILES.in
--- abrt.1/po/POTFILES.in	2012-02-16 10:09:08.000000000 +0100
+++ abrt.2/po/POTFILES.in	2012-03-14 03:24:28.105323391 +0100
@@ -21,6 +21,7 @@ src/plugins/abrt-action-generate-core-ba
 src/plugins/abrt-action-install-debuginfo
 src/plugins/abrt-action-trim-files.c
 src/plugins/abrt-dedup-client.c
+src/plugins/abrt-watch-log.c
 src/plugins/abrt-dump-oops.c
 src/plugins/abrt-retrace-client.c
 src/plugins/analyze_LocalGDB.xml.in
diff -x '*.po' -d -urpN abrt.1/src/plugins/abrt-action-analyze-vmcore.in abrt.2/src/plugins/abrt-action-analyze-vmcore.in
--- abrt.1/src/plugins/abrt-action-analyze-vmcore.in	2012-02-28 14:29:11.000000000 +0100
+++ abrt.2/src/plugins/abrt-action-analyze-vmcore.in	2012-03-14 13:18:50.141654159 +0100
@@ -123,5 +123,6 @@ if __name__ == "__main__":
     out, err = crash.communicate(input="log")
     log_file.close()
     backtrace_file = open("backtrace", "w")
-    dump_oops = Popen(["abrt-dump-oops", "-o", "kernel_log"], stdout=backtrace_file, bufsize=-1)
+    kernel_log_file = open("kernel_log", "r")
+    dump_oops = Popen(["abrt-dump-oops", "-o"], stdin=kernel_log_file, stdout=backtrace_file, bufsize=-1)
     backtrace_file.close()
diff -x '*.po' -d -urpN abrt.1/src/plugins/abrt-dump-oops.c abrt.2/src/plugins/abrt-dump-oops.c
--- abrt.1/src/plugins/abrt-dump-oops.c	1970-01-01 01:00:00.000000000 +0100
+++ abrt.2/src/plugins/abrt-dump-oops.c	2012-03-14 12:46:15.173708053 +0100
@@ -0,0 +1,277 @@
+/*
+    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 <[email protected]>
+       Arjan van de Ven <[email protected]>
+ */
+#include <syslog.h>
+#include "libabrt.h"
+
+
+static bool world_readable_dump = false;
+static const char *debug_dumps_dir = ".";
+
+#define MAX_SCAN_BLOCK  (4*1024*1024)
+#define READ_AHEAD          (10*1024)
+
+static void scan_syslog_file(GList **oops_list, int fd)
+{
+    struct stat st;
+    struct stat *statbuf = &st;
+
+    /* Try to not allocate an absurd amount of memory */
+    int sz = MAX_SCAN_BLOCK - READ_AHEAD;
+    /* If it's a real file, estimate size after cur pos */
+    off_t cur_pos = lseek(fd, 0, SEEK_CUR);
+    if (cur_pos >= 0 && fstat(fd, statbuf) == 0 && S_ISREG(statbuf->st_mode))
+    {
+        off_t size_to_read = statbuf->st_size - cur_pos;
+        if (size_to_read >= 0 && sz > size_to_read)
+            sz = size_to_read;
+    }
+
+    /*
+     * 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);
+
+    for (;;)
+    {
+        int r = full_read(fd, buffer, sz-1);
+        if (r <= 0)
+            break;
+        VERB3 log("Read %u bytes", r);
+        koops_extract_oopses(oops_list, buffer, r);
+//TODO: rewind to last newline?
+    }
+
+    free(buffer);
+}
+
+/* returns number of errors */
+static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
+{
+    unsigned countdown = 16; /* do not report hundreds of oopses */
+    unsigned idx = oops_cnt;
+
+    VERB1 log("Saving %u oopses as dump dirs", idx >= countdown ? countdown-1 : idx);
+
+    char *cmdline_str = NULL;
+    FILE *cmdline_fp = fopen("/proc/cmdline", "r");
+    if (cmdline_fp)
+    {
+        cmdline_str = xmalloc_fgetline(cmdline_fp);
+        fclose(cmdline_fp);
+    }
+
+    time_t t = time(NULL);
+    const char *iso_date = iso_date_string(&t);
+    /* dump should be readable by all if we're run with -x */
+    uid_t my_euid = (uid_t)-1L;
+    mode_t mode = 0644;
+    /* and readable only for the owner otherwise */
+    if (!world_readable_dump)
+    {
+        mode = 0640;
+        my_euid = geteuid();
+    }
+
+    pid_t my_pid = getpid();
+    unsigned errors = 0;
+    while (idx != 0 && --countdown != 0)
+    {
+        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;
+        {
+            char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
+            sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
+            char *path = concat_path_file(debug_dumps_dir, base);
+            dd = dd_create(path, /*uid:*/ my_euid, mode);
+            free(path);
+        }
+
+        if (dd)
+        {
+            dd_create_basic_files(dd, /*uid:*/ my_euid);
+            dd_save_text(dd, "abrt_version", VERSION);
+            dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
+            dd_save_text(dd, FILENAME_KERNEL, first_line);
+            if (cmdline_str)
+                dd_save_text(dd, FILENAME_CMDLINE, cmdline_str);
+            dd_save_text(dd, FILENAME_BACKTRACE, second_line);
+
+            /* check if trace doesn't have line: 'Your BIOS is broken' */
+            char *broken_bios = strstr(second_line, "Your BIOS is broken");
+            if (broken_bios)
+                dd_save_text(dd, FILENAME_NOT_REPORTABLE, "Your BIOS is broken");
+
+            char *tainted_short = kernel_tainted_short(second_line);
+            if (tainted_short && !broken_bios)
+            {
+                VERB1 log("Kernel is tainted '%s'", tainted_short);
+                dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
+                const char *fmt = _("A kernel problem occurred, but your kernel has been"
+                             "tainted (flags:%s). Kernel maintainers are unable to"
+                             "diagnose tainted reports.");
+
+                char *reason = xasprintf(fmt, tainted_short);
+
+                dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason);
+                free(reason);
+            }
+// TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
+// kernel oops 1st line may look quite puzzling otherwise...
+            strchrnul(second_line, '\n')[0] = '\0';
+            dd_save_text(dd, FILENAME_REASON, second_line);
+
+/*
+            GList *tainted_long = kernel_tainted_long(tainted);
+
+            struct strbuf *tnt_long = strbuf_new();
+            for (GList *li = tainted_long; li; li = li->next)
+                strbuf_append_strf(tnt_long, "%s\n", (char*) li->data);
+
+            dd_save_text(dd, FILENAME_TAINTED, tainted_str);
+            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
+            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long->buf);
+            strbuf_free(tnt_long);
+            list_free_with_free(tainted_long);
+*/
+            dd_close(dd);
+        }
+        else
+            errors++;
+    }
+
+    free(cmdline_str);
+
+    return errors;
+}
+
+int main(int argc, char **argv)
+{
+    /* I18n */
+    setlocale(LC_ALL, "");
+#if ENABLE_NLS
+    bindtextdomain(PACKAGE, LOCALEDIR);
+    textdomain(PACKAGE);
+#endif
+
+    abrt_init(argv);
+
+    /* Can't keep these strings/structs static: _() doesn't support that */
+    const char *program_usage_string = _(
+        "& [-vsox] [-d DIR]/[-D]\n"
+        "\n"
+        "Extract oops from standard input"
+    );
+    enum {
+        OPT_v = 1 << 0,
+        OPT_s = 1 << 1,
+        OPT_o = 1 << 2,
+        OPT_d = 1 << 3,
+        OPT_D = 1 << 4,
+        OPT_x = 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(  'o', NULL, NULL, _("Print found oopses on standard output")),
+        /* oopses don't contain any sensitive info, and even
+         * the old koops app was showing the oopses to all users
+         */
+        OPT_STRING('d', NULL, &debug_dumps_dir, "DIR", _("Create ABRT dump in DIR for every oops found")),
+        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
+        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
+        OPT_END()
+    };
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+
+    if ((opts & OPT_d) && (opts & OPT_D))
+        show_usage_and_die(program_usage_string, program_options);
+
+    export_abrt_envvars(0);
+
+    msg_prefix = g_progname;
+    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
+    {
+        openlog(msg_prefix, 0, LOG_DAEMON);
+        logmode = LOGMODE_SYSLOG;
+    }
+
+//    argv += optind;
+
+    world_readable_dump = (opts & OPT_x);
+    unsigned errors = 0;
+    GList *oops_list = NULL;
+    scan_syslog_file(&oops_list, STDIN_FILENO);
+
+    int oops_cnt = g_list_length(oops_list);
+    if (oops_cnt != 0)
+    {
+        log("Found oopses: %d", oops_cnt);
+        if (opts & OPT_o)
+        {
+            int i = 0;
+            while (i < oops_cnt)
+            {
+                char *kernel_bt = (char*)g_list_nth_data(oops_list, i++);
+                char *tainted_short = kernel_tainted_short(kernel_bt);
+                if (tainted_short)
+                    log("Kernel is tainted '%s'", tainted_short);
+
+                free(tainted_short);
+                printf("\nVersion: %s", kernel_bt);
+            }
+        }
+        if (opts & (OPT_d|OPT_D))
+        {
+            if (opts & OPT_D)
+            {
+                load_abrt_conf();
+                debug_dumps_dir = g_settings_dump_location;
+            }
+
+            log("Creating dump directories");
+            errors = save_oops_to_dump_dir(oops_list, oops_cnt);
+            if (errors)
+                log("%d errors while dumping oopses", errors);
+            /*
+             * This marker in syslog file prevents us from
+             * re-parsing old oopses. The only problem is that we
+             * can't be sure here that the file we are watching
+             * is the same file where syslog(xxx) stuff ends up.
+             */
+            syslog(LOG_WARNING,
+                    "Reported %u kernel oopses to Abrt",
+                    oops_cnt
+            );
+
+//            if (opts & OPT_D)
+//                free_abrt_conf_data();
+        }
+    }
+//    list_free_with_free(oops_list);
+//    oops_list = NULL;
+
+    return errors;
+}
diff -x '*.po' -d -urpN abrt.1/src/plugins/abrt-watch-log.c abrt.2/src/plugins/abrt-watch-log.c
--- abrt.1/src/plugins/abrt-watch-log.c	1970-01-01 01:00:00.000000000 +0100
+++ abrt.2/src/plugins/abrt-watch-log.c	2012-03-14 13:12:27.424596150 +0100
@@ -0,0 +1,212 @@
+/*
+    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 <[email protected]>
+       Arjan van de Ven <[email protected]>
+ */
+#include <syslog.h>
+#include <sys/inotify.h>
+#include "libabrt.h"
+
+static void run_scanner_prog(int fd, struct stat *statbuf, char **prog)
+{
+    /* fstat(fd, &statbuf) was just done by caller */
+
+    off_t cur_pos = lseek(fd, 0, SEEK_CUR);
+    if (statbuf->st_size <= cur_pos)
+    {
+        /* If file was truncated, treat it as a new file.
+         * (changing inode# causes caller to think that file was closed or renamed)
+         */
+        if (statbuf->st_size < cur_pos)
+            statbuf->st_ino++;
+        return; /* we are at EOF, nothing to do */
+    }
+
+    VERB3 log("File grew by %llu bytes, from %llu to %llu",
+        (long long)(statbuf->st_size - cur_pos),
+        (long long)(cur_pos),
+        (long long)(statbuf->st_size));
+
+    pid_t pid = vfork();
+    if (pid < 0)
+        perror_msg_and_die("vfork");
+    if (pid == 0)
+    {
+        xmove_fd(fd, STDIN_FILENO);
+        execvp(prog[0], prog);
+        perror_msg_and_die("Can't execute '%s'", prog[0]);
+    }
+
+    safe_waitpid(pid, NULL, 0);
+
+//TODO: check fd's position, and move to end if wasn't changed.
+}
+
+int main(int argc, char **argv)
+{
+    /* I18n */
+    setlocale(LC_ALL, "");
+#if ENABLE_NLS
+    bindtextdomain(PACKAGE, LOCALEDIR);
+    textdomain(PACKAGE);
+#endif
+
+    abrt_init(argv);
+
+    /* Can't keep these strings/structs static: _() doesn't support that */
+    const char *program_usage_string = _(
+        "& [-vsw] FILE PROG [ARGS]\n"
+        "\n"
+        "Watch log file FILE, run PROG when it grows or is replaced"
+    );
+    enum {
+        OPT_v = 1 << 0,
+        OPT_s = 1 << 1,
+        OPT_w = 1 << 2,
+    };
+    /* 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(  'w', NULL, NULL, _("Do not exit, watch FILE for changes")),
+        OPT_END()
+    };
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+
+    export_abrt_envvars(0);
+
+    msg_prefix = g_progname;
+    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
+    {
+        openlog(msg_prefix, 0, LOG_DAEMON);
+        logmode = LOGMODE_SYSLOG;
+    }
+
+    argv += optind;
+    if (!argv[0] || !argv[1])
+        show_usage_and_die(program_usage_string, program_options);
+
+    const char *filename = *argv++;
+
+    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);
+    }
+
+    struct stat statbuf;
+    int file_fd = -1;
+    int wd = -1;
+
+    while (1) /* loops only if -w */
+    {
+        /* If file is already opened, scan it from current pos */
+        if (file_fd >= 0)
+        {
+            memset(&statbuf, 0, sizeof(statbuf));
+            fstat(file_fd, &statbuf);
+            run_scanner_prog(file_fd, &statbuf, argv);
+
+            /* 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("Inode# changed, closing fd");
+                close(file_fd);
+                if (wd >= 0)
+                    inotify_rm_watch(inotify_fd, wd);
+                file_fd = -1;
+                wd = -1;
+            }
+        }
+
+        /* If file isn't opened, try to open it and scan */
+        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.
+                     */
+#define MAX_SCAN_BLOCK  (4*1024*1024)
+#define READ_AHEAD          (10*1024)
+                    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,
+                     * run_scanner_prog needs that
+                     */
+                    run_scanner_prog(file_fd, &statbuf, argv);
+                }
+            }
+        }
+
+        /* 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 && errno != EINTR) /* I saw EINTR here on strace attach */
+                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);
+            /* Let them finish writing to the log file. otherwise
+             * we may end up trying to analyze partial oops.
+             */
+            sleep(1);
+        }
+
+    } /* while (1) */
+
+    return 0;
+}
diff -x '*.po' -d -urpN abrt.1/src/plugins/Makefile.am abrt.2/src/plugins/Makefile.am
--- abrt.1/src/plugins/Makefile.am	2012-02-28 14:29:11.000000000 +0100
+++ abrt.2/src/plugins/Makefile.am	2012-03-14 03:14:31.418176392 +0100
@@ -7,6 +7,7 @@ bin_SCRIPTS = \
     abrt-action-list-dsos
 
 bin_PROGRAMS = \
+    abrt-watch-log \
     abrt-dump-oops \
     abrt-action-analyze-c \
     abrt-action-analyze-python \
@@ -69,6 +70,20 @@ EXTRA_DIST = \
     abrt-action-analyze-vmcore \
     https-utils.h
 
+abrt_watch_log_SOURCES = \
+    abrt-watch-log.c
+abrt_watch_log_CPPFLAGS = \
+    -I$(srcdir)/../include \
+    -I$(srcdir)/../lib \
+    $(GLIB_CFLAGS) \
+    $(LIBREPORT_CFLAGS) \
+    -D_GNU_SOURCE \
+    -Wall -Wwrite-strings -Werror
+abrt_watch_log_LDADD = \
+    $(GLIB_LIBS) \
+    $(LIBREPORT_LIBS) \
+    ../lib/libabrt.la
+
 abrt_dump_oops_SOURCES = \
     abrt-dump-oops.c
 abrt_dump_oops_CPPFLAGS = \
diff -x '*.po' -d -urpN abrt.1/tests/runtests/dumpoops/runtest.sh abrt.2/tests/runtests/dumpoops/runtest.sh
--- abrt.1/tests/runtests/dumpoops/runtest.sh	2011-11-22 15:19:35.000000000 +0100
+++ abrt.2/tests/runtests/dumpoops/runtest.sh	2012-03-14 13:19:36.179418713 +0100
@@ -39,13 +39,13 @@ rlJournalStart
 
     rlPhaseStartTest OOPS
         for oops in oops*.test; do
-            rlRun "abrt-dump-oops $oops 2>&1 | grep 'abrt-dump-oops: Found oopses: [1-9]'" 0 "[$oops] Found OOPS"
+            rlRun "abrt-dump-oops <$oops 2>&1 | grep 'abrt-dump-oops: Found oopses: [1-9]'" 0 "[$oops] Found OOPS"
         done
     rlPhaseEnd
 
     rlPhaseStartTest not-OOPS
         for noops in not_oops*.test; do
-            rlRun "abrt-dump-oops $noops 2>&1 | grep 'abrt-dump-oops: Found oopses: 0'" 0 "[$noops] Not found OOPS"
+            rlRun "abrt-dump-oops <$noops 2>&1 | grep 'abrt-dump-oops: Found oopses: 0'" 0 "[$noops] Not found OOPS"
         done
     rlPhaseEnd
 

Reply via email to