summaryrefslogtreecommitdiffstats
path: root/lib/Plugins/KerneloopsScanner.cpp
blob: 3134d3429820f4d707cd3d07004b1302a171b355 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "abrtlib.h"

#include "KerneloopsScanner.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
#include "PluginSettings.h"

#include <assert.h>
//#include <stdlib.h>
//#include <string.h>
#include <syslog.h>
//#include <sys/stat.h>
#include <asm/unistd.h>


#define FILENAME_KERNELOOPS  "kerneloops"

void CKerneloopsScanner::Run(const std::string& pActionDir,
                             const std::string& pArgs)
{
    int cnt_FoundOopses;

    if (!m_bSysLogFileScanned)
    {
        cnt_FoundOopses = ScanSysLogFile(m_sSysLogFile.c_str(), 1);
        if (cnt_FoundOopses > 0) {
            SaveOopsToDebugDump();
            openlog("abrt", 0, LOG_KERN);
            syslog(LOG_WARNING, "Kerneloops: Reported %u kernel oopses to Abrt", cnt_FoundOopses);
            closelog();
        }
        m_bSysLogFileScanned = true;
    }
    cnt_FoundOopses = ScanDmesg();
    if (cnt_FoundOopses > 0)
        SaveOopsToDebugDump();
}

void CKerneloopsScanner::SaveOopsToDebugDump()
{
    comm_layer_inner_status("Creating kernel oops crash reports...");

    CDebugDump debugDump;
    char path[PATH_MAX];
    std::list<COops> oopsList;

    time_t t = time(NULL);

    oopsList = m_pSysLog.GetOopsList();
    m_pSysLog.ClearOopsList();
    while (!oopsList.empty())
    {
        snprintf(path, sizeof(path), "%s/kerneloops-%lu-%lu", DEBUG_DUMPS_DIR, (long)t, (long)oopsList.size());

        COops oops = oopsList.back();

        try
        {
            debugDump.Create(path, "0");
            debugDump.SaveText(FILENAME_ANALYZER, "Kerneloops");
            debugDump.SaveText(FILENAME_EXECUTABLE, "kernel");
            debugDump.SaveText(FILENAME_KERNEL, oops.m_sVersion);
            debugDump.SaveText(FILENAME_PACKAGE, "not_applicable");
            debugDump.SaveText(FILENAME_KERNELOOPS, oops.m_sData);
            debugDump.Close();
        }
        catch (CABRTException& e)
        {
            throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": " + e.what());
        }
        oopsList.pop_back();
    }
}

int CKerneloopsScanner::ScanDmesg()
{
    comm_layer_inner_debug("Scanning dmesg...");

    int cnt_FoundOopses;
    char *buffer;

    buffer = (char*)xzalloc(getpagesize()+1);

    syscall(__NR_syslog, 3, buffer, getpagesize());
    cnt_FoundOopses = m_pSysLog.ExtractOops(buffer, strlen(buffer), 0);
    free(buffer);

    return cnt_FoundOopses;
}

int CKerneloopsScanner::ScanSysLogFile(const char *filename, int issyslog)
{
    comm_layer_inner_debug("Scanning syslog...");

    char *buffer;
    struct stat statb;
    int fd;
    int cnt_FoundOopses;
    ssize_t sz;

    fd = open(filename, O_RDONLY);
    if (fd < 0)
        return 0;
    statb.st_size = 0; /* paranoia */
    if (fstat(fd, &statb) != 0 || statb.st_size < 1)
        return 0;

    /*
     * in theory there's a race here, since someone could spew
     * to /var/log/messages before we read it in... we try to
     * deal with it by reading at most 1023 bytes extra. If there's
     * more than that.. any oops will be in dmesg anyway.
     * Do not try to allocate an absurd amount of memory; ignore
     * older log messages because they are unlikely to have
     * sufficiently recent data to be useful.  32MB is more
     * than enough; it's not worth looping through more log
     * if the log is larger than that.
     */
    sz = statb.st_size + 1024;
    if (statb.st_size > (32*1024*1024 - 1024)) {
        xlseek(fd, -(32*1024*1024 - 1024), SEEK_END);
        sz = 32*1024*1024;
    }
    buffer = (char*)xzalloc(sz);
    sz = full_read(fd, buffer, sz);
    close(fd);

    cnt_FoundOopses = 0;
    if (sz > 0)
        cnt_FoundOopses = m_pSysLog.ExtractOops(buffer, sz, issyslog);
    free(buffer);

    return cnt_FoundOopses;
}

void CKerneloopsScanner::LoadSettings(const std::string& pPath)
{
    map_settings_t settings;
    plugin_load_settings(pPath, settings);

    if (settings.find("SysLogFile") != settings.end())
    {
        m_sSysLogFile = settings["SysLogFile"];
    }
}