Cleanup shm at startup in message_bridge_test

When we start forwarding messages from before connection, we need shm to
be clean.  Take this oppertunity to dedup some things.

Change-Id: Ic4caff28ba63e48ce5e74a28868deb5c808a984d
diff --git a/aos/util/file.cc b/aos/util/file.cc
index afefa86..97500d1 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -1,6 +1,7 @@
 #include "aos/util/file.h"
 
 #include <fcntl.h>
+#include <fts.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -78,5 +79,64 @@
   return stat(path.data(), &buffer) == 0;
 }
 
+void UnlinkRecursive(std::string_view path) {
+  FTS *ftsp = NULL;
+  FTSENT *curr;
+
+  // Cast needed (in C) because fts_open() takes a "char * const *", instead
+  // of a "const char * const *", which is only allowed in C++. fts_open()
+  // does not modify the argument.
+  std::string p(path);
+  char *files[] = {const_cast<char *>(p.c_str()), NULL};
+
+  // FTS_NOCHDIR  - Avoid changing cwd, which could cause unexpected behavior
+  //                in multithreaded programs
+  // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
+  //                of the specified directory
+  // FTS_XDEV     - Don't cross filesystem boundaries
+  ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
+  if (!ftsp) {
+    return;
+  }
+
+  while ((curr = fts_read(ftsp))) {
+    switch (curr->fts_info) {
+      case FTS_NS:
+      case FTS_DNR:
+      case FTS_ERR:
+        LOG(WARNING) << "Can't read " << curr->fts_accpath;
+        break;
+
+      case FTS_DC:
+      case FTS_DOT:
+      case FTS_NSOK:
+        // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
+        // passed to fts_open()
+        break;
+
+      case FTS_D:
+        // Do nothing. Need depth-first search, so directories are deleted
+        // in FTS_DP
+        break;
+
+      case FTS_DP:
+      case FTS_F:
+      case FTS_SL:
+      case FTS_SLNONE:
+      case FTS_DEFAULT:
+        VLOG(1) << "Removing " << curr->fts_path;
+        if (remove(curr->fts_accpath) < 0) {
+          LOG(WARNING) << curr->fts_path
+                       << ": Failed to remove: " << strerror(curr->fts_errno);
+        }
+        break;
+    }
+  }
+
+  if (ftsp) {
+    fts_close(ftsp);
+  }
+}
+
 }  // namespace util
 }  // namespace aos
diff --git a/aos/util/file.h b/aos/util/file.h
index bf216bb..4d0ed2d 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -26,6 +26,10 @@
 
 bool PathExists(std::string_view path);
 
+// Recursively removes everything in the provided path.  Ignores any errors it
+// runs across.
+void UnlinkRecursive(std::string_view path);
+
 }  // namespace util
 }  // namespace aos