merge in oc-release history after reset to oc-dev
diff --git a/Android.mk b/Android.mk
index 36b4bea..901fe02 100644
--- a/Android.mk
+++ b/Android.mk
@@ -80,6 +80,32 @@
     libavb/avb_version.c
 include $(BUILD_STATIC_LIBRARY)
 
+# Build avbctl for the target.
+include $(CLEAR_VARS)
+LOCAL_MODULE := avbctl
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CLANG := true
+LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_COMPILATION -DAVB_ENABLE_DEBUG
+LOCAL_CPPFLAGS := $(avb_common_cppflags)
+LOCAL_LDFLAGS := $(avb_common_ldflags)
+LOCAL_STATIC_LIBRARIES := \
+    libavb \
+    libfs_mgr
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    libutils \
+    android.hardware.boot@1.0
+LOCAL_SRC_FILES := \
+    libavb_ab/avb_ab_flow.c \
+    libavb_user/avb_ops_user.c \
+    tools/avbctl/avbctl.cc
+include $(BUILD_EXECUTABLE)
+
 # Build libavb for the host (for unit tests).
 include $(CLEAR_VARS)
 LOCAL_MODULE := libavb_host
@@ -196,10 +222,9 @@
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_REQUIRED_MODULES := libavb
 LOCAL_SRC_FILES := \
-    boot_control/boot_control_avb.c \
-    boot_control/avb_ops_device.c \
     libavb_ab/avb_ab_flow.c \
-    libavb/avb_sysdeps_posix.c
+    libavb_user/avb_ops_user.c \
+    boot_control/boot_control_avb.c
 LOCAL_CLANG := true
 LOCAL_CFLAGS := $(avb_common_cflags) -DAVB_COMPILATION
 LOCAL_LDFLAGS := $(avb_common_ldflags)
diff --git a/README.md b/README.md
index 3e36f76..8c0d550 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,9 @@
     + An A/B implementation for use in boot loaders.
 * `libavb_atx/`
     + An Android Things Extension for validating public key metadata.
+* `libavb_user/`
+    + Contains an AvbOps implementation suitable for use in userspace
+      on the device (used in boot_control.avb and avbctl).
 * `boot_control/`
     + An implemementation of the Android boot_control HAL for use with
       boot loaders using `libavb_ab`.
@@ -105,6 +108,9 @@
 * `test/`
     + Unit tests for `abvtool`, `libavb`, `libavb_ab`, and
       `libavb_atx`.
+* `tools/avbctl/`
+    + Contains the source-code for a tool that can be used to control
+      AVB at runtime.
 * `examples/uefi/`
     + Contains the source-code for a UEFI-based boot-loader utilizing
       `libavb/` and `libavb_ab/`.
diff --git a/boot_control/boot_control_avb.c b/boot_control/boot_control_avb.c
index 8775d09..f0e89d2 100644
--- a/boot_control/boot_control_avb.c
+++ b/boot_control/boot_control_avb.c
@@ -29,17 +29,17 @@
 #include <hardware/boot_control.h>
 #include <hardware/hardware.h>
 
-#include "avb_ops_device.h"
+#include <libavb_user/libavb_user.h>
 
-static AvbABOps* ab_ops = NULL;
+static AvbOps* ops = NULL;
 
 static void module_init(boot_control_module_t* module) {
-  if (ab_ops != NULL) {
+  if (ops != NULL) {
     return;
   }
 
-  ab_ops = avb_ops_device_new();
-  if (ab_ops == NULL) {
+  ops = avb_ops_user_new();
+  if (ops == NULL) {
     avb_error("Unable to allocate AvbOps instance.\n");
   }
 }
@@ -64,7 +64,7 @@
 }
 
 static int module_markBootSuccessful(boot_control_module_t* module) {
-  if (avb_ab_mark_slot_successful(ab_ops, module_getCurrentSlot(module)) ==
+  if (avb_ab_mark_slot_successful(ops->ab_ops, module_getCurrentSlot(module)) ==
       AVB_IO_RESULT_OK) {
     return 0;
   } else {
@@ -74,7 +74,7 @@
 
 static int module_setActiveBootSlot(boot_control_module_t* module,
                                     unsigned int slot) {
-  if (avb_ab_mark_slot_active(ab_ops, slot) == AVB_IO_RESULT_OK) {
+  if (avb_ab_mark_slot_active(ops->ab_ops, slot) == AVB_IO_RESULT_OK) {
     return 0;
   } else {
     return -EIO;
@@ -83,7 +83,7 @@
 
 static int module_setSlotAsUnbootable(struct boot_control_module* module,
                                       unsigned int slot) {
-  if (avb_ab_mark_slot_unbootable(ab_ops, slot) == AVB_IO_RESULT_OK) {
+  if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot) == AVB_IO_RESULT_OK) {
     return 0;
   } else {
     return -EIO;
@@ -97,7 +97,7 @@
 
   avb_assert(slot < 2);
 
-  if (avb_ab_data_read(ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
+  if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
     return -EIO;
   }
 
@@ -115,7 +115,7 @@
 
   avb_assert(slot < 2);
 
-  if (avb_ab_data_read(ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
+  if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
     return -EIO;
   }
 
diff --git a/boot_control/avb_ops_device.c b/libavb_user/avb_ops_user.c
similarity index 84%
rename from boot_control/avb_ops_device.c
rename to libavb_user/avb_ops_user.c
index 6a744c5..a95ce4d 100644
--- a/boot_control/avb_ops_device.c
+++ b/libavb_user/avb_ops_user.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -22,6 +22,8 @@
  * SOFTWARE.
  */
 
+#include "avb_ops_user.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/fs.h>
@@ -35,7 +37,7 @@
 #include <cutils/properties.h>
 #include <fs_mgr.h>
 
-#include "avb_ops_device.h"
+#include <libavb_ab/libavb_ab.h>
 
 /* Open the appropriate fstab file and fallback to /fstab.device if
  * that's what's being used.
@@ -47,7 +49,7 @@
     return fstab;
   }
 
-  fstab = fs_mgr_read_fstab_with_dt("/fstab.device");
+  fstab = fs_mgr_read_fstab("/fstab.device");
   return fstab;
 }
 
@@ -120,11 +122,21 @@
 
   fd = open_partition(partition, O_RDONLY);
   if (fd == -1) {
-    avb_errorv("Error opening \"", partition, "\" partition.\n", NULL);
-    ret = AVB_IO_RESULT_ERROR_IO;
+    ret = AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
     goto out;
   }
 
+  if (offset < 0) {
+    uint64_t partition_size;
+    if (ioctl(fd, BLKGETSIZE64, &partition_size) != 0) {
+      avb_errorv(
+          "Error getting size of \"", partition, "\" partition.\n", NULL);
+      ret = AVB_IO_RESULT_ERROR_IO;
+      goto out;
+    }
+    offset = partition_size - (-offset);
+  }
+
   where = lseek(fd, offset, SEEK_SET);
   if (where == -1) {
     avb_error("Error seeking to offset.\n");
@@ -209,35 +221,33 @@
   return ret;
 }
 
-AvbABOps* avb_ops_device_new(void) {
-  AvbABOps* ab_ops;
+AvbOps* avb_ops_user_new(void) {
+  AvbOps* ops;
 
-  ab_ops = calloc(1, sizeof(AvbABOps));
-  if (ab_ops == NULL) {
-    avb_error("Error allocating memory for AvbABOps.\n");
-    goto out;
-  }
-
-  ab_ops->ops = calloc(1, sizeof(AvbOps));
-  if (ab_ops->ops == NULL) {
+  ops = calloc(1, sizeof(AvbOps));
+  if (ops == NULL) {
     avb_error("Error allocating memory for AvbOps.\n");
-    free(ab_ops);
     goto out;
   }
 
-  /* We only need these operations since that's all what is being used
-   * by the A/B routines.
-   */
-  ab_ops->ops->read_from_partition = read_from_partition;
-  ab_ops->ops->write_to_partition = write_to_partition;
-  ab_ops->read_ab_metadata = avb_ab_data_read;
-  ab_ops->write_ab_metadata = avb_ab_data_write;
+  ops->ab_ops = calloc(1, sizeof(AvbABOps));
+  if (ops->ab_ops == NULL) {
+    avb_error("Error allocating memory for AvbABOps.\n");
+    free(ops);
+    goto out;
+  }
+  ops->ab_ops->ops = ops;
+
+  ops->read_from_partition = read_from_partition;
+  ops->write_to_partition = write_to_partition;
+  ops->ab_ops->read_ab_metadata = avb_ab_data_read;
+  ops->ab_ops->write_ab_metadata = avb_ab_data_write;
 
 out:
-  return ab_ops;
+  return ops;
 }
 
-void avb_ops_device_free(AvbABOps* ab_ops) {
-  free(ab_ops->ops);
-  free(ab_ops);
+void avb_ops_user_free(AvbOps* ops) {
+  free(ops->ab_ops);
+  free(ops);
 }
diff --git a/boot_control/avb_ops_device.h b/libavb_user/avb_ops_user.h
similarity index 77%
rename from boot_control/avb_ops_device.h
rename to libavb_user/avb_ops_user.h
index ad7bddb..4e547b9 100644
--- a/boot_control/avb_ops_device.h
+++ b/libavb_user/avb_ops_user.h
@@ -22,19 +22,27 @@
  * SOFTWARE.
  */
 
-#ifndef AVB_OPS_DEVICE_H_
-#define AVB_OPS_DEVICE_H_
+#ifndef AVB_OPS_USER_H_
+#define AVB_OPS_USER_H_
 
-#include <libavb_ab/libavb_ab.h>
+#include <libavb/libavb.h>
 
-/* Allocates an AvbOps instance suitable for use on the
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Allocates an AvbOps instance suitable for use in userspace on the
  * device. Returns NULL on OOM.
  *
- * Free with avb_ops_device_free().
+ * Free with avb_ops_user_free().
  */
-AvbABOps* avb_ops_device_new(void);
+AvbOps* avb_ops_user_new(void);
 
 /* Frees an AvbOps instance previously allocated with avb_ops_device_new(). */
-void avb_ops_device_free(AvbABOps* ab_ops);
+void avb_ops_user_free(AvbOps* ops);
 
-#endif /* AVB_OPS_DEVICE_H_ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_OPS_USER_H_ */
diff --git a/boot_control/avb_ops_device.h b/libavb_user/libavb_user.h
similarity index 75%
copy from boot_control/avb_ops_device.h
copy to libavb_user/libavb_user.h
index ad7bddb..4b34bdd 100644
--- a/boot_control/avb_ops_device.h
+++ b/libavb_user/libavb_user.h
@@ -22,19 +22,18 @@
  * SOFTWARE.
  */
 
-#ifndef AVB_OPS_DEVICE_H_
-#define AVB_OPS_DEVICE_H_
+#ifndef LIBAVB_USER_H_
+#define LIBAVB_USER_H_
 
 #include <libavb_ab/libavb_ab.h>
 
-/* Allocates an AvbOps instance suitable for use on the
- * device. Returns NULL on OOM.
- *
- * Free with avb_ops_device_free().
+/* The AVB_INSIDE_LIBAVB_USER_H preprocessor symbol is used to enforce
+ * library users to include only this file. All public interfaces, and
+ * only public interfaces, must be included here.
  */
-AvbABOps* avb_ops_device_new(void);
 
-/* Frees an AvbOps instance previously allocated with avb_ops_device_new(). */
-void avb_ops_device_free(AvbABOps* ab_ops);
+#define AVB_INSIDE_LIBAVB_USER_H
+#include "avb_ops_user.h"
+#undef AVB_INSIDE_LIBAVB_USER_H
 
-#endif /* AVB_OPS_DEVICE_H_ */
+#endif /* LIBAVB_USER_H_ */
diff --git a/tools/avbctl/avbctl.cc b/tools/avbctl/avbctl.cc
new file mode 100644
index 0000000..0842c59
--- /dev/null
+++ b/tools/avbctl/avbctl.cc
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+#include <libavb_user/libavb_user.h>
+
+using android::sp;
+using android::hardware::hidl_string;
+using android::hardware::Return;
+using android::hardware::boot::V1_0::IBootControl;
+using android::hardware::boot::V1_0::Slot;
+
+namespace {
+
+/* Prints program usage to |where|. */
+void usage(FILE* where, int /* argc */, char* argv[]) {
+  fprintf(where,
+          "%s - command-line tool for AVB.\n"
+          "\n"
+          "Usage:\n"
+          "  %s COMMAND\n"
+          "\n"
+          "Commands:\n"
+          "  %s disable-verity    - Disable verity in current slot.\n"
+          "  %s enable-verity     - Enable verity in current slot.\n",
+          argv[0],
+          argv[0],
+          argv[0],
+          argv[0]);
+}
+
+/* Returns the A/B suffix the device booted from or the empty string
+ * if A/B is not in use.
+ */
+std::string get_ab_suffix(sp<IBootControl> module) {
+  std::string suffix = "";
+
+  if (module != nullptr) {
+    uint32_t num_slots = module->getNumberSlots();
+    if (num_slots > 1) {
+      Slot cur_slot = module->getCurrentSlot();
+      Return<void> ret =
+          module->getSuffix(cur_slot, [&suffix](const hidl_string& value) {
+            suffix = std::string(value.c_str());
+          });
+      if (!ret.isOk()) {
+        fprintf(stderr, "Error getting suffix for slot %d.\n", cur_slot);
+      }
+    }
+  }
+
+  return suffix;
+}
+
+/* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by
+ * |ab_suffix| into |vbmeta_image|. No validation, verification, or
+ * byteswapping is performed.
+ *
+ * If successful, |true| is returned and the partition it was loaded
+ * from is returned in |out_partition_name| and the offset on said
+ * partition is returned in |out_vbmeta_offset|.
+ */
+bool load_top_level_vbmeta_header(
+    AvbOps* ops,
+    const std::string& ab_suffix,
+    uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
+    std::string* out_partition_name,
+    uint64_t* out_vbmeta_offset) {
+  std::string partition_name = std::string("vbmeta") + ab_suffix;
+  uint64_t vbmeta_offset = 0;
+
+  // Only read the header.
+  size_t num_read;
+  AvbIOResult io_res = ops->read_from_partition(ops,
+                                                partition_name.c_str(),
+                                                vbmeta_offset,
+                                                AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                                vbmeta_image,
+                                                &num_read);
+  if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+    AvbFooter footer;
+    // Try looking for the vbmeta struct in 'boot' via the footer.
+    partition_name = std::string("boot") + ab_suffix;
+    io_res = ops->read_from_partition(ops,
+                                      partition_name.c_str(),
+                                      -AVB_FOOTER_SIZE,
+                                      AVB_FOOTER_SIZE,
+                                      &footer,
+                                      &num_read);
+    if (io_res != AVB_IO_RESULT_OK) {
+      fprintf(stderr,
+              "Error loading footer from partition '%s' (%d).\n",
+              partition_name.c_str(),
+              io_res);
+      return false;
+    }
+
+    if (memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) {
+      fprintf(stderr,
+              "Data from '%s' does not look like a vbmeta footer.\n",
+              partition_name.c_str());
+      return false;
+    }
+
+    vbmeta_offset = avb_be64toh(footer.vbmeta_offset);
+    io_res = ops->read_from_partition(ops,
+                                      partition_name.c_str(),
+                                      vbmeta_offset,
+                                      AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                      vbmeta_image,
+                                      &num_read);
+  }
+
+  if (io_res != AVB_IO_RESULT_OK) {
+    fprintf(stderr,
+            "Error loading from offset %" PRIu64 " of partition '%s' (%d).\n",
+            vbmeta_offset,
+            partition_name.c_str(),
+            io_res);
+    return false;
+  }
+
+  if (out_partition_name != nullptr) {
+    *out_partition_name = partition_name;
+  }
+  if (out_vbmeta_offset != nullptr) {
+    *out_vbmeta_offset = vbmeta_offset;
+  }
+  return true;
+}
+
+/* Function to enable and disable dm-verity. The |ops| parameter
+ * should be an |AvbOps| from libavb_user and |module| can either be
+ * |nullptr| or a valid boot_control module.
+ */
+int do_set_verity(AvbOps* ops, sp<IBootControl> module, bool enable_verity) {
+  uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE];  // 256 bytes.
+  std::string ab_suffix;
+  std::string partition_name;
+  uint64_t vbmeta_offset;
+  AvbIOResult io_res;
+
+  ab_suffix = get_ab_suffix(module);
+
+  if (!load_top_level_vbmeta_header(
+          ops, ab_suffix, vbmeta_image, &partition_name, &vbmeta_offset)) {
+    return EX_SOFTWARE;
+  }
+
+  if (memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    fprintf(stderr,
+            "Data from '%s' does not look like a vbmeta header.\n",
+            partition_name.c_str());
+    return EX_SOFTWARE;
+  }
+
+  // Set/clear the HASHTREE_DISABLED bit, as requested.
+  AvbVBMetaImageHeader* header =
+      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image);
+  uint32_t flags = avb_be32toh(header->flags);
+  flags &= ~AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED;
+  if (!enable_verity) {
+    flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED;
+  }
+  header->flags = avb_htobe32(flags);
+
+  // Write the header.
+  io_res = ops->write_to_partition(ops,
+                                   partition_name.c_str(),
+                                   vbmeta_offset,
+                                   AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                   vbmeta_image);
+  if (io_res != AVB_IO_RESULT_OK) {
+    fprintf(stderr,
+            "Error writing to offset %" PRIu64 " of partition '%s' (%d).\n",
+            vbmeta_offset,
+            partition_name.c_str(),
+            io_res);
+    return EX_SOFTWARE;
+  }
+
+  fprintf(stdout,
+          "Successfully %s verity on %s.\n",
+          enable_verity ? "enabled" : "disabled",
+          partition_name.c_str());
+
+  return EX_OK;
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  int ret;
+  sp<IBootControl> module;
+  AvbOps* ops = nullptr;
+
+  if (argc < 2) {
+    usage(stderr, argc, argv);
+    ret = EX_USAGE;
+    goto out;
+  }
+
+  ops = avb_ops_user_new();
+  if (ops == nullptr) {
+    fprintf(stderr, "Error getting AVB ops.\n");
+    ret = EX_SOFTWARE;
+    goto out;
+  }
+
+  // Failing to get the boot_control HAL is not a fatal error - it can
+  // happen if A/B is not in use, in which case |nullptr| is returned.
+  module = IBootControl::getService();
+
+  if (strcmp(argv[1], "disable-verity") == 0) {
+    ret = do_set_verity(ops, module, false);
+  } else if (strcmp(argv[1], "enable-verity") == 0) {
+    ret = do_set_verity(ops, module, true);
+  } else {
+    usage(stderr, argc, argv);
+    ret = EX_USAGE;
+  }
+
+  ret = EX_OK;
+out:
+  if (ops != nullptr) {
+    avb_ops_user_free(ops);
+  }
+  return ret;
+}