Handle loop device partitions.

Loop devices can have partitions on them which follow naming conventions
similar to mmcblk devices (/dev/loop2p4).

BUG=chromium:349045
TEST=Unittests.

Change-Id: I653ae88eae69e638185a01e736900f0b695ce992
Reviewed-on: https://chromium-review.googlesource.com/190892
Reviewed-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Commit-Queue: Don Garrett <dgarrett@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
diff --git a/inst_util.cc b/inst_util.cc
index b83e6a9..1e5218a 100644
--- a/inst_util.cc
+++ b/inst_util.cc
@@ -11,6 +11,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
@@ -301,7 +302,9 @@
   return false;
 }
 
-const std::string mmcblk_dev = "/dev/mmcblk";
+// This is an array of device names that are allowed in end in a digit, and
+// which use the 'p' notation to denote partitions.
+const char *numbered_devices[] = {"/dev/mmcblk", "/dev/loop"};
 
 string GetBlockDevFromPartitionDev(const string& partition_dev) {
   size_t i = partition_dev.length();
@@ -309,14 +312,21 @@
   while (i > 0 && isdigit(partition_dev[i-1]))
     i--;
 
-  // mmcblk devices are of the form "/dev/mmcblk12p34"
-  if (partition_dev.compare(0, mmcblk_dev.size(), mmcblk_dev) == 0) {
-    // If it ends with a p, strip off the p. If it doesn't there was
-    // no partition at the end (/dev/mmcblk12) return unmodified.
-    if (partition_dev[i-1] == 'p')
-      i--;
-    else
-      return partition_dev;
+  for (const char **nd = begin(numbered_devices);
+       nd != end(numbered_devices); nd++) {
+
+    size_t nd_len = strlen(*nd);
+    // numbered_devices are of the form "/dev/mmcblk12p34"
+    if (partition_dev.compare(0, nd_len, *nd) == 0) {
+      if ((i == nd_len) || (partition_dev[i-1] != 'p')) {
+        // If there was no partition at the end (/dev/mmcblk12) return
+        // unmodified.
+        return partition_dev;
+      } else {
+        // If it ends with a p, strip off the p.
+        i--;
+      }
+    }
   }
 
   return partition_dev.substr(0, i);
@@ -328,11 +338,15 @@
   while (i > 0 && isdigit(partition_dev[i-1]))
     i--;
 
-  // mmcblk devices are of the form "/dev/mmcblk12p34"
-  // If there is no ending p, There was no partition at the end (/dev/mmcblk12)
-  if ((partition_dev.compare(0, mmcblk_dev.size(), mmcblk_dev) == 0) &&
-      (partition_dev[i-1] != 'p')) {
-    return 0;
+  for (const char **nd = begin(numbered_devices);
+       nd != end(numbered_devices); nd++) {
+    size_t nd_len = strlen(*nd);
+    // numbered_devices are of the form "/dev/mmcblk12p34"
+    // If there is no ending p, there is no partition at the end (/dev/mmcblk12)
+    if ((partition_dev.compare(0, nd_len, *nd) == 0) &&
+        ((i == nd_len) || (partition_dev[i-1] != 'p'))) {
+      return 0;
+    }
   }
 
   string partition_str = partition_dev.substr(i, i+1);
@@ -346,8 +360,13 @@
 }
 
 string MakePartitionDev(const string& block_dev, int partition) {
-  if (block_dev.compare(0, mmcblk_dev.size(), mmcblk_dev) == 0)
-    return StringPrintf("%sp%d", block_dev.c_str(), partition);
+
+  for (const char **nd = begin(numbered_devices);
+       nd != end(numbered_devices); nd++) {
+    size_t nd_len = strlen(*nd);
+    if (block_dev.compare(0, nd_len, *nd) == 0)
+      return StringPrintf("%sp%d", block_dev.c_str(), partition);
+  }
 
   return StringPrintf("%s%d", block_dev.c_str(), partition);
 }
diff --git a/inst_util.h b/inst_util.h
index 876958b..18f689e 100644
--- a/inst_util.h
+++ b/inst_util.h
@@ -13,6 +13,18 @@
     if (RunCommand(_x) != 0) return false;                      \
   } while (0)
 
+// Find a pointer to the first element of a statically sized array.
+template<typename T, size_t N>
+T * begin(T (&ra)[N]) {
+    return ra + 0;
+}
+
+// Find a pointer to the element after the end of a statically sized array.
+template<typename T, size_t N>
+T * end(T (&ra)[N]) {
+    return ra + N;
+}
+
 // Start a timer (there can only be one active).
 void LoggingTimerStart();
 
diff --git a/inst_util_unittest.cc b/inst_util_unittest.cc
index a2b82fd..ea82a07 100644
--- a/inst_util_unittest.cc
+++ b/inst_util_unittest.cc
@@ -234,7 +234,8 @@
   EXPECT_EQ(GetBlockDevFromPartitionDev("/dev/mmcblk0p3"), "/dev/mmcblk0");
   EXPECT_EQ(GetBlockDevFromPartitionDev("/dev/mmcblk12p321"), "/dev/mmcblk12");
   EXPECT_EQ(GetBlockDevFromPartitionDev("/dev/mmcblk0"), "/dev/mmcblk0");
-  EXPECT_EQ(GetBlockDevFromPartitionDev(""), "");
+  EXPECT_EQ(GetBlockDevFromPartitionDev("/dev/loop0"), "/dev/loop0");
+  EXPECT_EQ(GetBlockDevFromPartitionDev("/dev/loop32p12"), "/dev/loop32");
 }
 
 TEST(UtilTest, GetPartitionDevTest) {
@@ -245,7 +246,8 @@
   EXPECT_EQ(GetPartitionFromPartitionDev("/dev/mmcblk12p321"), 321);
   EXPECT_EQ(GetPartitionFromPartitionDev("/dev/mmcblk1"), 0);
   EXPECT_EQ(GetPartitionFromPartitionDev("3"), 3);
-  EXPECT_EQ(GetPartitionFromPartitionDev(""), 0);
+  EXPECT_EQ(GetPartitionFromPartitionDev("/dev/loop1"), 0);
+  EXPECT_EQ(GetPartitionFromPartitionDev("/dev/loop1p12"), 12);
 }
 
 TEST(UtilTest, MakePartitionDevTest) {
@@ -253,6 +255,7 @@
   EXPECT_EQ(MakePartitionDev("/dev/sda", 321), "/dev/sda321");
   EXPECT_EQ(MakePartitionDev("/dev/mmcblk0", 3), "/dev/mmcblk0p3");
   EXPECT_EQ(MakePartitionDev("/dev/mmcblk12", 321), "/dev/mmcblk12p321");
+  EXPECT_EQ(MakePartitionDev("/dev/loop16", 321), "/dev/loop16p321");
   EXPECT_EQ(MakePartitionDev("", 0), "0");
 }