verity_tool: Implement status getter

VB1.0 and VB2.0 are handled.

Change-Id: Id3753d3b7b87f3a8a2c03b96dd49be59b96e6d03
diff --git a/verity_tool/include/verity_tool.h b/verity_tool/include/verity_tool.h
index 25a6a7c..b81eda1 100644
--- a/verity_tool/include/verity_tool.h
+++ b/verity_tool/include/verity_tool.h
@@ -18,6 +18,14 @@
 
 #include <string>
 
+typedef enum {
+    VERITY_STATE_UNKNOWN,
+    VERITY_STATE_NO_DEVICE,
+    VERITY_STATE_DISABLED,
+    VERITY_STATE_ENABLED,
+    VERITY_STATE_MAX = VERITY_STATE_ENABLED
+} verity_state_t;
+
 /*
  * Return codes:
  *
@@ -30,6 +38,13 @@
 /*
  * Return codes:
  *
+ *    verity state (unknown, disabled, enabled)
+ */
+verity_state_t get_verity_state();
+
+/*
+ * Return codes:
+ *
  *    true: verity state set for all block devices
  *    false: verity state not for set all block devices
  */
diff --git a/verity_tool/main.cpp b/verity_tool/main.cpp
index f5f026a..befdafa 100644
--- a/verity_tool/main.cpp
+++ b/verity_tool/main.cpp
@@ -24,20 +24,23 @@
     printf("veritytool - toggle block device verification\n"
            "    --help        show this help\n"
            "    --enable      enable dm-verity\n"
-           "    --disable     disable dm-verity\n");
+           "    --disable     disable dm-verity\n"
+           "    --show        show current dm-verity state\n");
 }
 
 int main(int argc, char** argv) {
     int c, rc;
     int enable = 0;
+    int show = 0;
     bool flag_set = false;
     struct option long_opts[] = {
         {"disable", no_argument, &enable, 0},
         {"enable", no_argument, &enable, 1},
+        {"show", no_argument, &show, 1},
         {NULL, 0, NULL, 0},
     };
 
-    while ((c = getopt_long(argc, argv, "de", long_opts, NULL)) != -1) {
+    while ((c = getopt_long(argc, argv, "des", long_opts, NULL)) != -1) {
         switch (c) {
             case 0:
                 flag_set = true;
@@ -53,6 +56,26 @@
         exit(0);
     }
 
+    if (show) {
+        printf("dm-verity state: ");
+        switch (get_verity_state()) {
+            case VERITY_STATE_NO_DEVICE:
+                printf("NO DEVICE");
+                break;
+            case VERITY_STATE_DISABLED:
+                printf("DISABLED");
+                break;
+            case VERITY_STATE_ENABLED:
+                printf("ENABLED");
+                break;
+            default:
+                printf("UNKNOWN");
+                break;
+        }
+        printf("\n");
+        return 0;
+    }
+
     if (!set_verity_enabled(enable)) {
         printf("Error occurred in set_verity_enable\n");
         exit(EXIT_FAILURE);
diff --git a/verity_tool/verity_tool.cpp b/verity_tool/verity_tool.cpp
index 9575c4c..48e95b6 100644
--- a/verity_tool/verity_tool.cpp
+++ b/verity_tool/verity_tool.cpp
@@ -108,6 +108,69 @@
     return ab_suffix;
 }
 
+verity_state_t get_verity_state() {
+    verity_state_t rc = VERITY_STATE_NO_DEVICE;
+    std::string ab_suffix = get_ab_suffix();
+
+    // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
+    // contract, androidboot.vbmeta.digest is set by the bootloader
+    // when using AVB).
+    bool using_avb = !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
+
+    if (using_avb) {
+        // Yep, the system is using AVB.
+        AvbOps* ops = avb_ops_user_new();
+        if (ops == nullptr) {
+            LOG(ERROR) << "Error getting AVB ops";
+            avb_ops_user_free(ops);
+            return VERITY_STATE_UNKNOWN;
+        }
+        bool verity_enabled;
+        if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
+            LOG(ERROR) << "Error getting verity state";
+            avb_ops_user_free(ops);
+            return VERITY_STATE_UNKNOWN;
+        }
+        rc = verity_enabled ? VERITY_STATE_ENABLED : VERITY_STATE_DISABLED;
+        avb_ops_user_free(ops);
+    } else {
+        // Not using AVB - assume VB1.0.
+
+        // read all fstab entries at once from all sources
+        struct fstab* fstab = fs_mgr_read_fstab_default();
+        if (!fstab) {
+            LOG(ERROR) << "Failed to read fstab";
+            fs_mgr_free_fstab(fstab);
+            return VERITY_STATE_UNKNOWN;
+        }
+
+        // Loop through entries looking for ones that vold manages.
+        for (int i = 0; i < fstab->num_entries; i++) {
+            if (fs_mgr_is_verified(&fstab->recs[i])) {
+                std::string block_device = fstab->recs[i].blk_device;
+                fec::io fh(block_device, O_RDONLY);
+                if (!fh) {
+                    PLOG(ERROR) << "Could not open block device " << block_device;
+                    rc = VERITY_STATE_UNKNOWN;
+                    break;
+                }
+
+                fec_verity_metadata metadata;
+                if (!fh.get_verity_metadata(metadata)) {
+                    LOG(ERROR) << "Couldn't find verity metadata!";
+                    rc = VERITY_STATE_UNKNOWN;
+                    break;
+                }
+
+                rc = metadata.disabled ? VERITY_STATE_DISABLED : VERITY_STATE_ENABLED;
+            }
+        }
+        fs_mgr_free_fstab(fstab);
+    }
+
+    return rc;
+}
+
 /* Use AVB to turn verity on/off */
 static bool set_avb_verity_enabled_state(AvbOps* ops, bool enable_verity) {
     std::string ab_suffix = get_ab_suffix();