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>
68 ctor(filename, do_sanity_check);
72 if ((strcmp(interface_->
type(), interface_type_) != 0)
73 || (strcmp(interface_->
id(), interface_id_) != 0)) {
79 free(interface_type_);
81 throw Exception(
"Interface UID %s does not match expected %s:%s",
88 interface_ = instance_factory_->new_interface_instance(interface_type_, interface_id_);
104 ctor(filename, do_sanity_check);
110BBLogFile::ctor(
const char *filename,
bool do_sanity_check)
112 f_ = fopen(filename,
"r");
117 filename_ = strdup(filename);
127 free(interface_type_);
139 if (instance_factory_) {
140 instance_factory_->delete_interface_instance(interface_);
141 instance_factory_.reset();
148 free(interface_type_);
157BBLogFile::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);
194BBLogFile::sanity_check()
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");
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_
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");
270 if (getc(f_) == EOF) {
273 fseek(f_, -1, SEEK_CUR);
288 && (fread(ifdata_, header_->
data_size, 1, f_) == 1)) {
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_
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 "
384 success.append(
"FIXING: header of file %s has 0 data items, setting to %zu.",
390 success.append(
"FIXING: header has %u data items, but expecting %zu, setting",
397 f = freopen(filename_,
"r", f_);
399 throw Exception(
"Reopening file %s with read-only mode failed", filename_);
417 for (
unsigned int i = 0; i < BBLOG_INTERFACE_HASH_SIZE; ++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",
436 (header_->
endianess == 1) ?
"Big" :
"Little",
442 (
long int)fs.st_size,
461 fprintf(outf,
"Time Offset: %f\n", entry_offset_.
in_sec());
471 if (asprintf(&typesize,
"%s", i.
get_typename()) == -1) {
499 if (instance_factory_) {
500 instance_factory_->delete_interface_instance(interface_);
501 instance_factory_.reset();
516 return entry_offset_;
561 return interface_type_;
570 return interface_id_;
609 long curpos = ftell(f_);
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_);
Class to easily access bblogger log files.
void set_num_entries(size_t num_entries)
Set number of entries.
uint32_t num_data_items() const
Get number of data items in file.
uint32_t file_version() const
Get file version.
bool is_big_endian() const
Check if file is big endian.
const char * interface_type() const
Get interface type.
bool has_next()
Check if another entry is available.
void set_interface(fawkes::Interface *interface)
Set the internal interface.
void read_next()
Read next entry.
const char * interface_id() const
Get interface ID.
const fawkes::Time & entry_offset() const
Get current entry offset.
static void repair_file(const char *filename)
Repair file.
fawkes::Interface * interface()
Get interface instance.
fawkes::Time & start_time()
Get start time.
void rewind()
Rewind file to start.
BBLogFile(const char *filename, bool do_sanity_check)
Constructor.
void read_index(unsigned int index)
Read entry at particular index.
unsigned char * interface_hash() const
Get interface hash.
void print_info(const char *line_prefix="", FILE *outf=stdout)
Print file meta info.
size_t file_size() const
Get file size.
const char * scenario() const
Get scenario identifier.
uint32_t data_size()
Get data size.
unsigned int remaining_entries()
Get number of remaining entries.
void print_entry(FILE *outf=stdout)
Print an entry.
BlackBoard instance factory.
File could not be opened.
Base class for exceptions in Fawkes.
void set_type_id(const char *id)
Set exception type ID.
Interface field iterator.
size_t get_length() const
Get length of current field.
const char * get_name() const
Get name of current field.
const char * get_value_string(const char *array_sep=", ")
Get value of current field as string.
const char * get_typename() const
Get type of current field as string.
Base class for all Fawkes BlackBoard interfaces.
const char * type() const
Get type of interface.
InterfaceFieldIterator fields_end()
Invalid iterator.
const unsigned char * hash() const
Get interface hash.
const char * id() const
Get identifier of interface.
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
void set_from_chunk(void *chunk)
Set from a raw data chunk.
const char * uid() const
Get unique identifier of interface.
A class for handling time.
double in_sec() const
Convet time to seconds.
const char * str(bool utc=false) const
Output function.
void set_time(const timeval *tv)
Sets the time.
Fawkes library namespace.