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