|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2011,2014 ABRT team
|
|
Packit |
8ea169 |
Copyright (C) 2011,2014 RedHat Inc
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
Authors:
|
|
Packit |
8ea169 |
Anton Arapov <anton@redhat.com>
|
|
Packit |
8ea169 |
Arjan van de Ven <arjan@linux.intel.com>
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
#include <syslog.h>
|
|
Packit |
8ea169 |
#include "libabrt.h"
|
|
Packit |
8ea169 |
#include "oops-utils.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define MAX_SCAN_BLOCK (4*1024*1024)
|
|
Packit |
8ea169 |
#define READ_AHEAD (10*1024)
|
|
Packit |
8ea169 |
#define ABRT_DUMP_OOPS_ANALYZER "abrt-oops"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void scan_syslog_file(GList **oops_list, int fd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct stat st;
|
|
Packit |
8ea169 |
struct stat *statbuf = &st;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Try to not allocate an absurd amount of memory */
|
|
Packit |
8ea169 |
int sz = MAX_SCAN_BLOCK - READ_AHEAD;
|
|
Packit |
8ea169 |
/* If it's a real file, estimate size after cur pos */
|
|
Packit |
8ea169 |
off_t cur_pos = lseek(fd, 0, SEEK_CUR);
|
|
Packit |
8ea169 |
if (cur_pos >= 0 && fstat(fd, statbuf) == 0 && S_ISREG(statbuf->st_mode))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
off_t size_to_read = statbuf->st_size - cur_pos;
|
|
Packit |
8ea169 |
if (size_to_read >= 0 && sz > size_to_read)
|
|
Packit |
8ea169 |
sz = size_to_read;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
* In theory we have a race here, since someone can spew
|
|
Packit |
8ea169 |
* to /var/log/messages before we read it in...
|
|
Packit |
8ea169 |
* We try to deal with it by reading READ_AHEAD extra.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
sz += READ_AHEAD;
|
|
Packit |
8ea169 |
char *buffer = xzalloc(sz);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
for (;;)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
int r = full_read(fd, buffer, sz-1);
|
|
Packit |
8ea169 |
if (r <= 0)
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
log_debug("Read %u bytes", r);
|
|
Packit |
8ea169 |
koops_extract_oopses(oops_list, buffer, r);
|
|
Packit |
8ea169 |
//TODO: rewind to last newline?
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(buffer);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int main(int argc, char **argv)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* I18n */
|
|
Packit |
8ea169 |
setlocale(LC_ALL, "");
|
|
Packit |
8ea169 |
#if ENABLE_NLS
|
|
Packit |
8ea169 |
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
Packit |
8ea169 |
textdomain(PACKAGE);
|
|
Packit |
8ea169 |
#endif
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
abrt_init(argv);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* Can't keep these strings/structs static: _() doesn't support that */
|
|
Packit |
8ea169 |
const char *program_usage_string = _(
|
|
Packit |
8ea169 |
"& [-vusoxm] [-d DIR]/[-D] [FILE]\n"
|
|
Packit |
8ea169 |
"\n"
|
|
Packit |
8ea169 |
"Extract oops from FILE (or standard input)"
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
enum {
|
|
Packit |
8ea169 |
OPT_v = 1 << 0,
|
|
Packit |
8ea169 |
OPT_s = 1 << 1,
|
|
Packit |
8ea169 |
OPT_o = 1 << 2,
|
|
Packit |
8ea169 |
OPT_d = 1 << 3,
|
|
Packit |
8ea169 |
OPT_D = 1 << 4,
|
|
Packit |
8ea169 |
OPT_u = 1 << 5,
|
|
Packit |
8ea169 |
OPT_x = 1 << 6,
|
|
Packit |
8ea169 |
OPT_t = 1 << 7,
|
|
Packit |
8ea169 |
OPT_m = 1 << 8,
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
char *problem_dir = NULL;
|
|
Packit |
8ea169 |
char *dump_location = NULL;
|
|
Packit |
8ea169 |
/* Keep enum above and order of options below in sync! */
|
|
Packit |
8ea169 |
struct options program_options[] = {
|
|
Packit |
8ea169 |
OPT__VERBOSE(&g_verbose),
|
|
Packit |
8ea169 |
OPT_BOOL( 's', NULL, NULL, _("Log to syslog")),
|
|
Packit |
8ea169 |
OPT_BOOL( 'o', NULL, NULL, _("Print found oopses on standard output")),
|
|
Packit |
8ea169 |
/* oopses don't contain any sensitive info, and even
|
|
Packit |
8ea169 |
* the old koops app was showing the oopses to all users
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")),
|
|
Packit |
8ea169 |
OPT_BOOL( 'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
|
|
Packit |
8ea169 |
OPT_STRING('u', NULL, &problem_dir, "PROBLEM", _("Save the extracted information in PROBLEM")),
|
|
Packit |
8ea169 |
OPT_BOOL( 'x', NULL, NULL, _("Make the problem directory world readable")),
|
|
Packit |
8ea169 |
OPT_BOOL( 't', NULL, NULL, _("Throttle problem directory creation to 1 per second")),
|
|
Packit |
8ea169 |
OPT_BOOL( 'm', NULL, NULL, _("Print search string(s) to stdout and exit")),
|
|
Packit |
8ea169 |
OPT_END()
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
export_abrt_envvars(0);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
msg_prefix = g_progname;
|
|
Packit |
8ea169 |
if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
logmode = LOGMODE_JOURNAL;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (opts & OPT_m)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *oops_string_filter_regex = abrt_oops_string_filter_regex();
|
|
Packit |
8ea169 |
if (oops_string_filter_regex)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
regex_t filter_re;
|
|
Packit |
8ea169 |
if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0)
|
|
Packit |
8ea169 |
perror_msg_and_die(_("Failed to compile regex"));
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
const regex_t *filter[] = { &filter_re, NULL };
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
koops_print_suspicious_strings_filtered(filter);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
regfree(&filter_re);
|
|
Packit |
8ea169 |
free(oops_string_filter_regex);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
koops_print_suspicious_strings();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return 1;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (opts & OPT_D)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (opts & OPT_d)
|
|
Packit |
8ea169 |
show_usage_and_die(program_usage_string, program_options);
|
|
Packit |
8ea169 |
load_abrt_conf();
|
|
Packit |
8ea169 |
dump_location = g_settings_dump_location;
|
|
Packit |
8ea169 |
g_settings_dump_location = NULL;
|
|
Packit |
8ea169 |
free_abrt_conf_data();
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
int oops_utils_flags = 0;
|
|
Packit |
8ea169 |
if ((opts & OPT_x))
|
|
Packit |
8ea169 |
oops_utils_flags |= ABRT_OOPS_WORLD_READABLE;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if ((opts & OPT_t))
|
|
Packit |
8ea169 |
oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if ((opts & OPT_o))
|
|
Packit |
8ea169 |
oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
argv += optind;
|
|
Packit |
8ea169 |
if (argv[0])
|
|
Packit |
8ea169 |
xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
GList *oops_list = NULL;
|
|
Packit |
8ea169 |
scan_syslog_file(&oops_list, STDIN_FILENO);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unsigned errors = 0;
|
|
Packit |
8ea169 |
if (opts & OPT_u)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_warning("Updating problem directory");
|
|
Packit |
8ea169 |
switch (g_list_length(oops_list))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
case 0:
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
error_msg(_("Can't update the problem: no oops found"));
|
|
Packit |
8ea169 |
errors = 1;
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
default:
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice(_("More oopses found: process only the first one"));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
/* falls trought */
|
|
Packit |
8ea169 |
case 1:
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0);
|
|
Packit |
8ea169 |
if (dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
abrt_oops_save_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
errors = abrt_oops_process_list(oops_list, dump_location,
|
|
Packit |
8ea169 |
ABRT_DUMP_OOPS_ANALYZER, oops_utils_flags);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
list_free_with_free(oops_list);
|
|
Packit |
8ea169 |
//oops_list = NULL;
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return errors;
|
|
Packit |
8ea169 |
}
|