text: #include <dirent.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <mntent.h>
  #include <pwd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/types.h>
  #include <time.h>
  #include <unistd.h>
  #include <string>
  
  #include <chrono>
  #include <map>
  #include <unordered_set>
  
  #include "aos/die.h"
  #include "aos/logging/binary_log_file.h"
  #include "aos/logging/implementations.h"
  #include "aos/logging/log_namer.h"
  #include "aos/time/time.h"
  #include "aos/configuration.h"
  #include "aos/init.h"
  #include "aos/ipc_lib/queue.h"
  
  namespace aos {
  namespace logging {
  namespace linux_code {
  namespace {
  
  int BinaryLogReaderMain() {
    InitNRT();
  
    const std::string file_name = GetLogName("aos_log");
    int fd = open(file_name.c_str(), O_SYNC | O_APPEND | O_RDWR | O_CREAT,
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if (fd == -1) {
      AOS_PLOG(FATAL, "opening file '%s' failed", file_name.c_str());
    }
    LogFileWriter writer(fd);
  
    RawQueue *queue = GetLoggingQueue();
  
    ::std::unordered_set<uint32_t> written_type_ids;
  
    while (true) {
      const LogMessage *const msg =
          static_cast<const LogMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
      if (msg == NULL) {
        // If we've emptied the queue, then wait for a bit before starting to read
        // again so the queue can buffer up some logs. This avoids lots of context
        // switches and mutex contention which happens if we're constantly reading
        // new messages as they come in.
        ::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
        continue;
      }
  
      const size_t raw_output_length =
          sizeof(LogFileMessageHeader) + msg->name_length + msg->message_length;
      size_t output_length = raw_output_length;
      LogFileMessageHeader *const output = writer.GetWritePosition(output_length);
      char *output_strings = reinterpret_cast<char *>(output) + sizeof(*output);
      output->name_size = msg->name_length;
      output->message_size = msg->message_length;
      output->source = msg->source;
      output->level = msg->level;
      output->time_sec = msg->seconds;
      output->time_nsec = msg->nseconds;
      output->sequence = msg->sequence;
      memcpy(output_strings, msg->name, msg->name_length);
  
      switch (msg->type) {
        case LogMessage::Type::kString:
          memcpy(output_strings + msg->name_length, msg->message,
                 msg->message_length);
          output->type = LogFileMessageHeader::MessageType::kString;
          break;
      }
  
      if (output->message_size - msg->message_length !=
          output_length - raw_output_length) {
        AOS_LOG(FATAL, "%zu != %zu\n", output->message_size - msg->message_length,
                output_length - raw_output_length);
      }
  
      futex_set(&output->marker);
  
      queue->FreeMessage(msg);
    }
  
    Cleanup();
    return 0;
  }
  
  }  // namespace
  }  // namespace linux_code
  }  // namespace logging
  }  // namespace aos
  
  int main() {
    return ::aos::logging::linux_code::BinaryLogReaderMain();
  }
  