moved the logging-related executables into an intelligent location
diff --git a/aos/linux_code/logging/binary_log_file.h b/aos/linux_code/logging/binary_log_file.h
new file mode 100644
index 0000000..6ce20cd
--- /dev/null
+++ b/aos/linux_code/logging/binary_log_file.h
@@ -0,0 +1,199 @@
+#ifndef AOS_LINUX_CODE_LOGGING_BINARY_LOG_FILE_H_
+#define AOS_LINUX_CODE_LOGGING_BINARY_LOG_FILE_H_
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include "aos/common/logging/logging_impl.h"
+
+namespace aos {
+namespace logging {
+
+// File format: {
+//   LogFileMessageHeader header;
+//   char *name;  // of the process that wrote the message
+//   char *message;
+// } not crossing kPageSize boundaries into the file.
+//
+// Field sizes designed to fit the various values from LogMessage even on
+// other machines (hopefully) because they're baked into the files.
+//
+// A lot of the fields don't have comments because they're the same as the
+// identically named fields in LogMessage.
+struct __attribute__((aligned)) LogFileMessageHeader {
+  // gets futex_set once this one has been written
+  // for readers keeping up with a live writer
+  //
+  // gets initialized to 0 by ftruncate
+  // 
+  // there will be something here after the last log on a "page" set to 2
+  // (by the futex_set) to indicate that the next log is on the next page
+  mutex marker;
+  static_assert(sizeof(marker) == 4, "mutex changed size!");
+  log_level level;
+  static_assert(sizeof(level) == 1, "log_level changed size!");
+
+  uint32_t time_sec;
+  static_assert(sizeof(time_sec) >= sizeof(LogMessage::seconds),
+                "tv_sec won't fit");
+  uint32_t time_nsec;
+  static_assert(sizeof(time_nsec) >= sizeof(LogMessage::nseconds),
+                "tv_nsec won't fit");
+
+  int32_t source;
+  static_assert(sizeof(source) >= sizeof(LogMessage::source), "PIDs won't fit");
+  uint16_t sequence;
+  static_assert(sizeof(sequence) == sizeof(LogMessage::sequence),
+                "something changed");
+
+  // both including the terminating '\0'
+  uint32_t name_size;
+  uint32_t message_size;
+};
+static_assert(std::is_pod<LogFileMessageHeader>::value,
+              "LogFileMessageHeader will to get dumped to a file");
+
+// Handles the mmapping and munmapping for reading and writing log files.
+class LogFileAccessor {
+ private:
+  // The size of the chunks that get mmaped/munmapped together. Large enough so
+  // that not too much space is wasted and it's hopefully bigger than and a
+  // multiple of the system page size but small enough so that really large chunks
+  // of memory don't have to get mapped at the same time.
+  static const size_t kPageSize = 32768;
+  // What to align messages to. Necessary for futexes to work.
+  static const size_t kAlignment = 64;
+  static_assert(kAlignment >= __alignof__(mutex), "futexes will complain");
+
+  const int fd_;
+  const bool writable_;
+
+  off_t offset_; // into the file. will be aligned to kPageSize
+  char *current_;
+  size_t position_;
+
+  inline unsigned long SystemPageSize() {
+    static unsigned long r = sysconf(_SC_PAGESIZE);
+    return r;
+  }
+  void MapNextPage() {
+    if (writable_) {
+      if (ftruncate(fd_, offset_ + kPageSize) == -1) {
+        fprintf(stderr, "ftruncate(%d, %zd) failed with %d: %s. aborting\n",
+                fd_, kPageSize, errno, strerror(errno));
+        printf("see stderr\n");
+        abort();
+      }
+    }
+    current_ = static_cast<char *>(mmap(NULL, kPageSize,
+                                        PROT_READ | (writable_ ? PROT_WRITE : 0),
+                                        MAP_SHARED, fd_, offset_));
+    if (current_ == MAP_FAILED) {
+      fprintf(stderr, "mmap(NULL, %zd, PROT_READ | PROT_WRITE, MAP_SHARED, %d, %jd)"
+              " failed with %d: %s. aborting\n", kPageSize, fd_,
+              static_cast<intmax_t>(offset_), errno, strerror(errno));
+      printf("see stderr\n");
+      abort();
+    }
+    offset_ += kPageSize;
+  }
+  void Unmap(void *location) {
+    if (munmap(location, kPageSize) == -1) {
+      fprintf(stderr, "munmap(%p, %zd) failed with %d: %s. aborting\n",
+              location, kPageSize, errno, strerror(errno));
+      printf("see stderr\n");
+      abort();
+    }
+  }
+ public:
+  LogFileAccessor(int fd, bool writable) : fd_(fd), writable_(writable),
+    offset_(0), current_(0), position_(0) {
+    // check to make sure that mmap will allow mmaping in chunks of kPageSize
+    if (SystemPageSize() > kPageSize || (kPageSize % SystemPageSize()) != 0) {
+      fprintf(stderr, "LogFileCommon: system page size (%lu)"
+              " not compatible with kPageSize (%zd). aborting\n",
+              SystemPageSize(), kPageSize);
+      printf("see stderr\n");
+      abort();
+    }
+
+    MapNextPage();
+  }
+  // message_size should be the total number of bytes needed for the message
+  LogFileMessageHeader *GetWritePosition(size_t message_size) {
+    if (position_ + message_size + (kAlignment - (message_size % kAlignment)) +
+        sizeof(mutex) > kPageSize) {
+      char *const temp = current_;
+      MapNextPage();
+      if (futex_set_value(static_cast<mutex *>(static_cast<void *>(
+                      &temp[position_])), 2) == -1) {
+        fprintf(stderr,
+                "LogFileCommon: futex_set_value(%p, 2) failed with %d: %s."
+                " readers will hang\n",
+                &temp[position_], errno, strerror(errno));
+      }
+      Unmap(temp);
+      position_ = 0;
+    }
+    LogFileMessageHeader *const r = static_cast<LogFileMessageHeader *>(
+        static_cast<void *>(&current_[position_]));
+    position_ += message_size;
+    // keep it aligned for next time
+    position_ += kAlignment - (position_ % kAlignment);
+    return r;
+  }
+  // may only return NULL if wait is false
+  const LogFileMessageHeader *ReadNextMessage(bool wait) {
+    LogFileMessageHeader *r;
+    do {
+      r = static_cast<LogFileMessageHeader *>(
+          static_cast<void *>(&current_[position_]));
+      if (wait) {
+        if (futex_wait(&r->marker) != 0) continue;
+      }
+      if (r->marker == 2) {
+        Unmap(current_);
+        MapNextPage();
+        position_ = 0;
+        r = static_cast<LogFileMessageHeader *>(static_cast<void *>(current_));
+      }
+    } while (wait && r->marker == 0);
+    if (r->marker == 0) {
+      return NULL;
+    }
+    position_ += sizeof(LogFileMessageHeader) + r->name_size + r->message_size;
+    // keep it aligned for next time
+    position_ += kAlignment - (position_ % kAlignment);
+    return r;
+  }
+
+  // asynchronously syncs all open mappings
+  void Sync() {
+    msync(current_, kPageSize, MS_ASYNC | MS_INVALIDATE);
+  }
+
+  void MoveToEnd() {
+    Unmap(current_);
+    struct stat info;
+    if (fstat(fd_, &info) == -1) {
+      fprintf(stderr, "LOgFileCommon: fstat(%d, %p) failed with %d: %s\n",
+              fd_, &info, errno, strerror(errno));
+      printf("see stderr\n");
+      abort();
+    }
+    offset_ = info.st_size - kPageSize;
+    MapNextPage();
+  }
+};
+
+}  // namespace logging
+}  // namespace aos
+
+#endif  // AOS_LINUX_CODE_LOGGING_BINARY_LOG_FILE_H_
diff --git a/aos/linux_code/logging/binary_log_writer.cc b/aos/linux_code/logging/binary_log_writer.cc
new file mode 100644
index 0000000..48e9cf1
--- /dev/null
+++ b/aos/linux_code/logging/binary_log_writer.cc
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <fcntl.h>
+
+#include <map>
+
+#include "aos/linux_code/logging/linux_logging.h"
+#include "aos/linux_code/logging/binary_log_file.h"
+#include "aos/linux_code/init.h"
+#include "aos/linux_code/configuration.h"
+
+namespace aos {
+namespace logging {
+namespace linux_code {
+namespace {
+
+int BinaryLogReaderMain() {
+  InitNRT();
+
+  const char *folder = configuration::GetLoggingDirectory();
+  if (access(folder, R_OK | W_OK) == -1) {
+    LOG(FATAL, "folder '%s' does not exist. please create it\n", folder);
+  }
+  LOG(INFO, "logging to folder '%s'\n", folder);
+
+  const time_t t = time(NULL);
+  char *tmp;
+  if (asprintf(&tmp, "%s/aos_log-%jd", folder, static_cast<uintmax_t>(t)) ==
+      -1) {
+    fprintf(stderr,
+            "BinaryLogReader: couldn't create final name because of %d (%s)."
+            " exiting\n", errno, strerror(errno));
+    return EXIT_FAILURE;
+  }
+  char *tmp2;
+  if (asprintf(&tmp2, "%s/aos_log-current", folder) == -1) {
+    fprintf(stderr,
+            "BinaryLogReader: couldn't create symlink name because of %d (%s)."
+            " not creating current symlink\n", errno, strerror(errno));
+  } else {
+    if (unlink(tmp2) == -1 && (errno != EROFS && errno != ENOENT)) {
+      fprintf(stderr,
+              "BinaryLogReader: warning: unlink('%s') failed"
+              " because of %d (%s)\n",
+              tmp2, errno, strerror(errno));
+    }
+    if (symlink(tmp, tmp2) == -1) {
+      fprintf(stderr, "BinaryLogReader: warning: symlink('%s', '%s') failed"
+              " because of %d (%s)\n", tmp, tmp2, errno, strerror(errno));
+    }
+    free(tmp2);
+  }
+  int fd = open(tmp, O_SYNC | O_APPEND | O_RDWR | O_CREAT,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+  free(tmp);
+  if (fd == -1) {
+    fprintf(stderr,
+            "BinaryLogReader: couldn't open file '%s' because of %d (%s)."
+            " exiting\n", tmp, errno, strerror(errno));
+    return EXIT_FAILURE;
+  }
+  LogFileAccessor writer(fd, true);
+
+  struct timespec timespec;
+  time_t last_sec = 0;
+  while (true) {
+    clock_gettime(CLOCK_MONOTONIC, &timespec);
+    if (last_sec != timespec.tv_sec) {
+      LOG(INFO, "msyncing output\n");
+      last_sec = timespec.tv_sec;
+      writer.Sync();
+    }
+
+    const LogMessage *const msg = ReadNext();
+    if (msg == NULL) continue;
+
+    // add 1 for terminating '\0'
+    size_t name_size = strlen(msg->name) + 1;
+    size_t message_size = strlen(msg->message) + 1;
+
+    LogFileMessageHeader *const output = writer.GetWritePosition(
+        sizeof(LogFileMessageHeader) + name_size + message_size);
+    char *output_strings = reinterpret_cast<char *>(output) + sizeof(*output);
+    output->name_size = name_size;
+    output->message_size = message_size;
+    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, name_size);
+    memcpy(output_strings + name_size, msg->message, message_size);
+    futex_set(&output->marker);
+
+    logging::linux_code::Free(msg);
+  }
+
+  Cleanup();
+  return 0;
+}
+
+}  // namespace
+}  // namespace linux_code
+}  // namespace logging
+}  // namespace aos
+
+int main() {
+  return ::aos::logging::linux_code::BinaryLogReaderMain();
+}
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
new file mode 100644
index 0000000..988c307
--- /dev/null
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include "aos/linux_code/logging/binary_log_file.h"
+#include "aos/common/logging/logging_impl.h"
+
+namespace {
+
+const char *kArgsHelp = "[OPTION]... [FILE]\n"
+    "Display log file FILE (created by BinaryLogReader) to stdout.\n"
+    "FILE is \"aos_log-current\" by default.\n"
+    "\n"
+    "  -n, --name NAME       only display entries from processes named NAME\n"
+    "  -l, --level LEVEL     "
+      "only display log entries at least as important as LEVEL\n"
+    "  // -p, --pid PID        only display log entries from process PID\n"
+    "  -f, --follow          "
+      "wait when the end of the file is reached (implies --end)\n"
+    "  -t, --terminate       stop when the end of file is reached (default)\n"
+    "  -b, --beginning       start at the beginning of the file (default)\n"
+    "  -e, --end             start at the end of the file\n"
+    "  -s, --skip NUMBER     skip NUMBER matching logs\n"
+    "  // -m, --max NUMBER     only display up to NUMBER logs\n"
+    "  // -o, --format FORMAT  use FORMAT to display log entries\n"
+    "  -h, --help            display this help and exit\n"
+    "\n"
+    "LEVEL must be DEBUG, INFO, WARNING, ERROR, or FATAL.\n"
+    "  It defaults to INFO.\n"
+    "\n"
+    "TODO(brians) implement the commented out ones and changing FILE\n";
+
+void PrintHelpAndExit() {
+  fprintf(stderr, "Usage: %s %s", program_invocation_name, kArgsHelp);
+
+  exit(EXIT_SUCCESS);
+}
+
+}  // namespace
+
+int main(int argc, char **argv) {
+  const char *filter_name = NULL;
+  log_level filter_level = INFO;
+  bool follow = false, start_at_beginning = true;
+  const char *filename = "aos_log-current";
+
+  while (true) {
+    static struct option long_options[] = {
+      {"name", required_argument, NULL, 'n'},
+      {"level", required_argument, NULL, 'l'},
+      {"pid", required_argument, NULL, 'p'},
+
+      {"follow", no_argument, NULL, 'f'},
+      {"terminate", no_argument, NULL, 't'},
+      {"beginning", no_argument, NULL, 'b'},
+      {"end", no_argument, NULL, 'e'},
+      {"skip", required_argument, NULL, 's'},
+      {"max", required_argument, NULL, 'm'},
+
+      {"format", required_argument, NULL, 'o'},
+
+      {"help", no_argument, NULL, 'h'},
+      {0, 0, 0, 0}
+    };
+    int option_index = 0;
+
+    const int c = getopt_long(argc, argv, "n:l:p:fts:m:o:h",
+                    long_options, &option_index);
+    if (c == -1) { // if we're at the end
+      break;
+    }
+    switch (c) {
+      case 0:
+        fprintf(stderr, "LogDisplayer: got a 0 option but didn't set up any\n");
+        abort();
+      case 'n':
+        filter_name = optarg;
+        break;
+      case 'l':
+        filter_level = ::aos::logging::str_log(optarg);
+        if (filter_level == LOG_UNKNOWN) {
+          fprintf(stderr, "LogDisplayer: unknown log level '%s'\n", optarg);
+          exit(EXIT_FAILURE);
+        }
+        break;
+      case 'p':
+        abort();
+        break;
+      case 'f':
+        follow = true;
+        start_at_beginning = false;
+        break;
+      case 't':
+        follow = false;
+        break;
+      case 'b':
+        start_at_beginning = true;
+        break;
+      case 'e':
+        start_at_beginning = false;
+        break;
+      case 'm':
+        abort();
+        break;
+      case 'o':
+        abort();
+        break;
+      case 'h':
+        PrintHelpAndExit();
+        break;
+      case '?':
+        break;
+      default:
+        fprintf(stderr, "LogDisplayer: in a bad spot (%s: %d)\n",
+                __FILE__, __LINE__);
+        abort();
+    }
+  }
+
+  fprintf(stderr, "displaying down to level %s from file '%s'\n",
+          ::aos::logging::log_str(filter_level), filename);
+  if (optind < argc) {
+    fprintf(stderr, "non-option ARGV-elements: ");
+    while (optind < argc) {
+      fprintf(stderr, "%s\n", argv[optind++]);
+    }
+  }
+
+  int fd = open(filename, O_RDONLY);
+  if (fd == -1) {
+    fprintf(stderr, "error: couldn't open file '%s' for reading because of %s\n",
+            filename, strerror(errno));
+    exit(EXIT_FAILURE);
+  }
+  ::aos::logging::LogFileAccessor accessor(fd, false);
+  if (!start_at_beginning) {
+    accessor.MoveToEnd();
+  }
+  const ::aos::logging::LogFileMessageHeader *msg;
+  ::aos::logging::LogMessage log_message;
+  do {
+    msg = accessor.ReadNextMessage(follow);
+    if (msg == NULL) continue;
+    if (::aos::logging::log_gt_important(filter_level, msg->level)) continue;
+    if (filter_name != NULL &&
+        strcmp(filter_name,
+               reinterpret_cast<const char *>(msg) + sizeof(*msg)) != 0) {
+      continue;
+    }
+
+    log_message.source = msg->source;
+    log_message.sequence = msg->sequence;
+    log_message.level = msg->level;
+    log_message.seconds = msg->time_sec;
+    log_message.nseconds = msg->time_nsec;
+    strncpy(log_message.name,
+            reinterpret_cast<const char *>(msg) + sizeof(*msg),
+            sizeof(log_message.name));
+    strncpy(log_message.message,
+            reinterpret_cast<const char *>(msg) + sizeof(*msg) +
+            msg->name_size,
+            sizeof(log_message.message));
+    ::aos::logging::internal::PrintMessage(stdout, log_message);
+  } while (msg != NULL);
+}
diff --git a/aos/linux_code/logging/log_streamer.cc b/aos/linux_code/logging/log_streamer.cc
new file mode 100644
index 0000000..ad351e7
--- /dev/null
+++ b/aos/linux_code/logging/log_streamer.cc
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "aos/linux_code/logging/linux_logging.h"
+#include "aos/linux_code/logging/binary_log_file.h"
+#include "aos/linux_code/init.h"
+#include "aos/linux_code/ipc_lib/queue.h"
+#include "aos/common/logging/logging_impl.h"
+#include "aos/common/time.h"
+
+namespace aos {
+namespace logging {
+namespace linux_code {
+namespace {
+
+int LogStreamerMain() {
+  InitNRT();
+
+  const time::Time now = time::Time::Now();
+  printf("starting at %" PRId32 "s%" PRId32 "ns-----------------------------\n",
+         now.sec(), now.nsec());
+
+  int index = 0;
+  while (true) {
+    const LogMessage *const msg = ReadNext(RawQueue::kBlock, &index);
+    if (msg == NULL) continue;
+
+    internal::PrintMessage(stdout, *msg);
+
+    logging::linux_code::Free(msg);
+  }
+
+  Cleanup();
+  return 0;
+}
+
+}  // namespace
+}  // namespace linux_code
+}  // namespace logging
+}  // namespace aos
+
+int main() {
+  return ::aos::logging::linux_code::LogStreamerMain();
+}
diff --git a/aos/linux_code/logging/logging.gyp b/aos/linux_code/logging/logging.gyp
index dfb189c..96c197f 100644
--- a/aos/linux_code/logging/logging.gyp
+++ b/aos/linux_code/logging/logging.gyp
@@ -1,4 +1,40 @@
 {
   'targets': [
+    {
+      'target_name': 'binary_log_writer',
+      'type': 'executable',
+      'sources': [
+        'binary_log_writer.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging',
+        '<(AOS)/linux_code/linux_code.gyp:init',
+        '<(AOS)/linux_code/linux_code.gyp:configuration',
+      ],
+    },
+    {
+      'target_name': 'log_streamer',
+      'type': 'executable',
+      'sources': [
+        'log_streamer.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging',
+        '<(AOS)/linux_code/linux_code.gyp:init',
+        '<(AOS)/common/common.gyp:time',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue',
+      ],
+    },
+    {
+      'target_name': 'log_displayer',
+      'type': 'executable',
+      'sources': [
+        'log_displayer.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging',
+        '<(AOS)/linux_code/linux_code.gyp:init',
+      ],
+    },
   ],
 }