23 #include "bblogfile.h" 25 #include <core/exceptions/system.h> 26 #include <utils/misc/strndup.h> 27 #include <blackboard/internal/instance_factory.h> 33 # include <sys/endian.h> 34 #elif defined(__MACH__) && defined(__APPLE__) 35 # include <sys/_endian.h> 39 #include <arpa/inet.h> 40 #include <sys/types.h> 68 ctor(filename, do_sanity_check);
71 __instance_factory = NULL;
72 __interface = interface;
73 if ((strcmp(__interface->type(), __interface_type) != 0) ||
74 (strcmp(__interface->id(), __interface_id) != 0)) {
78 free(__interface_type);
80 throw Exception(
"Interface UID %s does not match expected %s:%s",
81 __interface->uid(), __interface_type, __interface_id);
85 __interface = __instance_factory->new_interface_instance(__interface_type,
103 ctor(filename, do_sanity_check);
105 __instance_factory = NULL;
111 BBLogFile::ctor(
const char *filename,
bool do_sanity_check)
113 __f = fopen(filename,
"r");
118 __filename = strdup(filename);
123 if (do_sanity_check) sanity_check();
127 free(__interface_type);
128 free(__interface_id);
133 __ifdata = malloc(__header->data_size);
139 if (__instance_factory) {
140 __instance_factory->delete_interface_instance(__interface);
141 delete __instance_factory;
148 free(__interface_type);
149 free(__interface_id);
158 BBLogFile::read_file_header()
162 if ((fread(&magic,
sizeof(uint32_t), 1, __f) == 1) &&
163 (fread(&version,
sizeof(uint32_t), 1, __f) == 1) ) {
164 if ( (ntohl(magic) == BBLOGGER_FILE_MAGIC) &&
165 (ntohl(version) == BBLOGGER_FILE_VERSION) ) {
171 throw Exception(
"File magic/version %X/%u does not match (expected %X/%u)",
172 ntohl(magic), ntohl(version),
173 BBLOGGER_FILE_VERSION, BBLOGGER_FILE_MAGIC);
176 throw Exception(__filename, errno,
"Failed to read magic/version from file");
179 __scenario = strndup(__header->scenario, BBLOG_SCENARIO_SIZE);
180 __interface_type = strndup(__header->interface_type, BBLOG_INTERFACE_TYPE_SIZE);
181 __interface_id = strndup(__header->interface_id, BBLOG_INTERFACE_ID_SIZE);
183 __start_time.set_time(__header->start_time_sec, __header->start_time_usec);
195 BBLogFile::sanity_check()
197 if (__header->num_data_items == 0) {
198 Exception e(
"File %s does not specify number of data items", __filename);
204 if (fstat(fileno(__f), &fs) != 0) {
205 Exception e(errno,
"Failed to stat file %s", __filename);
211 + __header->num_data_items * __header->data_size
213 if (expected_size != fs.st_size) {
214 Exception e(
"Size of file %s does not match expectation " 215 "(actual: %li, actual: %li)",
216 __filename, expected_size, (
long int)fs.st_size);
221 #if __BYTE_ORDER == __LITTLE_ENDIAN 222 if (__header->endianess == 1)
224 if (__header->endianess == 0)
227 Exception e(
"File %s has incompatible endianess", __filename);
242 if (fseek(__f, offset, SEEK_SET) != 0) {
243 throw Exception(errno,
"Cannot seek to index %u", index);
257 throw Exception(errno,
"Cannot reset file");
259 __entry_offset.set_time(0, 0);
271 if (getc(__f) == EOF) {
274 fseek(__f, -1, SEEK_CUR);
289 (fread(__ifdata, __header->data_size, 1, __f) == 1) ) {
291 __interface->set_from_chunk(__ifdata);
293 throw Exception(
"Cannot read interface data");
306 #if _POSIX_MAPPED_FILES 309 if (h == MAP_FAILED) {
310 throw Exception(errno,
"Failed to mmap log, not updating number of data items");
317 throw Exception(
"Cannot set number of entries, mmap not available.");
341 FILE *f = freopen(__filename,
"r+", __f);
343 throw Exception(
"Reopening file %s with new mode failed", __filename);
347 bool repair_done =
false;
349 Exception success(
"Successfully repaired file");
352 #if __BYTE_ORDER == __LITTLE_ENDIAN 353 if (__header->endianess == 1)
355 if (__header->endianess == 0)
358 throw Exception(
"File %s has incompatible endianess. Cannot repair.",
363 if (fstat(fileno(__f), &fs) != 0) {
364 throw Exception(errno,
"Failed to stat file %s", __filename);
369 size_t num_entries = all_entries_size / entry_size;
370 size_t extra_bytes = all_entries_size % entry_size;
372 if (extra_bytes != 0) {
373 success.
append(
"FIXING: errorneous bytes at end of file, " 374 "truncating by %zu b", extra_bytes);
375 if (ftruncate(fileno(__f), fs.st_size - extra_bytes) == -1) {
376 throw Exception(errno,
"Failed to truncate file %s", __filename);
378 all_entries_size -= extra_bytes;
380 if (fstat(fileno(__f), &fs) != 0) {
381 throw Exception(errno,
"Failed to update information of file %s " 382 "after truncate", __filename);
386 if (__header->num_data_items == 0) {
387 success.
append(
"FIXING: header of file %s has 0 data items, setting to %zu.",
388 __filename, num_entries);
389 set_num_entries(num_entries);
391 }
else if (__header->num_data_items != num_entries) {
392 success.
append(
"FIXING: header has %u data items, but expecting %zu, setting",
393 __header->num_data_items, num_entries);
394 set_num_entries(num_entries);
398 f = freopen(__filename,
"r", __f);
400 throw Exception(
"Reopening file %s with read-only mode failed", __filename);
417 char interface_hash[BBLOG_INTERFACE_HASH_SIZE * 2 + 1];
419 for (
unsigned int i = 0; i < BBLOG_INTERFACE_HASH_SIZE; ++i) {
420 snprintf(&interface_hash[i*2], 3,
"%02X", __header->interface_hash[i]);
424 if (fstat(fileno(__f), &fs) != 0) {
425 throw Exception(errno,
"Failed to get stat file");
429 "%sFile version: %-10u Endianess: %s Endian\n" 430 "%s# data items: %-10u Data size: %u bytes\n" 431 "%sHeader size: %zu bytes File size: %li bytes\n" 434 "%sInterface: %s::%s (%s)\n" 435 "%sStart time: %s\n",
436 line_prefix, ntohl(__header->file_version),
437 (__header->endianess == 1) ?
"Big" :
"Little",
438 line_prefix, __header->num_data_items, __header->data_size,
441 line_prefix, __scenario,
442 line_prefix, __interface_type, __interface_id, interface_hash,
443 line_prefix, __start_time.str());
455 fprintf(outf,
"Time Offset: %f\n", __entry_offset.in_sec());
458 for (i = __interface->fields(); i != __interface->fields_end(); ++i) {
460 if (i.get_length() > 1) {
461 if (asprintf(&typesize,
"%s[%zu]", i.get_typename(), i.get_length()) == -1) {
465 if (asprintf(&typesize,
"%s", i.get_typename()) == -1) {
469 fprintf(outf,
"%-16s %-18s: %s\n",
470 i.get_name(), typesize, i.get_value_string());
493 if ( (strcmp(interface->
type(), __interface_type) == 0) &&
494 (strcmp(interface->
id(), __interface_id) == 0) &&
495 (memcmp(interface->
hash(), __header->interface_hash,
496 __INTERFACE_HASH_SIZE) == 0) ) {
497 if (__instance_factory) {
498 __instance_factory->delete_interface_instance(__interface);
499 delete __instance_factory;
500 __instance_factory = NULL;
502 __interface = interface;
516 return __entry_offset;
526 return ntohl(__header->file_version);
536 return (__header->endianess == 1);
545 return __header->num_data_items;
565 return __interface_type;
575 return __interface_id;
586 return __header->interface_hash;
596 return __header->data_size;
618 long curpos = ftell(__f);
619 size_t fsize = file_size();
620 ssize_t sizediff = fsize - curpos;
623 throw Exception(
"File %s shrank while reading it", __filename);
626 return sizediff / entry_size;
636 if (fstat(fileno(__f), &fs) != 0) {
637 Exception e(errno,
"Failed to stat file %s", __filename);
Interface field iterator.
size_t file_size() const
Get file size.
BlackBoard instance factory.
File could not be opened.
bool is_big_endian() const
Check if file is big endian.
uint32_t data_size()
Get data size.
void rewind()
Rewind file to start.
Fawkes library namespace.
void set_num_entries(size_t num_entries)
Set number of entries.
const char * id() const
Get identifier of interface.
const char * interface_id() const
Get interface ID.
A class for handling time.
Base class for all Fawkes BlackBoard interfaces.
bool has_next()
Check if another entry is available.
unsigned char * interface_hash() const
Get interface hash.
void read_next()
Read next entry.
void print_entry(FILE *outf=stdout)
Print an entry.
const fawkes::Time & entry_offset() const
Get current entry offset.
BBLogFile(const char *filename, bool do_sanity_check)
Constructor.
const unsigned char * hash() const
Get interface hash.
uint32_t num_data_items() const
Get number of data items in file.
void set_interface(fawkes::Interface *interface)
Set the internal interface.
const char * type() const
Get type of interface.
Base class for exceptions in Fawkes.
void print_info(const char *line_prefix="", FILE *outf=stdout)
Print file meta info.
static void repair_file(const char *filename)
Repair file.
fawkes::Time & start_time()
Get start time.
void read_index(unsigned int index)
Read entry at particular index.
fawkes::Interface * interface()
Get interface instance.
const char * scenario() const
Get scenario identifier.
uint32_t file_version() const
Get file version.
unsigned int remaining_entries()
Get number of remaining entries.
const char * interface_type() const
Get interface type.
void set_type_id(const char *id)
Set exception type ID.
Class to easily access bblogger log files.
void append(const char *format,...)
Append messages to the message list.