create parent paths of target mounts as needed

Currently if you want to bind mount a single subdir, you have to make
sure to create the full parent directory chain.  For example, if you
want /var/lib/timezone/ but not the rest of /var, you have to do:
	-k none,/var,tmpfs
	-k none,/var/lib,tmpfs
	-b /var/lib/timezone/
For every additional subdir, you need to add another -k option just to
do an [effective] mkdir with a tmpfs mount.

The current -k/-b behavior is to run mkdir if the target doesn't already
exist, but only for the final target.  Lets extend it to also create any
missing parent paths, so now only the base path needs to be writable:
	-k none,/var,tmpfs
	-b /var/lib/timezone/

Bug: None
Test: `minijail0 --profile minimalistic-mountns -k none,/var,tmpfs -b /var/lib/timezone /bin/date` works
Change-Id: I7f36bcb445ce40ed66a9403a4ee1c1fe3f9e5ea8
diff --git a/system_unittest.cc b/system_unittest.cc
index db5fe98..c584808 100644
--- a/system_unittest.cc
+++ b/system_unittest.cc
@@ -8,6 +8,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <gtest/gtest.h>
@@ -125,6 +126,57 @@
 }
 
 // If the destination exists, there's nothing to do.
+// Also check trailing slash handling.
+TEST(mkdir_p, dest_exists) {
+  EXPECT_EQ(0, mkdir_p("/", 0, true));
+  EXPECT_EQ(0, mkdir_p("///", 0, true));
+  EXPECT_EQ(0, mkdir_p("/proc", 0, true));
+  EXPECT_EQ(0, mkdir_p("/proc/", 0, true));
+  EXPECT_EQ(0, mkdir_p("/dev", 0, true));
+  EXPECT_EQ(0, mkdir_p("/dev/", 0, true));
+}
+
+// Create a directory tree that doesn't exist.
+TEST(mkdir_p, create_tree) {
+  char *path = get_temp_path();
+  ASSERT_NE(nullptr, path);
+  unlink(path);
+
+  // Run `mkdir -p <path>/a/b/c`.
+  char *path_a, *path_a_b, *path_a_b_c;
+  ASSERT_NE(-1, asprintf(&path_a, "%s/a", path));
+  ASSERT_NE(-1, asprintf(&path_a_b, "%s/b", path_a));
+  ASSERT_NE(-1, asprintf(&path_a_b_c, "%s/c", path_a_b));
+
+  // First try creating it as a file.
+  EXPECT_EQ(0, mkdir_p(path_a_b_c, 0700, false));
+
+  // Make sure the final path doesn't exist yet.
+  struct stat st;
+  EXPECT_EQ(0, stat(path_a_b, &st));
+  EXPECT_EQ(true, S_ISDIR(st.st_mode));
+  EXPECT_EQ(-1, stat(path_a_b_c, &st));
+
+  // Then create it as a complete dir.
+  EXPECT_EQ(0, mkdir_p(path_a_b_c, 0700, true));
+
+  // Make sure the final dir actually exists.
+  EXPECT_EQ(0, stat(path_a_b_c, &st));
+  EXPECT_EQ(true, S_ISDIR(st.st_mode));
+
+  // Clean up.
+  ASSERT_EQ(0, rmdir(path_a_b_c));
+  ASSERT_EQ(0, rmdir(path_a_b));
+  ASSERT_EQ(0, rmdir(path_a));
+  ASSERT_EQ(0, rmdir(path));
+
+  free(path_a_b_c);
+  free(path_a_b);
+  free(path_a);
+  free(path);
+}
+
+// If the destination exists, there's nothing to do.
 TEST(setup_mount_destination, dest_exists) {
   // Pick some paths that should always exist.  We pass in invalid pointers
   // for other args so we crash if the dest check doesn't short circuit.