23 #include "bblogfile.h" 25 #include <blackboard/internal/instance_factory.h> 26 #include <core/exceptions/system.h> 27 #include <utils/misc/strndup.h> 33 # include <sys/endian.h> 34 #elif defined(__MACH__) && defined(__APPLE__) 35 # include <sys/_endian.h> 39 #include <arpa/inet.h> 42 #include <sys/types.h> 68 ctor(filename, do_sanity_check);
71 interface_ = interface;
72 if ((strcmp(interface_->type(), interface_type_) != 0)
73 || (strcmp(interface_->id(), interface_id_) != 0)) {
77 std::string interface_type(interface_type_);
78 std::string interface_id(interface_id_);
79 free(interface_type_);
81 throw Exception(
"Interface UID %s does not match expected %s:%s",
83 interface_type.c_str(),
84 interface_id.c_str());
88 interface_ = instance_factory_->new_interface_instance(interface_type_, interface_id_);
104 ctor(filename, do_sanity_check);
110 BBLogFile::ctor(
const char *filename,
bool do_sanity_check)
112 f_ = fopen(filename,
"r");
117 filename_ = strdup(filename);
127 free(interface_type_);
133 ifdata_ = malloc(header_->data_size);
139 if (instance_factory_) {
140 instance_factory_->delete_interface_instance(interface_);
141 instance_factory_.reset();
148 free(interface_type_);
157 BBLogFile::read_file_header()
161 if ((fread(&magic,
sizeof(uint32_t), 1, f_) == 1)
162 && (fread(&version,
sizeof(uint32_t), 1, f_) == 1)) {
163 if ((ntohl(magic) == BBLOGGER_FILE_MAGIC) && (ntohl(version) == BBLOGGER_FILE_VERSION)) {
169 throw Exception(
"File magic/version %X/%u does not match (expected %X/%u)",
172 BBLOGGER_FILE_VERSION,
173 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);
194 BBLogFile::sanity_check()
196 if (header_->num_data_items == 0) {
197 Exception e(
"File %s does not specify number of data items", filename_);
198 e.set_type_id(
"bblogfile-num-items-zero");
203 if (fstat(fileno(f_), &fs) != 0) {
204 Exception e(errno,
"Failed to stat file %s", filename_);
205 e.set_type_id(
"bblogfile-stat-failed");
210 + (
size_t)header_->num_data_items * header_->data_size
212 if (expected_size != fs.st_size) {
213 Exception e(
"Size of file %s does not match expectation " 214 "(actual: %li, actual: %li)",
217 (
long int)fs.st_size);
218 e.set_type_id(
"bblogfile-file-size-mismatch");
222 #if BYTE_ORDER_ == LITTLE_ENDIAN_ 223 if (header_->endianess == 1)
225 if (header_->endianess == 0)
228 Exception e(
"File %s has incompatible endianess", filename_);
229 e.set_type_id(
"bblogfile-endianess-mismatch");
243 if (fseek(f_, offset, SEEK_SET) != 0) {
244 throw Exception(errno,
"Cannot seek to index %u", index);
257 throw Exception(errno,
"Cannot reset file");
259 entry_offset_.set_time(0, 0);
270 if (getc(f_) == EOF) {
273 fseek(f_, -1, SEEK_CUR);
288 && (fread(ifdata_, header_->data_size, 1, f_) == 1)) {
290 interface_->set_from_chunk(ifdata_);
292 throw Exception(
"Cannot read interface data");
304 #if _POSIX_MAPPED_FILES 305 void *h = mmap(NULL,
sizeof(
bblog_file_header), PROT_WRITE, MAP_SHARED, fileno(f_), 0);
306 if (h == MAP_FAILED) {
307 throw Exception(errno,
"Failed to mmap log, not updating number of data items");
314 throw Exception(
"Cannot set number of entries, mmap not available.");
336 FILE *f = freopen(filename_,
"r+", f_);
338 throw Exception(
"Reopening file %s with new mode failed", filename_);
342 bool repair_done =
false;
344 Exception success(
"Successfully repaired file");
345 success.set_type_id(
"repair-success");
347 #if BYTE_ORDER_ == LITTLE_ENDIAN_ 348 if (header_->endianess == 1)
350 if (header_->endianess == 0)
353 throw Exception(
"File %s has incompatible endianess. Cannot repair.", filename_);
357 if (fstat(fileno(f_), &fs) != 0) {
358 throw Exception(errno,
"Failed to stat file %s", filename_);
363 size_t num_entries = all_entries_size / entry_size;
364 size_t extra_bytes = all_entries_size % entry_size;
366 if (extra_bytes != 0) {
367 success.append(
"FIXING: errorneous bytes at end of file, " 368 "truncating by %zu b",
370 if (ftruncate(fileno(f_), fs.st_size - extra_bytes) == -1) {
371 throw Exception(errno,
"Failed to truncate file %s", filename_);
375 if (fstat(fileno(f_), &fs) != 0) {
377 "Failed to update information of file %s " 383 if (header_->num_data_items == 0) {
384 success.append(
"FIXING: header of file %s has 0 data items, setting to %zu.",
387 set_num_entries(num_entries);
389 }
else if (header_->num_data_items != num_entries) {
390 success.append(
"FIXING: header has %u data items, but expecting %zu, setting",
391 header_->num_data_items,
393 set_num_entries(num_entries);
397 f = freopen(filename_,
"r", f_);
399 throw Exception(
"Reopening file %s with read-only mode failed", filename_);
415 char interface_hash[BBLOG_INTERFACE_HASH_SIZE * 2 + 1];
417 for (
unsigned int i = 0; i < BBLOG_INTERFACE_HASH_SIZE; ++i) {
418 snprintf(&interface_hash[i * 2], 3,
"%02X", header_->interface_hash[i]);
422 if (fstat(fileno(f_), &fs) != 0) {
423 throw Exception(errno,
"Failed to get stat file");
427 "%sFile version: %-10u Endianess: %s Endian\n" 428 "%s# data items: %-10u Data size: %u bytes\n" 429 "%sHeader size: %zu bytes File size: %li bytes\n" 432 "%sInterface: %s::%s (%s)\n" 433 "%sStart time: %s\n",
435 ntohl(header_->file_version),
436 (header_->endianess == 1) ?
"Big" :
"Little",
438 header_->num_data_items,
442 (
long int)fs.st_size,
461 fprintf(outf,
"Time Offset: %f\n", entry_offset_.in_sec());
464 for (i = interface_->fields(); i != interface_->fields_end(); ++i) {
466 if (i.get_length() > 1) {
467 if (asprintf(&typesize,
"%s[%zu]", i.get_typename(), i.get_length()) == -1) {
471 if (asprintf(&typesize,
"%s", i.get_typename()) == -1) {
475 fprintf(outf,
"%-16s %-18s: %s\n", i.get_name(), typesize, i.get_value_string());
496 if ((strcmp(interface->
type(), interface_type_) == 0)
497 && (strcmp(interface->
id(), interface_id_) == 0)
498 && (memcmp(interface->
hash(), header_->interface_hash, INTERFACE_HASH_SIZE_) == 0)) {
499 if (instance_factory_) {
500 instance_factory_->delete_interface_instance(interface_);
501 instance_factory_.reset();
503 interface_ = interface;
516 return entry_offset_;
525 return ntohl(header_->file_version);
534 return (header_->endianess == 1);
543 return header_->num_data_items;
561 return interface_type_;
570 return interface_id_;
580 return header_->interface_hash;
589 return header_->data_size;
609 long curpos = ftell(f_);
610 size_t fsize = file_size();
611 ssize_t sizediff = fsize - curpos;
614 throw Exception(
"File %s shrank while reading it", filename_);
617 return sizediff / entry_size;
627 if (fstat(fileno(f_), &fs) != 0) {
628 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.