Blame src/plugins/abrt-dump-oops.c

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
}