Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / logread.cpp
... / ...
CommitLineData
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <stdio.h>
25
26#include <fstream>
27#include <stdexcept>
28
29#include <boost/scoped_array.hpp>
30
31#include "logread.hxx"
32
33using namespace std;
34
35/// Constructor
36logread::logread(string filename, bool _goto_end)
37{
38 this->filename = filename;
39 reset();
40
41 if (_goto_end)
42 goto_end();
43}
44
45/// Reset line state engine
46void logread::reset()
47{
48 logsize = 0;
49 logsize_old = 0;
50
51 line.clear();
52 line_complete = false;
53}
54
55/// Skip initial content. Useful when parsing /var/log/messages
56void logread::goto_end()
57{
58 struct stat my_stat;
59 if (stat(filename.c_str(), &my_stat) == 0) {
60 logsize = my_stat.st_size;
61 logsize_old = logsize;
62 }
63}
64
65/// Main read loop
66void logread::read()
67{
68 // check if size changed
69 if (check_changed()) {
70 if (logsize > logsize_old) {
71 string logChanges = getLogChanges();
72
73 do {
74 extractSingeLine (logChanges);
75 line_complete == true ? processLine() : processUnfinishedLine();
76 } while (!logChanges.empty());
77 } else
78 reset(); // file got truncated
79
80 logsize_old = logsize;
81 }
82}
83
84/// Check if file is modified
85bool logread::check_changed()
86{
87 bool changed = false;
88
89 struct stat my_stat;
90 if (stat(filename.c_str(), &my_stat) == 0
91 && my_stat.st_size != logsize)
92 {
93 logsize = my_stat.st_size;
94 changed = true;
95 }
96
97 return changed;
98}
99
100/// Get changed content since last read
101string logread::getLogChanges()
102{
103 // open logfile
104 ifstream log( filename.c_str(), ifstream::in );
105 if ( !log.is_open() )
106 return "";
107
108 // read logfile
109 int size = logsize-logsize_old;
110
111 boost::scoped_array<char> read_buffer( new char[ size + 1 ] );
112 log.seekg( logsize_old, fstream::beg );
113 if ( log.rdstate() != fstream::goodbit )
114 throw runtime_error("can't seek in file " + filename);
115 log.read( read_buffer.get(), size );
116 if ( log.rdstate() != fstream::goodbit )
117 throw runtime_error("error reading from file " + filename);
118 log.close();
119
120 read_buffer[size] = 0;
121 string changes( read_buffer.get() );
122
123 return changes;
124}
125
126/// Extract a single line from input buffer
127void logread::extractSingeLine(string &input)
128{
129 string::size_type rtn_pos, copysize;
130
131 // go to next line
132 if (line_complete) {
133 line_complete = false;
134 line.clear();
135 }
136
137 rtn_pos = input.find("\n", 0);
138
139 // complete line or even multi-line
140 if (rtn_pos != string::npos)
141 copysize = rtn_pos;
142 else
143 copysize = input.length();
144
145 line.append (input.c_str(), copysize);
146
147 // Erase data from the input buffer
148 if (rtn_pos == string::npos) // no return found
149 input.erase (0, copysize);
150 else {
151 // also erase the return
152 input.erase (0, copysize+1);
153 line_complete = true;
154 }
155}
156
157/** Short example
158
159#include <iostream>
160class logread_syslog : public logread
161{
162public:
163 logread_syslog() : logread("messages", false) {};
164
165 void processLine()
166 {
167 cout << "finished: " << line << endl;
168 }
169
170 void processUnfinishedLine()
171 {
172 cout << "unfinished: " << line << endl;
173 }
174};
175
176int main(void)
177{
178 logread_syslog messages;
179
180 while (1) {
181 messages.read();
182 sleep(1);
183 }
184
185 return 0;
186}
187*/