xref: /openbmc/phosphor-event/message.cpp (revision acdc2a90)
1 #include <iostream>
2 #include <fstream>
3 #include <iomanip>
4 #include <cstdint>
5 #include <string>
6 #include <sys/types.h>
7 #include <dirent.h>
8 #include <sstream>
9 #include <sys/stat.h>
10 #include <cstring>
11 #include "message.hpp"
12 #include <time.h>
13 #include <stddef.h>
14 #include <cstdio>
15 #include <syslog.h>
16 
17 const uint32_t g_eyecatcher = 0x4F424D43; // OBMC
18 const uint16_t g_version    = 1;
19 
20 struct logheader_t {
21 	uint32_t eyecatcher;
22 	uint16_t version;
23 	uint16_t logid;
24 	time_t   timestamp;
25 	uint16_t detailsoffset;
26 	uint16_t messagelen;
27 	uint16_t severitylen;
28 	uint16_t associationlen;
29 	uint16_t reportedbylen;
30 	uint16_t debugdatalen;
31 };
32 
33 size_t get_file_size(string fn);
34 
35 
event_manager(string path,size_t reqmaxsize,uint16_t reqmaxlogs)36 event_manager::event_manager(string path, size_t reqmaxsize, uint16_t reqmaxlogs)
37 {
38 	uint16_t x;
39 	eventpath = path;
40 	latestid = 0;
41 	dirp = NULL;
42 	logcount = 0;
43 	maxsize = -1;
44 	maxlogs = -1;
45 	currentsize = get_managed_size();
46 
47 	if (reqmaxsize)
48 		maxsize = reqmaxsize;
49 
50 	if (reqmaxlogs)
51 		maxlogs = reqmaxlogs;
52 
53 	// examine the files being managed and advance latestid to that value
54 	while ( (x = next_log()) ) {
55 		logcount++;
56 		if ( x > latestid )
57 			latestid = x;
58 	}
59 
60 	return;
61 }
62 
~event_manager()63 event_manager::~event_manager()
64 {
65 	if (dirp)
66 		closedir(dirp);
67 
68 	return;
69 }
70 
71 
is_logid_a_log(uint16_t logid)72 bool event_manager::is_logid_a_log(uint16_t logid)
73 {
74 	std::ostringstream buffer;
75 	buffer  << int(logid);
76 	return is_file_a_log(buffer.str());
77 }
78 
79 
is_file_a_log(string str)80 bool event_manager::is_file_a_log(string str)
81 {
82 	std::ostringstream buffer;
83 	ifstream f;
84 	logheader_t hdr;
85 
86 	if (!str.compare("."))
87 		return 0;
88 
89 	if (!str.compare(".."))
90 		return 0;
91 
92 	buffer << eventpath << "/" << str;
93 
94 	f.open( buffer.str(), ios::binary);
95 
96 	if (!f.good()) {
97 		f.close();
98 		return 0;
99 	}
100 
101 	f.read((char*)&hdr, sizeof(hdr));
102 	f.close();
103 
104 	if (hdr.eyecatcher != g_eyecatcher)
105 		return 0;
106 
107 	return 1;
108 }
109 
log_count(void)110 uint16_t event_manager::log_count(void)
111 {
112 	return logcount;
113 }
latest_log_id(void)114 uint16_t event_manager::latest_log_id(void)
115 {
116 	return latestid;
117 }
new_log_id(void)118 uint16_t event_manager::new_log_id(void)
119 {
120 	return ++latestid;
121 }
next_log_refresh(void)122 void event_manager::next_log_refresh(void)
123 {
124 	if (dirp) {
125 		closedir(dirp);
126 		dirp = NULL;
127 	}
128 
129 	return;
130 }
131 
next_log(void)132 uint16_t event_manager::next_log(void)
133 {
134 	std::ostringstream buffer;
135 	struct dirent *ent;
136 	uint16_t id;
137 
138 	if (dirp == NULL)
139 		dirp = opendir(eventpath.c_str());
140 
141 	if (dirp) {
142 		do {
143 			ent = readdir(dirp);
144 
145 			if (ent == NULL)
146 				break;
147 
148 			string str(ent->d_name);
149 
150 			if (is_file_a_log(str)) {
151 				id = (uint16_t) atoi(str.c_str());
152 				break;
153 			}
154 
155 		} while( 1 );
156 	} else {
157 		cerr << "Error opening directory " << eventpath << endl;
158 		ent = NULL;
159 		id = 0;
160 	}
161 
162 	if (ent == NULL) {
163 		closedir(dirp);
164 		dirp = NULL;
165 	}
166 
167 	return  ((ent == NULL) ? 0 : id);
168 }
169 
170 
create(event_record_t * rec)171 uint16_t event_manager::create(event_record_t *rec)
172 {
173 	rec->logid = new_log_id();
174 	rec->timestamp = time(NULL);
175 
176 	return create_log_event(rec);
177 }
178 
getlen(const char * s)179 inline uint16_t getlen(const char *s)
180 {
181 	return (uint16_t) (1 + strlen(s));
182 }
183 
184 
185 /* If everything is working correctly, return file size, */
186 /* Otherwise return 0 */
get_file_size(string fn)187 size_t get_file_size(string fn)
188 {
189 	struct stat f_stat;
190 	int r = -1;
191 
192 	r = stat(fn.c_str(), &f_stat);
193 
194 	if (r < 0) {
195 		fprintf(stderr, "Error get_file_size() for %s, %s\n",
196 				fn.c_str(),
197 				strerror(errno));
198 		return 0;
199 	}
200 
201 	return (f_stat.st_size);
202 }
203 
204 
get_managed_size(void)205 size_t event_manager::get_managed_size(void)
206 {
207 	DIR *dirp;
208 	std::ostringstream buffer;
209 	struct dirent *ent;
210 	ifstream f;
211 
212 	size_t db_size = 0;
213 
214 	dirp = opendir(eventpath.c_str());
215 
216 	if (dirp) {
217 		while ( (ent = readdir(dirp)) != NULL ) {
218 
219 			string str(ent->d_name);
220 
221 			if (is_file_a_log(str)) {
222 				buffer.str("");
223 				buffer << eventpath << "/" << str.c_str();
224 				db_size += get_file_size(buffer.str());
225 			}
226 		}
227 	}
228 
229 	closedir(dirp);
230 
231 	return (db_size);
232 }
233 
create_log_event(event_record_t * rec)234 uint16_t event_manager::create_log_event(event_record_t *rec)
235 {
236 	std::ostringstream buffer;
237 	ofstream myfile;
238 	logheader_t hdr = {0};
239 	size_t event_size=0;
240 
241 	buffer << eventpath << "/" << int(rec->logid) ;
242 
243 	hdr.eyecatcher     = g_eyecatcher;
244 	hdr.version        = g_version;
245 	hdr.logid          = rec->logid;
246 	hdr.timestamp      = rec->timestamp;
247 	hdr.detailsoffset  = offsetof(logheader_t, messagelen);
248 	hdr.messagelen     = getlen(rec->message);
249 	hdr.severitylen    = getlen(rec->severity);
250 	hdr.associationlen = getlen(rec->association);
251 	hdr.reportedbylen  = getlen(rec->reportedby);
252 	hdr.debugdatalen   = rec->n;
253 
254 	event_size = sizeof(logheader_t) + \
255 			hdr.messagelen     + \
256 			hdr.severitylen    + \
257 			hdr.associationlen + \
258 			hdr.reportedbylen  + \
259 			hdr.debugdatalen;
260 
261 	if((event_size + currentsize)  >= maxsize) {
262 		syslog(LOG_ERR, "event logger reached maximum capacity, event not logged");
263 		rec->logid = 0;
264 
265 	} else if (logcount >= maxlogs) {
266 		syslog(LOG_ERR, "event logger reached maximum log events, event not logged");
267 		rec->logid = 0;
268 
269 	} else {
270 		currentsize += event_size;
271 		myfile.open(buffer.str() , ios::out|ios::binary);
272 		myfile.write((char*) &hdr, sizeof(hdr));
273 		myfile.write((char*) rec->message, hdr.messagelen);
274 		myfile.write((char*) rec->severity, hdr.severitylen);
275 		myfile.write((char*) rec->association, hdr.associationlen);
276 		myfile.write((char*) rec->reportedby, hdr.reportedbylen);
277 		myfile.write((char*) rec->p, hdr.debugdatalen);
278 		myfile.close();
279 
280 		if (is_logid_a_log(rec->logid)) {
281 			logcount++;
282 		} else {
283 			cout << "Warning: Event not logged, failed to store data" << endl;
284 			rec->logid = 0;
285 		}
286 	}
287 
288 	return rec->logid;
289 }
290 
open(uint16_t logid,event_record_t ** rec)291 int event_manager::open(uint16_t logid, event_record_t **rec)
292 {
293 	std::ostringstream buffer;
294 	ifstream f;
295 	logheader_t hdr;
296 
297 	buffer << eventpath << "/" << int(logid);
298 
299 	f.open( buffer.str(), ios::binary );
300 
301 	if (!f.good()) {
302 		return 0;
303 	}
304 
305 	*rec = new event_record_t;
306 
307 	f.read((char*)&hdr, sizeof(hdr));
308 
309 	(*rec)->logid     = hdr.logid;
310 	(*rec)->timestamp = hdr.timestamp;
311 
312 
313 	(*rec)->message = new char[hdr.messagelen];
314 	f.read((*rec)->message, hdr.messagelen);
315 
316 	(*rec)->severity = new char[hdr.severitylen];
317 	f.read((*rec)->severity, hdr.severitylen);
318 
319 	(*rec)->association = new char[hdr.associationlen];
320 	f.read((*rec)->association, hdr.associationlen);
321 
322 	(*rec)->reportedby = new char[hdr.reportedbylen];
323 	f.read((*rec)->reportedby, hdr.reportedbylen);
324 
325 	(*rec)->p = new uint8_t[hdr.debugdatalen];
326 	f.read((char*)(*rec)->p, hdr.debugdatalen);
327 	(*rec)->n = hdr.debugdatalen;
328 
329 
330 	f.close();
331 	return logid;
332 }
333 
close(event_record_t * rec)334 void event_manager::close(event_record_t *rec)
335 {
336 	delete[] rec->message;
337 	delete[] rec->severity;
338 	delete[] rec->association;
339 	delete[] rec->reportedby;
340 	delete[] rec->p;
341 	delete rec;
342 
343 	return ;
344 }
345 
remove(uint16_t logid)346 int event_manager::remove(uint16_t logid)
347 {
348 	std::stringstream buffer;
349 	string s;
350 	size_t event_size;
351 
352 	buffer << eventpath << "/" << int(logid);
353 
354 	s = buffer.str();
355 
356 	event_size = get_file_size(s);
357 	std::remove(s.c_str());
358 
359 	/* If everything is working correctly deleting all the logs would */
360 	/* result in currentsize being zero.  But  since size_t is unsigned */
361 	/* it's kind of dangerous to  assume life happens perfectly */
362 	if (currentsize < event_size)
363 		currentsize = 0;
364 	else
365 		currentsize -= event_size;
366 
367 	if (logcount > 0)
368 		logcount--;
369 
370 	return 0;
371 }
372