Merge "libdm: Implement LoadTableAndActivate."
diff --git a/adb/Android.bp b/adb/Android.bp
index 53bf7e3..97c9762 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -104,6 +104,7 @@
     "socket_spec.cpp",
     "sysdeps/errno.cpp",
     "transport.cpp",
+    "transport_fd.cpp",
     "transport_local.cpp",
     "transport_usb.cpp",
 ]
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 06fcf16..e07dba7 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1795,6 +1795,11 @@
     }
     else if (!strcmp(argv[0], "track-devices")) {
         return adb_connect_command("host:track-devices");
+    } else if (!strcmp(argv[0], "raw")) {
+        if (argc != 2) {
+            return syntax_error("adb raw SERVICE");
+        }
+        return adb_connect_command(argv[1]);
     }
 
 
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 1b7758c..f98c11a 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -21,6 +21,7 @@
 #include "fdevent.h"
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,6 +35,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
@@ -75,6 +77,8 @@
 static bool main_thread_valid;
 static uint64_t main_thread_id;
 
+static uint64_t fdevent_id;
+
 static bool run_needs_flush = false;
 static auto& run_queue_notify_fd = *new unique_fd();
 static auto& run_queue_mutex = *new std::mutex();
@@ -111,7 +115,8 @@
     if (fde->state & FDE_ERROR) {
         state += "E";
     }
-    return android::base::StringPrintf("(fdevent %d %s)", fde->fd.get(), state.c_str());
+    return android::base::StringPrintf("(fdevent %" PRIu64 ": fd %d %s)", fde->id, fde->fd.get(),
+                                       state.c_str());
 }
 
 void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
@@ -125,6 +130,7 @@
     CHECK_GE(fd, 0);
 
     fdevent* fde = new fdevent();
+    fde->id = fdevent_id++;
     fde->state = FDE_ACTIVE;
     fde->fd.reset(fd);
     fde->func = func;
@@ -352,10 +358,56 @@
     }
 }
 
+static void fdevent_check_spin(uint64_t cycle) {
+    // Check to see if we're spinning because we forgot about an fdevent
+    // by keeping track of how long fdevents have been continuously pending.
+    struct SpinCheck {
+        fdevent* fde;
+        std::chrono::steady_clock::time_point timestamp;
+        uint64_t cycle;
+    };
+    static auto& g_continuously_pending = *new std::unordered_map<uint64_t, SpinCheck>();
+
+    auto now = std::chrono::steady_clock::now();
+    for (auto* fde : g_pending_list) {
+        auto it = g_continuously_pending.find(fde->id);
+        if (it == g_continuously_pending.end()) {
+            g_continuously_pending[fde->id] =
+                    SpinCheck{.fde = fde, .timestamp = now, .cycle = cycle};
+        } else {
+            it->second.cycle = cycle;
+        }
+    }
+
+    for (auto it = g_continuously_pending.begin(); it != g_continuously_pending.end();) {
+        if (it->second.cycle != cycle) {
+            it = g_continuously_pending.erase(it);
+        } else {
+            // Use an absurdly long window, since all we really care about is
+            // getting a bugreport eventually.
+            if (now - it->second.timestamp > std::chrono::minutes(5)) {
+                LOG(FATAL_WITHOUT_ABORT) << "detected spin in fdevent: " << dump_fde(it->second.fde);
+#if defined(__linux__)
+                int fd = it->second.fde->fd.get();
+                std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+                std::string path;
+                if (!android::base::Readlink(fd_path, &path)) {
+                    PLOG(FATAL_WITHOUT_ABORT) << "readlink of fd " << fd << " failed";
+                }
+                LOG(FATAL_WITHOUT_ABORT) << "fd " << fd << " = " << path;
+#endif
+                abort();
+            }
+            ++it;
+        }
+    }
+}
+
 void fdevent_loop() {
     set_main_thread();
     fdevent_run_setup();
 
+    uint64_t cycle = 0;
     while (true) {
         if (terminate_loop) {
             return;
@@ -365,6 +417,8 @@
 
         fdevent_process();
 
+        fdevent_check_spin(cycle++);
+
         while (!g_pending_list.empty()) {
             fdevent* fde = g_pending_list.front();
             g_pending_list.pop_front();
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 69c4072..d501b86 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -32,8 +32,7 @@
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
 struct fdevent {
-    fdevent* next = nullptr;
-    fdevent* prev = nullptr;
+    uint64_t id;
 
     unique_fd fd;
     int force_eof = 0;
diff --git a/adb/services.cpp b/adb/services.cpp
index a757d90..b613d83 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -181,6 +181,29 @@
     kick_transport(t);
 }
 
+static void spin_service(int fd, void*) {
+    unique_fd sfd(fd);
+
+    if (!__android_log_is_debuggable()) {
+        WriteFdExactly(sfd.get(), "refusing to spin on non-debuggable build\n");
+        return;
+    }
+
+    // A service that creates an fdevent that's always pending, and then ignores it.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        WriteFdExactly(sfd.get(), "failed to create pipe\n");
+        return;
+    }
+
+    fdevent_run_on_main_thread([fd = pipe_read.release()]() {
+        fdevent* fde = fdevent_create(fd, [](int, unsigned, void*) {}, nullptr);
+        fdevent_add(fde, FDE_READ);
+    });
+
+    WriteFdExactly(sfd.get(), "spinning\n");
+}
+
 int reverse_service(const char* command, atransport* transport) {
     int s[2];
     if (adb_socketpair(s)) {
@@ -328,6 +351,8 @@
                                     reinterpret_cast<void*>(1));
     } else if (!strcmp(name, "reconnect")) {
         ret = create_service_thread("reconnect", reconnect_service, transport);
+    } else if (!strcmp(name, "spin")) {
+        ret = create_service_thread("spin", spin_service, nullptr);
 #endif
     }
     if (ret >= 0) {
diff --git a/adb/transport.h b/adb/transport.h
index ae9cc02..cb20615 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -92,6 +92,8 @@
     std::string transport_name_;
     ReadCallback read_callback_;
     ErrorCallback error_callback_;
+
+    static std::unique_ptr<Connection> FromFd(unique_fd fd);
 };
 
 // Abstraction for a blocking packet transport.
diff --git a/adb/transport_benchmark.cpp b/adb/transport_benchmark.cpp
index da24aa7..022808f 100644
--- a/adb/transport_benchmark.cpp
+++ b/adb/transport_benchmark.cpp
@@ -24,13 +24,19 @@
 #include "sysdeps.h"
 #include "transport.h"
 
-#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...)               \
-    BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
-        ->Arg(1)                                                    \
-        ->Arg(16384)                                                \
-        ->Arg(MAX_PAYLOAD)                                          \
+#define ADB_CONNECTION_BENCHMARK(benchmark_name, ...)                          \
+    BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__)            \
+        ->Arg(1)                                                               \
+        ->Arg(16384)                                                           \
+        ->Arg(MAX_PAYLOAD)                                                     \
+        ->UseRealTime();                                                       \
+    BENCHMARK_TEMPLATE(benchmark_name, NonblockingFdConnection, ##__VA_ARGS__) \
+        ->Arg(1)                                                               \
+        ->Arg(16384)                                                           \
+        ->Arg(MAX_PAYLOAD)                                                     \
         ->UseRealTime()
 
+struct NonblockingFdConnection;
 template <typename ConnectionType>
 std::unique_ptr<Connection> MakeConnection(unique_fd fd);
 
@@ -40,6 +46,11 @@
     return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
 }
 
+template <>
+std::unique_ptr<Connection> MakeConnection<NonblockingFdConnection>(unique_fd fd) {
+    return Connection::FromFd(std::move(fd));
+}
+
 template <typename ConnectionType>
 void BM_Connection_Unidirectional(benchmark::State& state) {
     int fds[2];
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
new file mode 100644
index 0000000..85f3c52
--- /dev/null
+++ b/adb/transport_fd.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <deque>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+#include "sysdeps/memory.h"
+#include "transport.h"
+#include "types.h"
+
+static void CreateWakeFds(unique_fd* read, unique_fd* write) {
+    // TODO: eventfd on linux?
+    int wake_fds[2];
+    int rc = adb_socketpair(wake_fds);
+    set_file_block_mode(wake_fds[0], false);
+    set_file_block_mode(wake_fds[1], false);
+    CHECK_EQ(0, rc);
+    *read = unique_fd(wake_fds[0]);
+    *write = unique_fd(wake_fds[1]);
+}
+
+struct NonblockingFdConnection : public Connection {
+    NonblockingFdConnection(unique_fd fd) : started_(false), fd_(std::move(fd)) {
+        set_file_block_mode(fd_.get(), false);
+        CreateWakeFds(&wake_fd_read_, &wake_fd_write_);
+    }
+
+    void SetRunning(bool value) {
+        std::lock_guard<std::mutex> lock(run_mutex_);
+        running_ = value;
+    }
+
+    bool IsRunning() {
+        std::lock_guard<std::mutex> lock(run_mutex_);
+        return running_;
+    }
+
+    void Run(std::string* error) {
+        SetRunning(true);
+        while (IsRunning()) {
+            adb_pollfd pfds[2] = {
+                {.fd = fd_.get(), .events = POLLIN},
+                {.fd = wake_fd_read_.get(), .events = POLLIN},
+            };
+
+            {
+                std::lock_guard<std::mutex> lock(this->write_mutex_);
+                if (!writable_) {
+                    pfds[0].events |= POLLOUT;
+                }
+            }
+
+            int rc = adb_poll(pfds, 2, -1);
+            if (rc == -1) {
+                *error = android::base::StringPrintf("poll failed: %s", strerror(errno));
+                return;
+            } else if (rc == 0) {
+                LOG(FATAL) << "poll timed out with an infinite timeout?";
+            }
+
+            if (pfds[0].revents) {
+                if ((pfds[0].revents & POLLOUT)) {
+                    std::lock_guard<std::mutex> lock(this->write_mutex_);
+                    WriteResult result = DispatchWrites();
+                    switch (result) {
+                        case WriteResult::Error:
+                            *error = "write failed";
+                            return;
+
+                        case WriteResult::Completed:
+                            writable_ = true;
+                            break;
+
+                        case WriteResult::TryAgain:
+                            break;
+                    }
+                }
+
+                if (pfds[0].revents & POLLIN) {
+                    // TODO: Should we be getting blocks from a free list?
+                    auto block = std::make_unique<IOVector::block_type>(MAX_PAYLOAD);
+                    rc = adb_read(fd_.get(), &(*block)[0], block->size());
+                    if (rc == -1) {
+                        *error = std::string("read failed: ") + strerror(errno);
+                        return;
+                    } else if (rc == 0) {
+                        *error = "read failed: EOF";
+                        return;
+                    }
+                    block->resize(rc);
+                    read_buffer_.append(std::move(block));
+
+                    if (!read_header_ && read_buffer_.size() >= sizeof(amessage)) {
+                        auto header_buf = read_buffer_.take_front(sizeof(amessage)).coalesce();
+                        CHECK_EQ(sizeof(amessage), header_buf.size());
+                        read_header_ = std::make_unique<amessage>();
+                        memcpy(read_header_.get(), header_buf.data(), sizeof(amessage));
+                    }
+
+                    if (read_header_ && read_buffer_.size() >= read_header_->data_length) {
+                        auto data_chain = read_buffer_.take_front(read_header_->data_length);
+
+                        // TODO: Make apacket carry around a IOVector instead of coalescing.
+                        auto payload = data_chain.coalesce<apacket::payload_type>();
+                        auto packet = std::make_unique<apacket>();
+                        packet->msg = *read_header_;
+                        packet->payload = std::move(payload);
+                        read_header_ = nullptr;
+                        read_callback_(this, std::move(packet));
+                    }
+                }
+            }
+
+            if (pfds[1].revents) {
+                uint64_t buf;
+                rc = adb_read(wake_fd_read_.get(), &buf, sizeof(buf));
+                CHECK_EQ(static_cast<int>(sizeof(buf)), rc);
+
+                // We were woken up either to add POLLOUT to our events, or to exit.
+                // Do nothing.
+            }
+        }
+    }
+
+    void Start() override final {
+        if (started_.exchange(true)) {
+            LOG(FATAL) << "Connection started multiple times?";
+        }
+
+        thread_ = std::thread([this]() {
+            std::string error = "connection closed";
+            Run(&error);
+            this->error_callback_(this, error);
+        });
+    }
+
+    void Stop() override final {
+        SetRunning(false);
+        WakeThread();
+        thread_.join();
+    }
+
+    void WakeThread() {
+        uint64_t buf = 0;
+        if (TEMP_FAILURE_RETRY(adb_write(wake_fd_write_.get(), &buf, sizeof(buf))) != sizeof(buf)) {
+            LOG(FATAL) << "failed to wake up thread";
+        }
+    }
+
+    enum class WriteResult {
+        Error,
+        Completed,
+        TryAgain,
+    };
+
+    WriteResult DispatchWrites() REQUIRES(write_mutex_) {
+        CHECK(!write_buffer_.empty());
+        if (!writable_) {
+            return WriteResult::TryAgain;
+        }
+
+        auto iovs = write_buffer_.iovecs();
+        ssize_t rc = adb_writev(fd_.get(), iovs.data(), iovs.size());
+        if (rc == -1) {
+            return WriteResult::Error;
+        } else if (rc == 0) {
+            errno = 0;
+            return WriteResult::Error;
+        }
+
+        // TODO: Implement a more efficient drop_front?
+        write_buffer_.take_front(rc);
+        if (write_buffer_.empty()) {
+            return WriteResult::Completed;
+        }
+
+        // There's data left in the range, which means our write returned early.
+        return WriteResult::TryAgain;
+    }
+
+    bool Write(std::unique_ptr<apacket> packet) final {
+        std::lock_guard<std::mutex> lock(write_mutex_);
+        const char* header_begin = reinterpret_cast<const char*>(&packet->msg);
+        const char* header_end = header_begin + sizeof(packet->msg);
+        auto header_block = std::make_unique<IOVector::block_type>(header_begin, header_end);
+        write_buffer_.append(std::move(header_block));
+        if (!packet->payload.empty()) {
+            write_buffer_.append(std::make_unique<IOVector::block_type>(std::move(packet->payload)));
+        }
+        return DispatchWrites() != WriteResult::Error;
+    }
+
+    std::thread thread_;
+
+    std::atomic<bool> started_;
+    std::mutex run_mutex_;
+    bool running_ GUARDED_BY(run_mutex_);
+
+    std::unique_ptr<amessage> read_header_;
+    IOVector read_buffer_;
+
+    unique_fd fd_;
+    unique_fd wake_fd_read_;
+    unique_fd wake_fd_write_;
+
+    std::mutex write_mutex_;
+    bool writable_ GUARDED_BY(write_mutex_) = true;
+    IOVector write_buffer_ GUARDED_BY(write_mutex_);
+
+    IOVector incoming_queue_;
+};
+
+std::unique_ptr<Connection> Connection::FromFd(unique_fd fd) {
+    return std::make_unique<NonblockingFdConnection>(std::move(fd));
+}
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 923442f..b0b4839 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -57,12 +57,15 @@
         "libavb",
         "libfstab",
         "libdm",
+        "liblp",
     ],
     export_static_lib_headers: [
         "libfstab",
         "libdm",
+        "liblp",
     ],
     whole_static_libs: [
+        "liblp",
         "liblogwrap",
         "libdm",
         "libfstab",
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index b2f3a68..ed42d40 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -37,6 +37,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <liblp/reader.h>
 
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_dm_ioctl.h"
@@ -137,5 +138,30 @@
     return nullptr;
 }
 
+bool CreateLogicalPartitions(const std::string& block_device) {
+    uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
+    auto metadata = ReadMetadata(block_device.c_str(), slot);
+    if (!metadata) {
+        LOG(ERROR) << "Could not read partition table.";
+        return true;
+    }
+
+    LogicalPartitionTable table;
+    for (const auto& partition : metadata->partitions) {
+        LogicalPartition new_partition;
+        new_partition.name = GetPartitionName(partition);
+        new_partition.attributes = partition.attributes;
+        for (size_t i = 0; i < partition.num_extents; i++) {
+            const auto& extent = metadata->extents[partition.first_extent_index + i];
+            new_partition.extents.emplace_back(new_partition.num_sectors, extent.target_data,
+                                               extent.num_sectors, block_device.c_str());
+            new_partition.num_sectors += extent.num_sectors;
+        }
+        table.partitions.push_back(new_partition);
+    }
+
+    return CreateLogicalPartitions(table);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 7f928e5..9772c4b 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -92,6 +92,7 @@
 //   /dev/block/dm-<name> where |name| is the partition name.
 //
 bool CreateLogicalPartitions(const LogicalPartitionTable& table);
+bool CreateLogicalPartitions(const std::string& block_device);
 
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
new file mode 100644
index 0000000..0ca8938
--- /dev/null
+++ b/fs_mgr/liblp/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "liblp",
+    host_supported: true,
+    recovery_available: true,
+    defaults: ["fs_mgr_defaults"],
+    cppflags: [
+        "-D_FILE_OFFSET_BITS=64",
+    ],
+    srcs: [
+        "builder.cpp",
+        "reader.cpp",
+        "utility.cpp",
+        "writer.cpp",
+    ],
+    static_libs: [
+        "libbase",
+        "liblog",
+        "libcrypto",
+        "libcrypto_utils",
+    ],
+    whole_static_libs: [
+        "libext2_uuid",
+        "libext4_utils",
+        "libsparse",
+        "libz",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
new file mode 100644
index 0000000..a084893
--- /dev/null
+++ b/fs_mgr/liblp/builder.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "liblp/builder.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include <uuid/uuid.h>
+
+#include "liblp/metadata_format.h"
+#include "utility.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Align a byte count up to the nearest 512-byte sector.
+template <typename T>
+static inline T AlignToSector(T value) {
+    return (value + (LP_SECTOR_SIZE - 1)) & ~T(LP_SECTOR_SIZE - 1);
+}
+
+void LinearExtent::AddTo(LpMetadata* out) const {
+    out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_});
+}
+
+void ZeroExtent::AddTo(LpMetadata* out) const {
+    out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
+}
+
+Partition::Partition(const std::string& name, const std::string& guid, uint32_t attributes)
+    : name_(name), guid_(guid), attributes_(attributes), size_(0) {}
+
+void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
+    size_ += extent->num_sectors() * LP_SECTOR_SIZE;
+    extents_.push_back(std::move(extent));
+}
+
+void Partition::RemoveExtents() {
+    size_ = 0;
+    extents_.clear();
+}
+
+void Partition::ShrinkTo(uint64_t requested_size) {
+    uint64_t aligned_size = AlignToSector(requested_size);
+    if (size_ <= aligned_size) {
+        return;
+    }
+    if (aligned_size == 0) {
+        RemoveExtents();
+        return;
+    }
+
+    // Remove or shrink extents of any kind until the total partition size is
+    // equal to the requested size.
+    uint64_t sectors_to_remove = (size_ - aligned_size) / LP_SECTOR_SIZE;
+    while (sectors_to_remove) {
+        Extent* extent = extents_.back().get();
+        if (extent->num_sectors() > sectors_to_remove) {
+            size_ -= sectors_to_remove * LP_SECTOR_SIZE;
+            extent->set_num_sectors(extent->num_sectors() - sectors_to_remove);
+            break;
+        }
+        size_ -= (extent->num_sectors() * LP_SECTOR_SIZE);
+        sectors_to_remove -= extent->num_sectors();
+        extents_.pop_back();
+    }
+    DCHECK(size_ == requested_size);
+}
+
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(uint64_t blockdevice_size,
+                                                      uint32_t metadata_max_size,
+                                                      uint32_t metadata_slot_count) {
+    std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
+    if (!builder->Init(blockdevice_size, metadata_max_size, metadata_slot_count)) {
+        return nullptr;
+    }
+    return builder;
+}
+
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) {
+    std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
+    if (!builder->Init(metadata)) {
+        return nullptr;
+    }
+    return builder;
+}
+
+MetadataBuilder::MetadataBuilder() {
+    memset(&geometry_, 0, sizeof(geometry_));
+    geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
+    geometry_.struct_size = sizeof(geometry_);
+
+    memset(&header_, 0, sizeof(header_));
+    header_.magic = LP_METADATA_HEADER_MAGIC;
+    header_.major_version = LP_METADATA_MAJOR_VERSION;
+    header_.minor_version = LP_METADATA_MINOR_VERSION;
+    header_.header_size = sizeof(header_);
+    header_.partitions.entry_size = sizeof(LpMetadataPartition);
+    header_.extents.entry_size = sizeof(LpMetadataExtent);
+}
+
+bool MetadataBuilder::Init(const LpMetadata& metadata) {
+    geometry_ = metadata.geometry;
+
+    for (const auto& partition : metadata.partitions) {
+        Partition* builder = AddPartition(GetPartitionName(partition), GetPartitionGuid(partition),
+                                          partition.attributes);
+        if (!builder) {
+            return false;
+        }
+
+        for (size_t i = 0; i < partition.num_extents; i++) {
+            const LpMetadataExtent& extent = metadata.extents[partition.first_extent_index + i];
+            if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
+                auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_data);
+                builder->AddExtent(std::move(copy));
+            } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
+                auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
+                builder->AddExtent(std::move(copy));
+            }
+        }
+    }
+    return true;
+}
+
+bool MetadataBuilder::Init(uint64_t blockdevice_size, uint32_t metadata_max_size,
+                           uint32_t metadata_slot_count) {
+    if (metadata_max_size < sizeof(LpMetadataHeader)) {
+        LERROR << "Invalid metadata maximum size.";
+        return false;
+    }
+    if (metadata_slot_count == 0) {
+        LERROR << "Invalid metadata slot count.";
+        return false;
+    }
+
+    // Align the metadata size up to the nearest sector.
+    metadata_max_size = AlignToSector(metadata_max_size);
+
+    // We reserve a geometry block (4KB) plus space for each copy of the
+    // maximum size of a metadata blob. Then, we double that space since
+    // we store a backup copy of everything.
+    uint64_t reserved =
+            LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
+    uint64_t total_reserved = reserved * 2;
+
+    if (blockdevice_size < total_reserved || blockdevice_size - total_reserved < LP_SECTOR_SIZE) {
+        LERROR << "Attempting to create metadata on a block device that is too small.";
+        return false;
+    }
+
+    // The last sector is inclusive. We subtract one to make sure that logical
+    // partitions won't overlap with the same sector as the backup metadata,
+    // which could happen if the block device was not aligned to LP_SECTOR_SIZE.
+    geometry_.first_logical_sector = reserved / LP_SECTOR_SIZE;
+    geometry_.last_logical_sector = ((blockdevice_size - reserved) / LP_SECTOR_SIZE) - 1;
+    geometry_.metadata_max_size = metadata_max_size;
+    geometry_.metadata_slot_count = metadata_slot_count;
+    DCHECK(geometry_.last_logical_sector >= geometry_.first_logical_sector);
+    return true;
+}
+
+Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid,
+                                         uint32_t attributes) {
+    if (name.empty()) {
+        LERROR << "Partition must have a non-empty name.";
+        return nullptr;
+    }
+    if (FindPartition(name)) {
+        LERROR << "Attempting to create duplication partition with name: " << name;
+        return nullptr;
+    }
+    partitions_.push_back(std::make_unique<Partition>(name, guid, attributes));
+    return partitions_.back().get();
+}
+
+Partition* MetadataBuilder::FindPartition(const std::string& name) {
+    for (const auto& partition : partitions_) {
+        if (partition->name() == name) {
+            return partition.get();
+        }
+    }
+    return nullptr;
+}
+
+void MetadataBuilder::RemovePartition(const std::string& name) {
+    for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
+        if ((*iter)->name() == name) {
+            partitions_.erase(iter);
+            return;
+        }
+    }
+}
+
+bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) {
+    // Align the space needed up to the nearest sector.
+    uint64_t aligned_size = AlignToSector(requested_size);
+    if (partition->size() >= aligned_size) {
+        return true;
+    }
+
+    // Figure out how much we need to allocate.
+    uint64_t space_needed = aligned_size - partition->size();
+    uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
+    DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
+
+    struct Interval {
+        uint64_t start;
+        uint64_t end;
+
+        Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
+        bool operator<(const Interval& other) const { return start < other.start; }
+    };
+    std::vector<Interval> intervals;
+
+    // Collect all extents in the partition table.
+    for (const auto& partition : partitions_) {
+        for (const auto& extent : partition->extents()) {
+            LinearExtent* linear = extent->AsLinearExtent();
+            if (!linear) {
+                continue;
+            }
+            intervals.emplace_back(linear->physical_sector(),
+                                   linear->physical_sector() + extent->num_sectors());
+        }
+    }
+
+    // Sort extents by starting sector.
+    std::sort(intervals.begin(), intervals.end());
+
+    // Find gaps that we can use for new extents. Note we store new extents in a
+    // temporary vector, and only commit them if we are guaranteed enough free
+    // space.
+    std::vector<std::unique_ptr<LinearExtent>> new_extents;
+    for (size_t i = 1; i < intervals.size(); i++) {
+        const Interval& previous = intervals[i - 1];
+        const Interval& current = intervals[i];
+
+        if (previous.end >= current.start) {
+            // There is no gap between these two extents, try the next one. Note that
+            // extents may never overlap, but just for safety, we ignore them if they
+            // do.
+            DCHECK(previous.end == current.start);
+            continue;
+        }
+
+        // This gap is enough to hold the remainder of the space requested, so we
+        // can allocate what we need and return.
+        if (current.start - previous.end >= sectors_needed) {
+            auto extent = std::make_unique<LinearExtent>(sectors_needed, previous.end);
+            sectors_needed -= extent->num_sectors();
+            new_extents.push_back(std::move(extent));
+            break;
+        }
+
+        // This gap is not big enough to fit the remainder of the space requested,
+        // so consume the whole thing and keep looking for more.
+        auto extent = std::make_unique<LinearExtent>(current.start - previous.end, previous.end);
+        sectors_needed -= extent->num_sectors();
+        new_extents.push_back(std::move(extent));
+    }
+
+    // If we still have more to allocate, take it from the remaining free space
+    // in the allocatable region.
+    if (sectors_needed) {
+        uint64_t first_sector;
+        if (intervals.empty()) {
+            first_sector = geometry_.first_logical_sector;
+        } else {
+            first_sector = intervals.back().end;
+        }
+        DCHECK(first_sector <= geometry_.last_logical_sector);
+
+        // Note: the last usable sector is inclusive.
+        if (first_sector + sectors_needed > geometry_.last_logical_sector) {
+            LERROR << "Not enough free space to expand partition: " << partition->name();
+            return false;
+        }
+        auto extent = std::make_unique<LinearExtent>(sectors_needed, first_sector);
+        new_extents.push_back(std::move(extent));
+    }
+
+    for (auto& extent : new_extents) {
+        partition->AddExtent(std::move(extent));
+    }
+    return true;
+}
+
+void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t requested_size) {
+    partition->ShrinkTo(requested_size);
+}
+
+std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
+    std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
+    metadata->header = header_;
+    metadata->geometry = geometry_;
+
+    // Flatten the partition and extent structures into an LpMetadata, which
+    // makes it very easy to validate, serialize, or pass on to device-mapper.
+    for (const auto& partition : partitions_) {
+        LpMetadataPartition part;
+        memset(&part, 0, sizeof(part));
+
+        if (partition->name().size() > sizeof(part.name)) {
+            LERROR << "Partition name is too long: " << partition->name();
+            return nullptr;
+        }
+        if (partition->attributes() & ~(LP_PARTITION_ATTRIBUTE_MASK)) {
+            LERROR << "Partition " << partition->name() << " has unsupported attribute.";
+            return nullptr;
+        }
+
+        strncpy(part.name, partition->name().c_str(), sizeof(part.name));
+        if (uuid_parse(partition->guid().c_str(), part.guid) != 0) {
+            LERROR << "Could not parse guid " << partition->guid() << " for partition "
+                   << partition->name();
+            return nullptr;
+        }
+
+        part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
+        part.num_extents = static_cast<uint32_t>(partition->extents().size());
+        part.attributes = partition->attributes();
+
+        for (const auto& extent : partition->extents()) {
+            extent->AddTo(metadata.get());
+        }
+        metadata->partitions.push_back(part);
+    }
+
+    metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
+    metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
+    return metadata;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
new file mode 100644
index 0000000..fb982e2
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -0,0 +1,169 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef LIBLP_METADATA_BUILDER_H
+#define LIBLP_METADATA_BUILDER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+
+#include "metadata_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+class LinearExtent;
+
+// Abstraction around dm-targets that can be encoded into logical partition tables.
+class Extent {
+  public:
+    explicit Extent(uint64_t num_sectors) : num_sectors_(num_sectors) {}
+    virtual ~Extent() {}
+
+    virtual void AddTo(LpMetadata* out) const = 0;
+    virtual LinearExtent* AsLinearExtent() { return nullptr; }
+
+    uint64_t num_sectors() const { return num_sectors_; }
+    void set_num_sectors(uint64_t num_sectors) { num_sectors_ = num_sectors; }
+
+  protected:
+    uint64_t num_sectors_;
+};
+
+// This corresponds to a dm-linear target.
+class LinearExtent final : public Extent {
+  public:
+    LinearExtent(uint64_t num_sectors, uint64_t physical_sector)
+        : Extent(num_sectors), physical_sector_(physical_sector) {}
+
+    void AddTo(LpMetadata* metadata) const override;
+    LinearExtent* AsLinearExtent() override { return this; }
+
+    uint64_t physical_sector() const { return physical_sector_; }
+
+  private:
+    uint64_t physical_sector_;
+};
+
+// This corresponds to a dm-zero target.
+class ZeroExtent final : public Extent {
+  public:
+    explicit ZeroExtent(uint64_t num_sectors) : Extent(num_sectors) {}
+
+    void AddTo(LpMetadata* out) const override;
+};
+
+class Partition final {
+  public:
+    Partition(const std::string& name, const std::string& guid, uint32_t attributes);
+
+    // Add a raw extent.
+    void AddExtent(std::unique_ptr<Extent>&& extent);
+
+    // Remove all extents from this partition.
+    void RemoveExtents();
+
+    // Remove and/or shrink extents until the partition is the requested size.
+    // See MetadataBuilder::ShrinkPartition for more information.
+    void ShrinkTo(uint64_t requested_size);
+
+    const std::string& name() const { return name_; }
+    uint32_t attributes() const { return attributes_; }
+    const std::string& guid() const { return guid_; }
+    const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; }
+    uint64_t size() const { return size_; }
+
+  private:
+    std::string name_;
+    std::string guid_;
+    std::vector<std::unique_ptr<Extent>> extents_;
+    uint32_t attributes_;
+    uint64_t size_;
+};
+
+class MetadataBuilder {
+  public:
+    // Construct an empty logical partition table builder. The block device size
+    // and maximum metadata size must be specified, as this will determine which
+    // areas of the physical partition can be flashed for metadata vs for logical
+    // partitions.
+    //
+    // If the parameters would yield invalid metadata, nullptr is returned. This
+    // could happen if the block device size is too small to store the metadata
+    // and backup copies.
+    static std::unique_ptr<MetadataBuilder> New(uint64_t blockdevice_size,
+                                                uint32_t metadata_max_size,
+                                                uint32_t metadata_slot_count);
+
+    // Import an existing table for modification. If the table is not valid, for
+    // example it contains duplicate partition names, then nullptr is returned.
+    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
+
+    // Export metadata so it can be serialized to an image, to disk, or mounted
+    // via device-mapper.
+    std::unique_ptr<LpMetadata> Export();
+
+    // Add a partition, returning a handle so it can be sized as needed. If a
+    // partition with the given name already exists, nullptr is returned.
+    Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes);
+
+    // Delete a partition by name if it exists.
+    void RemovePartition(const std::string& name);
+
+    // Find a partition by name. If no partition is found, nullptr is returned.
+    Partition* FindPartition(const std::string& name);
+
+    // Grow a partition to the requested size. If the partition's size is already
+    // greater or equal to the requested size, this will return true and the
+    // partition table will not be changed. Otherwise, a greedy algorithm is
+    // used to find free gaps in the partition table and allocate them for this
+    // partition. If not enough space can be allocated, false is returned, and
+    // the parition table will not be modified.
+    //
+    // The size will be rounded UP to the nearest sector.
+    //
+    // Note, this is an in-memory operation, and it does not alter the
+    // underlying filesystem or contents of the partition on disk.
+    bool GrowPartition(Partition* partition, uint64_t requested_size);
+
+    // Shrink a partition to the requested size. If the partition is already
+    // smaller than the given size, this will return and the partition table
+    // will not be changed. Otherwise, extents will be removed and/or shrunk
+    // from the end of the partition until it is the requested size.
+    //
+    // The size will be rounded UP to the nearest sector.
+    //
+    // Note, this is an in-memory operation, and it does not alter the
+    // underlying filesystem or contents of the partition on disk.
+    void ShrinkPartition(Partition* partition, uint64_t requested_size);
+
+  private:
+    MetadataBuilder();
+    bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count);
+    bool Init(const LpMetadata& metadata);
+
+    LpMetadataGeometry geometry_;
+    LpMetadataHeader header_;
+    std::vector<std::unique_ptr<Partition>> partitions_;
+};
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif /* LIBLP_METADATA_BUILDER_H */
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
new file mode 100644
index 0000000..6a2c655
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGICAL_PARTITION_METADATA_FORMAT_H_
+#define LOGICAL_PARTITION_METADATA_FORMAT_H_
+
+#ifdef __cplusplus
+#include <string>
+#include <vector>
+#endif
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Magic signature for LpMetadataGeometry. */
+#define LP_METADATA_GEOMETRY_MAGIC 0x616c4467
+
+/* Space reserved for geometry information. */
+#define LP_METADATA_GEOMETRY_SIZE 4096
+
+/* Magic signature for LpMetadataHeader. */
+#define LP_METADATA_HEADER_MAGIC 0x414C5030
+
+/* Current metadata version. */
+#define LP_METADATA_MAJOR_VERSION 1
+#define LP_METADATA_MINOR_VERSION 0
+
+/* Attributes for the LpMetadataPartition::attributes field.
+ *
+ * READONLY - The partition should not be considered writable. When used with
+ * device mapper, the block device will be created as read-only.
+ */
+#define LP_PARTITION_ATTR_READONLY 0x1
+
+/* Mask that defines all valid attributes. */
+#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
+
+/* Default name of the physical partition that holds logical partition entries.
+ * The layout of this partition will look like:
+ *
+ *     +--------------------+
+ *     | Disk Geometry      |
+ *     +--------------------+
+ *     | Metadata           |
+ *     +--------------------+
+ *     | Logical Partitions |
+ *     +--------------------+
+ *     | Backup Metadata    |
+ *     +--------------------+
+ *     | Geometry Backup    |
+ *     +--------------------+
+ */
+#define LP_METADATA_PARTITION_NAME "android"
+
+/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
+#define LP_SECTOR_SIZE 512
+
+/* This structure is stored at sector 0 in the first 4096 bytes of the
+ * partition, and again in the very last 4096 bytes. It is never modified and
+ * describes how logical partition information can be located.
+ */
+typedef struct LpMetadataGeometry {
+    /*  0: Magic signature (LP_METADATA_GEOMETRY_MAGIC). */
+    uint32_t magic;
+
+    /*  4: Size of the LpMetadataGeometry struct. */
+    uint32_t struct_size;
+
+    /*  8: SHA256 checksum of this struct, with this field set to 0. */
+    uint8_t checksum[32];
+
+    /* 40: Maximum amount of space a single copy of the metadata can use. */
+    uint32_t metadata_max_size;
+
+    /* 44: Number of copies of the metadata to keep. For A/B devices, this
+     * will be 2. For an A/B/C device, it would be 3, et cetera. For Non-A/B
+     * it will be 1. A backup copy of each slot is kept, so if this is "2",
+     * there will be four copies total.
+     */
+    uint32_t metadata_slot_count;
+
+    /* 48: First usable sector for allocating logical partitions. this will be
+     * the first sector after the initial 4096 geometry block, followed by the
+     * space consumed by metadata_max_size*metadata_slot_count.
+     */
+    uint64_t first_logical_sector;
+
+    /* 56: Last usable sector, inclusive, for allocating logical partitions.
+     * At the end of this sector will follow backup metadata slots and the
+     * backup geometry block at the very end.
+     */
+    uint64_t last_logical_sector;
+} __attribute__((packed)) LpMetadataGeometry;
+
+/* The logical partition metadata has a number of tables; they are described
+ * in the header via the following structure.
+ *
+ * The size of the table can be computed by multiplying entry_size by
+ * num_entries, and the result must not overflow a 32-bit signed integer.
+ */
+typedef struct LpMetadataTableDescriptor {
+    /*  0: Location of the table, relative to the metadata header. */
+    uint32_t offset;
+    /*  4: Number of entries in the table. */
+    uint32_t num_entries;
+    /*  8: Size of each entry in the table, in bytes. */
+    uint32_t entry_size;
+} __attribute__((packed)) LpMetadataTableDescriptor;
+
+/* Binary format for the header of the logical partition metadata format.
+ *
+ * The format has three sections. The header must occur first, and the
+ * proceeding tables may be placed in any order after.
+ *
+ *  +-----------------------------------------+
+ *  | Header data - fixed size                |
+ *  +-----------------------------------------+
+ *  | Partition table - variable size         |
+ *  +-----------------------------------------+
+ *  | Partition table extents - variable size |
+ *  +-----------------------------------------+
+ *
+ * The "Header" portion is described by LpMetadataHeader. It will always
+ * precede the other three blocks.
+ *
+ * All fields are stored in little-endian byte order when serialized.
+ *
+ * This struct is versioned; see the |major_version| and |minor_version|
+ * fields.
+ */
+typedef struct LpMetadataHeader {
+    /*  0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
+    uint32_t magic;
+
+    /*  4: Version number required to read this metadata. If the version is not
+     * equal to the library version, the metadata should be considered
+     * incompatible.
+     */
+    uint16_t major_version;
+
+    /*  6: Minor version. A library supporting newer features should be able to
+     * read metadata with an older minor version. However, an older library
+     * should not support reading metadata if its minor version is higher.
+     */
+    uint16_t minor_version;
+
+    /*  8: The size of this header struct. */
+    uint32_t header_size;
+
+    /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
+     * if this field were set to 0.
+     */
+    uint8_t header_checksum[32];
+
+    /* 44: The total size of all tables. This size is contiguous; tables may not
+     * have gaps in between, and they immediately follow the header.
+     */
+    uint32_t tables_size;
+
+    /* 48: SHA256 checksum of all table contents. */
+    uint8_t tables_checksum[32];
+
+    /* 80: Partition table descriptor. */
+    LpMetadataTableDescriptor partitions;
+    /* 92: Extent table descriptor. */
+    LpMetadataTableDescriptor extents;
+} __attribute__((packed)) LpMetadataHeader;
+
+/* This struct defines a logical partition entry, similar to what would be
+ * present in a GUID Partition Table.
+ */
+typedef struct LpMetadataPartition {
+    /*  0: Name of this partition in ASCII characters. Any unused characters in
+     * the buffer must be set to 0. Characters may only be alphanumeric or _.
+     * The name must include at least one ASCII character, and it must be unique
+     * across all partition names. The length (36) is the same as the maximum
+     * length of a GPT partition name.
+     */
+    char name[36];
+
+    /* 36: Globally unique identifier (GUID) of this partition. */
+    uint8_t guid[16];
+
+    /* 52: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
+    uint32_t attributes;
+
+    /* 56: Index of the first extent owned by this partition. The extent will
+     * start at logical sector 0. Gaps between extents are not allowed.
+     */
+    uint32_t first_extent_index;
+
+    /* 60: Number of extents in the partition. Every partition must have at
+     * least one extent.
+     */
+    uint32_t num_extents;
+} __attribute__((packed)) LpMetadataPartition;
+
+/* This extent is a dm-linear target, and the index is an index into the
+ * LinearExtent table.
+ */
+#define LP_TARGET_TYPE_LINEAR 0
+
+/* This extent is a dm-zero target. The index is ignored and must be 0. */
+#define LP_TARGET_TYPE_ZERO 1
+
+/* This struct defines an extent entry in the extent table block. */
+typedef struct LpMetadataExtent {
+    /*  0: Length of this extent, in 512-byte sectors. */
+    uint64_t num_sectors;
+
+    /*  8: Target type for device-mapper (see LP_TARGET_TYPE_* values). */
+    uint32_t target_type;
+
+    /* 12: Contents depends on target_type.
+     *
+     * LINEAR: The sector on the physical partition that this extent maps onto.
+     * ZERO: This field must be 0.
+     */
+    uint64_t target_data;
+} __attribute__((packed)) LpMetadataExtent;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#ifdef __cplusplus
+namespace android {
+namespace fs_mgr {
+
+// Helper structure for easily interpreting deserialized metadata, or
+// re-serializing metadata.
+struct LpMetadata {
+    LpMetadataGeometry geometry;
+    LpMetadataHeader header;
+    std::vector<LpMetadataPartition> partitions;
+    std::vector<LpMetadataExtent> extents;
+};
+
+// Helper to extract safe C++ strings from partition info.
+std::string GetPartitionName(const LpMetadataPartition& partition);
+std::string GetPartitionGuid(const LpMetadataPartition& partition);
+
+// Helper to return a slot number for a slot suffix.
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+
+}  // namespace fs_mgr
+}  // namespace android
+#endif
+
+#endif /* LOGICAL_PARTITION_METADATA_FORMAT_H_ */
diff --git a/fs_mgr/liblp/include/liblp/reader.h b/fs_mgr/liblp/include/liblp/reader.h
new file mode 100644
index 0000000..e7fa46d
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/reader.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBLP_READER_H_
+#define LIBLP_READER_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "metadata_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Read logical partition metadata from its predetermined location on a block
+// device. If readback fails, we also attempt to load from a backup copy.
+std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number);
+
+// Read and validate the logical partition geometry from a block device.
+bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry);
+
+// Read logical partition metadata from an image file that was created with
+// WriteToImageFile().
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif /* LIBLP_READER_H_ */
diff --git a/fs_mgr/liblp/include/liblp/writer.h b/fs_mgr/liblp/include/liblp/writer.h
new file mode 100644
index 0000000..02fb21f
--- /dev/null
+++ b/fs_mgr/liblp/include/liblp/writer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBLP_WRITER_H
+#define LIBLP_WRITER_H
+
+#include "metadata_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+// When flashing the initial logical partition layout, we also write geometry
+// information at the start and end of the big physical partition. This helps
+// locate metadata and backup metadata in the case of corruption or a failed
+// update. For normal changes to the metadata, we never modify the geometry.
+enum class SyncMode {
+    // Write geometry information.
+    Flash,
+    // Normal update of a single slot.
+    Update
+};
+
+// Write the given partition table to the given block device, writing only
+// copies according to the given sync mode.
+//
+// This will perform some verification, such that the device has enough space
+// to store the metadata as well as all of its extents.
+//
+// The slot number indicates which metadata slot to use.
+bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
+                         uint32_t slot_number);
+
+// Helper function to serialize geometry and metadata to a normal file, for
+// flashing or debugging.
+bool WriteToImageFile(const char* file, const LpMetadata& metadata);
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif /* LIBLP_WRITER_H */
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
new file mode 100644
index 0000000..328fe37
--- /dev/null
+++ b/fs_mgr/liblp/reader.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "liblp/reader.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <functional>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+
+#include "utility.h"
+
+namespace android {
+namespace fs_mgr {
+
+// Parse an LpMetadataGeometry from a buffer. The buffer must be at least
+// LP_METADATA_GEOMETRY_SIZE bytes in size.
+static bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
+    static_assert(sizeof(*geometry) <= LP_METADATA_GEOMETRY_SIZE);
+    memcpy(geometry, buffer, sizeof(*geometry));
+
+    // Check the magic signature.
+    if (geometry->magic != LP_METADATA_GEOMETRY_MAGIC) {
+        LERROR << "Logical partition metadata has invalid geometry magic signature.";
+        return false;
+    }
+    // Recompute and check the CRC32.
+    {
+        LpMetadataGeometry temp = *geometry;
+        memset(&temp.checksum, 0, sizeof(temp.checksum));
+        SHA256(&temp, sizeof(temp), temp.checksum);
+        if (memcmp(temp.checksum, geometry->checksum, sizeof(temp.checksum)) != 0) {
+            LERROR << "Logical partition metadata has invalid geometry checksum.";
+            return false;
+        }
+    }
+    // Check that the struct size is equal (this will have to change if we ever
+    // change the struct size in a release).
+    if (geometry->struct_size != sizeof(LpMetadataGeometry)) {
+        LERROR << "Logical partition metadata has invalid struct size.";
+        return false;
+    }
+    if (geometry->metadata_slot_count == 0) {
+        LERROR << "Logical partition metadata has invalid slot count.";
+        return false;
+    }
+
+    // Check that the metadata area and logical partition areas don't overlap.
+    int64_t end_of_metadata =
+            GetPrimaryMetadataOffset(*geometry, geometry->metadata_slot_count - 1) +
+            geometry->metadata_max_size;
+    if (uint64_t(end_of_metadata) > geometry->first_logical_sector * LP_SECTOR_SIZE) {
+        LERROR << "Logical partition metadata overlaps with logical partition contents.";
+        return false;
+    }
+    return true;
+}
+
+// Read and validate geometry information from a block device that holds
+// logical partitions. If the information is corrupted, this will attempt
+// to read it from a secondary backup location.
+static bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
+    // Read the first 4096 bytes.
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
+    if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed";
+        return false;
+    }
+    if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
+        PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
+        return false;
+    }
+    if (ParseGeometry(buffer.get(), geometry)) {
+        return true;
+    }
+
+    // Try the backup copy in the last 4096 bytes.
+    if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
+        return false;
+    }
+    if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
+        PERROR << __PRETTY_FUNCTION__ << "backup read " << LP_METADATA_GEOMETRY_SIZE
+               << " bytes failed";
+        return false;
+    }
+    return ParseGeometry(buffer.get(), geometry);
+}
+
+// Helper function to read geometry from a device without an open descriptor.
+bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry) {
+    android::base::unique_fd fd(open(block_device, O_RDONLY));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        return false;
+    }
+    return ReadLogicalPartitionGeometry(fd, geometry);
+}
+
+static bool ValidateTableBounds(const LpMetadataHeader& header,
+                                const LpMetadataTableDescriptor& table) {
+    if (table.offset > header.tables_size) {
+        return false;
+    }
+    uint64_t table_size = uint64_t(table.num_entries) * table.entry_size;
+    if (header.tables_size - table.offset < table_size) {
+        return false;
+    }
+    return true;
+}
+
+static bool ValidateMetadataHeader(const LpMetadataHeader& header) {
+    // To compute the header's checksum, we have to temporarily set its checksum
+    // field to 0.
+    {
+        LpMetadataHeader temp = header;
+        memset(&temp.header_checksum, 0, sizeof(temp.header_checksum));
+        SHA256(&temp, sizeof(temp), temp.header_checksum);
+        if (memcmp(temp.header_checksum, header.header_checksum, sizeof(temp.header_checksum)) != 0) {
+            LERROR << "Logical partition metadata has invalid checksum.";
+            return false;
+        }
+    }
+
+    // Do basic validation of key metadata bits.
+    if (header.magic != LP_METADATA_HEADER_MAGIC) {
+        LERROR << "Logical partition metadata has invalid magic value.";
+        return false;
+    }
+    // Check that the version is compatible.
+    if (header.major_version != LP_METADATA_MAJOR_VERSION ||
+        header.minor_version > LP_METADATA_MINOR_VERSION) {
+        LERROR << "Logical partition metadata has incompatible version.";
+        return false;
+    }
+    if (!ValidateTableBounds(header, header.partitions) ||
+        !ValidateTableBounds(header, header.extents)) {
+        LERROR << "Logical partition metadata has invalid table bounds.";
+        return false;
+    }
+    // Check that table entry sizes can accomodate their respective structs. If
+    // table sizes change, these checks will have to be adjusted.
+    if (header.partitions.entry_size != sizeof(LpMetadataPartition)) {
+        LERROR << "Logical partition metadata has invalid partition table entry size.";
+        return false;
+    }
+    if (header.extents.entry_size != sizeof(LpMetadataExtent)) {
+        LERROR << "Logical partition metadata has invalid extent table entry size.";
+        return false;
+    }
+    return true;
+}
+
+using ReadMetadataFn = std::function<bool(void* buffer, size_t num_bytes)>;
+
+// Parse and validate all metadata at the current position in the given file
+// descriptor.
+static std::unique_ptr<LpMetadata> ParseMetadata(int fd) {
+    // First read and validate the header.
+    std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
+    if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) {
+        PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed";
+        return nullptr;
+    }
+    if (!ValidateMetadataHeader(metadata->header)) {
+        return nullptr;
+    }
+
+    LpMetadataHeader& header = metadata->header;
+
+    // Read the metadata payload. Allocation is fallible in case the metadata is
+    // corrupt and has some huge value.
+    std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[header.tables_size]);
+    if (!buffer) {
+        LERROR << "Out of memory reading logical partition tables.";
+        return nullptr;
+    }
+    if (!android::base::ReadFully(fd, buffer.get(), header.tables_size)) {
+        PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed";
+        return nullptr;
+    }
+
+    uint8_t checksum[32];
+    SHA256(buffer.get(), header.tables_size, checksum);
+    if (memcmp(checksum, header.tables_checksum, sizeof(checksum)) != 0) {
+        LERROR << "Logical partition metadata has invalid table checksum.";
+        return nullptr;
+    }
+
+    // ValidateTableSize ensured that |cursor| is valid for the number of
+    // entries in the table.
+    uint8_t* cursor = buffer.get() + header.partitions.offset;
+    for (size_t i = 0; i < header.partitions.num_entries; i++) {
+        LpMetadataPartition partition;
+        memcpy(&partition, cursor, sizeof(partition));
+        cursor += header.partitions.entry_size;
+
+        if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK) {
+            LERROR << "Logical partition has invalid attribute set.";
+            return nullptr;
+        }
+        if (partition.first_extent_index + partition.num_extents > header.extents.num_entries) {
+            LERROR << "Logical partition has invalid extent list.";
+            return nullptr;
+        }
+
+        metadata->partitions.push_back(partition);
+    }
+
+    cursor = buffer.get() + header.extents.offset;
+    for (size_t i = 0; i < header.extents.num_entries; i++) {
+        LpMetadataExtent extent;
+        memcpy(&extent, cursor, sizeof(extent));
+        cursor += header.extents.entry_size;
+
+        metadata->extents.push_back(extent);
+    }
+
+    return metadata;
+}
+
+std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
+    android::base::unique_fd fd(open(block_device, O_RDONLY));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        return nullptr;
+    }
+    LpMetadataGeometry geometry;
+    if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+        return nullptr;
+    }
+
+    // First try the primary copy.
+    int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
+    if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+        return nullptr;
+    }
+    if (std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd)) {
+        return metadata;
+    }
+
+    // Next try the backup copy.
+    offset = GetBackupMetadataOffset(geometry, slot_number);
+    if (SeekFile64(fd, offset, SEEK_END) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+        return nullptr;
+    }
+    return ParseMetadata(fd);
+}
+
+std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
+    android::base::unique_fd fd(open(file, O_RDONLY));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+        return nullptr;
+    }
+
+    LpMetadataGeometry geometry;
+    if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+        return nullptr;
+    }
+    if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
+        return nullptr;
+    }
+    std::unique_ptr<LpMetadata> metadata = ParseMetadata(fd);
+    if (!metadata) {
+        return nullptr;
+    }
+    metadata->geometry = geometry;
+    return metadata;
+}
+
+static std::string NameFromFixedArray(const char* name, size_t buffer_size) {
+    // If the end of the buffer has a null character, it's safe to assume the
+    // buffer is null terminated. Otherwise, we cap the string to the input
+    // buffer size.
+    if (name[buffer_size - 1] == '\0') {
+        return std::string(name);
+    }
+    return std::string(name, buffer_size);
+}
+
+std::string GetPartitionName(const LpMetadataPartition& partition) {
+    return NameFromFixedArray(partition.name, sizeof(partition.name));
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
new file mode 100644
index 0000000..217d802
--- /dev/null
+++ b/fs_mgr/liblp/utility.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <ext4_utils/ext4_utils.h>
+#include <openssl/sha.h>
+#include <uuid/uuid.h>
+
+#include "utility.h"
+
+namespace android {
+namespace fs_mgr {
+
+bool GetDescriptorSize(int fd, uint64_t* size) {
+    struct stat s;
+    if (fstat(fd, &s) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "fstat failed";
+        return false;
+    }
+
+    if (S_ISBLK(s.st_mode)) {
+        return get_block_device_size(fd);
+    }
+
+    int64_t result = SeekFile64(fd, 0, SEEK_END);
+    if (result == -1) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed";
+        return false;
+    }
+
+    *size = result;
+    return true;
+}
+
+int64_t SeekFile64(int fd, int64_t offset, int whence) {
+    static_assert(sizeof(off_t) == sizeof(int64_t), "Need 64-bit lseek");
+    return lseek(fd, offset, whence);
+}
+
+int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
+    CHECK(slot_number < geometry.metadata_slot_count);
+
+    int64_t offset = LP_METADATA_GEOMETRY_SIZE + geometry.metadata_max_size * slot_number;
+    CHECK(offset + geometry.metadata_max_size <=
+          int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
+    return offset;
+}
+
+int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
+    CHECK(slot_number < geometry.metadata_slot_count);
+    int64_t start = int64_t(-LP_METADATA_GEOMETRY_SIZE) -
+                    int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
+    return start + int64_t(geometry.metadata_max_size * slot_number);
+}
+
+void SHA256(const void* data, size_t length, uint8_t out[32]) {
+    SHA256_CTX c;
+    SHA256_Init(&c);
+    SHA256_Update(&c, data, length);
+    SHA256_Final(out, &c);
+}
+
+std::string GetPartitionGuid(const LpMetadataPartition& partition) {
+    // 32 hex characters, four hyphens. Unfortunately libext2_uuid provides no
+    // macro to assist with buffer sizing.
+    static const size_t kGuidLen = 36;
+    char buffer[kGuidLen + 1];
+    uuid_unparse(partition.guid, buffer);
+    return buffer;
+}
+
+uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
+    if (suffix.empty()) {
+        return 0;
+    }
+    if (suffix.size() != 2 || suffix[0] != '_' || suffix[1] < 'a') {
+        LERROR << __PRETTY_FUNCTION__ << "slot '" << suffix
+               << "' does not have a recognized format.";
+        return 0;
+    }
+    return suffix[1] - 'a';
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
new file mode 100644
index 0000000..09ed314
--- /dev/null
+++ b/fs_mgr/liblp/utility.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBLP_UTILITY_H
+#define LIBLP_UTILITY_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+
+#include "liblp/metadata_format.h"
+
+#define LP_TAG "[liblp]"
+#define LERROR LOG(ERROR) << LP_TAG
+#define PERROR PLOG(ERROR) << LP_TAG
+
+namespace android {
+namespace fs_mgr {
+
+// Determine the size of a block device (or file). Logs and returns false on
+// error. After calling this, the position of |fd| may have changed.
+bool GetDescriptorSize(int fd, uint64_t* size);
+
+// Return the offset of a primary metadata slot, relative to the start of the
+// device.
+int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);
+
+// Return the offset of a backup metadata slot, relative to the end of the
+// device.
+int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);
+
+// Cross-platform helper for lseek64().
+int64_t SeekFile64(int fd, int64_t offset, int whence);
+
+// Compute a SHA256 hash.
+void SHA256(const void* data, size_t length, uint8_t out[32]);
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif  // LIBLP_UTILITY_H
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
new file mode 100644
index 0000000..6a9c124
--- /dev/null
+++ b/fs_mgr/liblp/writer.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+
+#include "liblp/reader.h"
+#include "liblp/writer.h"
+#include "utility.h"
+
+namespace android {
+namespace fs_mgr {
+
+static std::string SerializeGeometry(const LpMetadataGeometry& input) {
+    LpMetadataGeometry geometry = input;
+    memset(geometry.checksum, 0, sizeof(geometry.checksum));
+    SHA256(&geometry, sizeof(geometry), geometry.checksum);
+    return std::string(reinterpret_cast<const char*>(&geometry), sizeof(geometry));
+}
+
+static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
+    return g1.metadata_max_size == g2.metadata_max_size &&
+           g1.metadata_slot_count == g2.metadata_slot_count &&
+           g1.first_logical_sector == g2.first_logical_sector &&
+           g1.last_logical_sector == g2.last_logical_sector;
+}
+
+static std::string SerializeMetadata(const LpMetadata& input) {
+    LpMetadata metadata = input;
+    LpMetadataHeader& header = metadata.header;
+
+    // Serialize individual tables.
+    std::string partitions(reinterpret_cast<const char*>(metadata.partitions.data()),
+                           metadata.partitions.size() * sizeof(LpMetadataPartition));
+    std::string extents(reinterpret_cast<const char*>(metadata.extents.data()),
+                        metadata.extents.size() * sizeof(LpMetadataExtent));
+
+    // Compute positions of tables.
+    header.partitions.offset = 0;
+    header.extents.offset = header.partitions.offset + partitions.size();
+    header.tables_size = header.extents.offset + extents.size();
+
+    // Compute payload checksum.
+    std::string tables = partitions + extents;
+    SHA256(tables.data(), tables.size(), header.tables_checksum);
+
+    // Compute header checksum.
+    memset(header.header_checksum, 0, sizeof(header.header_checksum));
+    SHA256(&header, sizeof(header), header.header_checksum);
+
+    std::string header_blob =
+            std::string(reinterpret_cast<const char*>(&metadata.header), sizeof(metadata.header));
+    return header_blob + tables;
+}
+
+// Perform sanity checks so we don't accidentally overwrite valid metadata
+// with potentially invalid metadata, or random partition data with metadata.
+static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size,
+                                        uint64_t metadata_size) {
+    const LpMetadataHeader& header = metadata.header;
+    const LpMetadataGeometry& geometry = metadata.geometry;
+    // Validate the usable sector range.
+    if (geometry.first_logical_sector > geometry.last_logical_sector) {
+        LERROR << "Logical partition metadata has invalid sector range.";
+        return false;
+    }
+    // Make sure we're writing within the space reserved.
+    if (metadata_size > geometry.metadata_max_size) {
+        LERROR << "Logical partition metadata is too large.";
+        return false;
+    }
+
+    // Make sure the device has enough space to store two backup copies of the
+    // metadata.
+    uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
+                             uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
+    if (reserved_size > blockdevice_size ||
+        reserved_size > geometry.first_logical_sector * LP_SECTOR_SIZE) {
+        LERROR << "Not enough space to store all logical partition metadata slots.";
+        return false;
+    }
+    if (blockdevice_size - reserved_size < (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE) {
+        LERROR << "Not enough space to backup all logical partition metadata slots.";
+        return false;
+    }
+
+    // Make sure all partition entries reference valid extents.
+    for (const auto& partition : metadata.partitions) {
+        if (partition.first_extent_index + partition.num_extents > metadata.extents.size()) {
+            LERROR << "Partition references invalid extent.";
+            return false;
+        }
+    }
+
+    // Make sure all linear extents have a valid range.
+    for (const auto& extent : metadata.extents) {
+        if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
+            uint64_t physical_sector = extent.target_data;
+            if (physical_sector < geometry.first_logical_sector ||
+                physical_sector + extent.num_sectors > geometry.last_logical_sector) {
+                LERROR << "Extent table entry is out of bounds.";
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode,
+                         uint32_t slot_number) {
+    android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+        return false;
+    }
+
+    uint64_t size;
+    if (!GetDescriptorSize(fd, &size)) {
+        return false;
+    }
+
+    const LpMetadataGeometry& geometry = metadata.geometry;
+    if (sync_mode != SyncMode::Flash) {
+        // Verify that the old geometry is identical. If it's not, then we've
+        // based this new metadata on invalid assumptions.
+        LpMetadataGeometry old_geometry;
+        if (!ReadLogicalPartitionGeometry(block_device, &old_geometry)) {
+            return false;
+        }
+        if (!CompareGeometry(geometry, old_geometry)) {
+            LERROR << "Incompatible geometry in new logical partition metadata";
+            return false;
+        }
+    }
+
+    // Make sure we're writing to a valid metadata slot.
+    if (slot_number >= geometry.metadata_slot_count) {
+        LERROR << "Invalid logical partition metadata slot number.";
+        return false;
+    }
+
+    // Before writing geometry and/or logical partition tables, perform some
+    // basic checks that the geometry and tables are coherent, and will fit
+    // on the given block device.
+    std::string blob = SerializeMetadata(metadata);
+    if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) {
+        return false;
+    }
+
+    // First write geometry if this is a flash operation. It gets written to
+    // the first and last 4096-byte regions of the device.
+    if (sync_mode == SyncMode::Flash) {
+        std::string blob = SerializeGeometry(metadata.geometry);
+        if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+            PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
+            return false;
+        }
+        if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+            PERROR << __PRETTY_FUNCTION__ << "write " << blob.size()
+                   << " bytes failed: " << block_device;
+            return false;
+        }
+        if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+            PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
+            return false;
+        }
+        if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+            PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size()
+                   << " bytes failed: " << block_device;
+            return false;
+        }
+    }
+
+    // Write the primary copy of the metadata.
+    int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
+    if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset;
+        return false;
+    }
+    if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+        PERROR << __PRETTY_FUNCTION__ << "write " << blob.size()
+               << " bytes failed: " << block_device;
+        return false;
+    }
+
+    // Write the backup copy of the metadata.
+    int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
+    int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END);
+    if (abs_offset == (int64_t)-1) {
+        PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
+        return false;
+    }
+    if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) {
+        PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
+               << " is within logical partition bounds, sector " << geometry.last_logical_sector;
+        return false;
+    }
+    if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
+        PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size()
+               << " bytes failed: " << block_device;
+        return false;
+    }
+    return true;
+}
+
+bool WriteToImageFile(const char* file, const LpMetadata& input) {
+    std::string geometry = SerializeGeometry(input.geometry);
+    std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0');
+    std::string metadata = SerializeMetadata(input);
+
+    std::string everything = geometry + padding + metadata;
+
+    android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+    if (fd < 0) {
+        PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+        return false;
+    }
+    if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
+        PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed: " << file;
+        return false;
+    }
+    return true;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 7d863c8..cf7637f 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -76,7 +76,6 @@
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
-        "libselinux",
     ],
     shared_libs: [
         "libcutils",
@@ -87,6 +86,7 @@
         "libc++",
         "libdl",
         "libz",
+        "libselinux",
     ],
 }
 
diff --git a/init/Android.mk b/init/Android.mk
index da27a73..a81a0f6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -61,7 +61,6 @@
     libseccomp_policy \
     libcrypto_utils \
     libsparse \
-    libselinux \
     libprocessgroup \
     libavb \
     libkeyutils \
@@ -76,6 +75,7 @@
     libcrypto \
     libdl \
     libz \
+    libselinux \
 
 ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
 # init is static executable for non-system-as-root devices, because the dynamic linker
diff --git a/init/README.md b/init/README.md
index 550ef05..b0a73b9 100644
--- a/init/README.md
+++ b/init/README.md
@@ -752,3 +752,22 @@
     kill -SIGCONT 4343
 
     > strace runs
+
+Host Init Script Verification
+-----------------------------
+
+Init scripts are checked for correctness during build time. Specifically the below is checked.
+
+1) Well formatted action, service and import sections, e.g. no actions without a preceding 'on'
+line, and no extraneous lines after an 'import' statement.
+2) All commands map to a valid keyword and the argument count is within the correct range.
+3) All service options are valid. This is stricter than how commands are checked as the service
+options' arguments are fully parsed, e.g. UIDs and GIDs must resolve.
+
+There are other parts of init scripts that are only parsed at runtime and therefore not checked
+during build time, among them are the below.
+
+1) The validity of the arguments of commands, e.g. no checking if file paths actually exist, if
+SELinux would permit the operation, or if the UIDs and GIDs resolve.
+2) No checking if a service exists or has a valid SELinux domain defined
+3) No checking if a service has not been previously defined in a different init script.
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 7e93b44..8407729 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -146,7 +146,7 @@
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<HostImportParser>());
 
-    if (!parser.ParseConfig(argv[1])) {
+    if (!parser.ParseConfigFileInsecure(argv[1])) {
         LOG(ERROR) << "Failed to open init rc script '" << argv[1] << "'";
         return EXIT_FAILURE;
     }
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index db60ce1..2bc9f3a 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -29,6 +29,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <liblp/metadata_format.h>
 
 #include "devices.h"
 #include "fs_mgr.h"
@@ -75,6 +76,7 @@
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
     std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
+    std::string lp_metadata_partition_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
     std::unique_ptr<DeviceHandler> device_handler_;
@@ -120,13 +122,17 @@
 }
 
 static inline bool IsDmLinearEnabled() {
-    bool enabled = false;
-    import_kernel_cmdline(
-        false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
-            if (key == "androidboot.logical_partitions" && value == "1") {
-                enabled = true;
-            }
-        });
+    static bool checked = false;
+    static bool enabled = false;
+    if (checked) {
+        return enabled;
+    }
+    import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+        if (key == "androidboot.logical_partitions" && value == "1") {
+            enabled = true;
+        }
+    });
+    checked = true;
     return enabled;
 }
 
@@ -163,7 +169,7 @@
 }
 
 bool FirstStageMount::DoFirstStageMount() {
-    if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
+    if (!IsDmLinearEnabled() && mount_fstab_recs_.empty()) {
         // Nothing to mount.
         LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
         return true;
@@ -184,14 +190,18 @@
 
 bool FirstStageMount::GetBackingDmLinearDevices() {
     // Add any additional devices required for dm-linear mappings.
-    if (!dm_linear_table_) {
+    if (!IsDmLinearEnabled()) {
         return true;
     }
 
-    for (const auto& partition : dm_linear_table_->partitions) {
-        for (const auto& extent : partition.extents) {
-            const std::string& partition_name = android::base::Basename(extent.block_device());
-            required_devices_partition_names_.emplace(partition_name);
+    required_devices_partition_names_.emplace(LP_METADATA_PARTITION_NAME);
+
+    if (dm_linear_table_) {
+        for (const auto& partition : dm_linear_table_->partitions) {
+            for (const auto& extent : partition.extents) {
+                const std::string& partition_name = android::base::Basename(extent.block_device());
+                required_devices_partition_names_.emplace(partition_name);
+            }
         }
     }
     return true;
@@ -205,7 +215,7 @@
         return true;
     }
 
-    if (dm_linear_table_ || need_dm_verity_) {
+    if (IsDmLinearEnabled() || need_dm_verity_) {
         const std::string dm_path = "/devices/virtual/misc/device-mapper";
         bool found = false;
         auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
@@ -253,10 +263,21 @@
 }
 
 bool FirstStageMount::CreateLogicalPartitions() {
-    if (!dm_linear_table_) {
+    if (!IsDmLinearEnabled()) {
         return true;
     }
-    return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
+
+    if (lp_metadata_partition_.empty()) {
+        LOG(ERROR) << "Could not locate logical partition tables in partition "
+                   << LP_METADATA_PARTITION_NAME;
+        return false;
+    }
+    if (dm_linear_table_) {
+        if (!android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get())) {
+            return false;
+        }
+    }
+    return android::fs_mgr::CreateLogicalPartitions(lp_metadata_partition_);
 }
 
 ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
@@ -266,6 +287,10 @@
     auto iter = required_devices_partition_names_.find(name);
     if (iter != required_devices_partition_names_.end()) {
         LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+        if (IsDmLinearEnabled() && name == LP_METADATA_PARTITION_NAME) {
+            std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
+            lp_metadata_partition_ = links[0];
+        }
         required_devices_partition_names_.erase(iter);
         device_handler_->HandleDeviceEvent(uevent);
         if (required_devices_partition_names_.empty()) {
diff --git a/init/parser.cpp b/init/parser.cpp
index 4f1cac4..fa0fd11 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 
 #include <android-base/chrono_utils.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -39,14 +40,13 @@
     line_callbacks_.emplace_back(prefix, callback);
 }
 
-void Parser::ParseData(const std::string& filename, const std::string& data) {
-    // TODO: Use a parser with const input and remove this copy
-    std::vector<char> data_copy(data.begin(), data.end());
-    data_copy.push_back('\0');
+void Parser::ParseData(const std::string& filename, std::string* data) {
+    data->push_back('\n');  // TODO: fix tokenizer
+    data->push_back('\0');
 
     parse_state state;
     state.line = 0;
-    state.ptr = &data_copy[0];
+    state.ptr = data->data();
     state.nexttoken = 0;
 
     SectionParser* section_parser = nullptr;
@@ -69,6 +69,11 @@
         switch (next_token(&state)) {
             case T_EOF:
                 end_section();
+
+                for (const auto& [section_name, section_parser] : section_parsers_) {
+                    section_parser->EndFile();
+                }
+
                 return;
             case T_NEWLINE: {
                 state.line++;
@@ -118,6 +123,16 @@
     }
 }
 
+bool Parser::ParseConfigFileInsecure(const std::string& path) {
+    std::string config_contents;
+    if (!android::base::ReadFileToString(path, &config_contents)) {
+        return false;
+    }
+
+    ParseData(path, &config_contents);
+    return true;
+}
+
 bool Parser::ParseConfigFile(const std::string& path) {
     LOG(INFO) << "Parsing file " << path << "...";
     android::base::Timer t;
@@ -127,11 +142,7 @@
         return false;
     }
 
-    config_contents->push_back('\n');  // TODO: fix parse_config.
-    ParseData(path, *config_contents);
-    for (const auto& [section_name, section_parser] : section_parsers_) {
-        section_parser->EndFile();
-    }
+    ParseData(path, &config_contents.value());
 
     LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
     return true;
diff --git a/init/parser.h b/init/parser.h
index 3501d8c..2454b6a 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -75,10 +75,13 @@
     void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
     void AddSingleLineParser(const std::string& prefix, LineCallback callback);
 
+    // Host init verifier check file permissions.
+    bool ParseConfigFileInsecure(const std::string& path);
+
     size_t parse_error_count() const { return parse_error_count_; }
 
   private:
-    void ParseData(const std::string& filename, const std::string& data);
+    void ParseData(const std::string& filename, std::string* data);
     bool ParseConfigFile(const std::string& path);
     bool ParseConfigDir(const std::string& path);
 
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 597a6bb..a8a9a12 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -3180,113 +3180,6 @@
 }
 #endif  // USING_LOGGER_DEFAULT
 
-#ifdef USING_LOGGER_DEFAULT  // Do not retest event mapping functionality
-#ifdef __ANDROID__
-// must be: '<needle:> 0 kB'
-static bool isZero(const std::string& content, std::string::size_type pos,
-                   const char* needle) {
-  std::string::size_type offset = content.find(needle, pos);
-  return (offset != std::string::npos) &&
-         ((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
-          std::string::npos) &&
-         (content.find_first_not_of('0', offset) != offset);
-}
-
-// must not be: '<needle:> 0 kB'
-static bool isNotZero(const std::string& content, std::string::size_type pos,
-                      const char* needle) {
-  std::string::size_type offset = content.find(needle, pos);
-  return (offset != std::string::npos) &&
-         ((offset = content.find_first_not_of(" \t", offset + strlen(needle))) !=
-          std::string::npos) &&
-         (content.find_first_not_of("123456789", offset) != offset);
-}
-
-static void event_log_tags_test_smap(pid_t pid) {
-  std::string filename = android::base::StringPrintf("/proc/%d/smaps", pid);
-
-  std::string content;
-  if (!android::base::ReadFileToString(filename, &content)) return;
-
-  bool shared_ok = false;
-  bool private_ok = false;
-  bool anonymous_ok = false;
-  bool pass_ok = false;
-
-  static const char event_log_tags[] = "event-log-tags";
-  std::string::size_type pos = 0;
-  while ((pos = content.find(event_log_tags, pos)) != std::string::npos) {
-    pos += strlen(event_log_tags);
-
-    // must not be: 'Shared_Clean: 0 kB'
-    bool ok =
-        isNotZero(content, pos, "Shared_Clean:") ||
-        // If not /etc/event-log-tags, thus r/w, then half points
-        // back for not 'Shared_Dirty: 0 kB'
-        ((content.substr(pos - 5 - strlen(event_log_tags), 5) != "/etc/") &&
-         isNotZero(content, pos, "Shared_Dirty:"));
-    if (ok && !pass_ok) {
-      shared_ok = true;
-    } else if (!ok) {
-      shared_ok = false;
-    }
-
-    // must be: 'Private_Dirty: 0 kB' and 'Private_Clean: 0 kB'
-    ok = isZero(content, pos, "Private_Dirty:") ||
-         isZero(content, pos, "Private_Clean:");
-    if (ok && !pass_ok) {
-      private_ok = true;
-    } else if (!ok) {
-      private_ok = false;
-    }
-
-    // must be: 'Anonymous: 0 kB'
-    ok = isZero(content, pos, "Anonymous:");
-    if (ok && !pass_ok) {
-      anonymous_ok = true;
-    } else if (!ok) {
-      anonymous_ok = false;
-    }
-
-    pass_ok = true;
-  }
-  content = "";
-
-  if (!pass_ok) return;
-  if (shared_ok && anonymous_ok && private_ok) return;
-
-  filename = android::base::StringPrintf("/proc/%d/comm", pid);
-  android::base::ReadFileToString(filename, &content);
-  content = android::base::StringPrintf(
-      "%d:%s", pid, content.substr(0, content.find('\n')).c_str());
-
-  EXPECT_TRUE(IsOk(shared_ok, content));
-  EXPECT_TRUE(IsOk(private_ok, content));
-  EXPECT_TRUE(IsOk(anonymous_ok, content));
-}
-#endif  // __ANDROID__
-
-TEST(liblog, event_log_tags) {
-#ifdef __ANDROID__
-  std::unique_ptr<DIR, int (*)(DIR*)> proc_dir(opendir("/proc"), closedir);
-  ASSERT_FALSE(!proc_dir);
-
-  dirent* e;
-  while ((e = readdir(proc_dir.get()))) {
-    if (e->d_type != DT_DIR) continue;
-    if (!isdigit(e->d_name[0])) continue;
-    long long id = atoll(e->d_name);
-    if (id <= 0) continue;
-    pid_t pid = id;
-    if (id != pid) continue;
-    event_log_tags_test_smap(pid);
-  }
-#else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif  // USING_LOGGER_DEFAULT
-
 #ifdef USING_LOGGER_DEFAULT  // Do not retest ratelimit
 TEST(liblog, __android_log_ratelimit) {
   time_t state = 0;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 70b6a3e..478b8d0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -201,6 +201,7 @@
 	$$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $$@
 	$$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@
 	$$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@
+	$$(hide) sed -i -e 's?%PRODUCT%?$$(TARGET_COPY_OUT_PRODUCT)?g' $$@
 
 llndk_libraries_list :=
 vndksp_libraries_list :=
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index eebad2b..42dc7ab 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,7 +7,7 @@
 # absolute path of an executable is selected.
 dir.system = /system/bin/
 dir.system = /system/xbin/
-dir.system = /product/bin/
+dir.system = /%PRODUCT%/bin/
 
 dir.vendor = /odm/bin/
 dir.vendor = /vendor/bin/
@@ -39,7 +39,7 @@
 namespace.default.isolated = true
 
 namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${LIB}
 
 # We can't have entire /system/${LIB} as permitted paths because doing so
 # makes it possible to load libs in /system/${LIB}/vndk* directories by
@@ -51,8 +51,7 @@
 namespace.default.permitted.paths  = /system/${LIB}/drm
 namespace.default.permitted.paths += /system/${LIB}/extractors
 namespace.default.permitted.paths += /system/${LIB}/hw
-namespace.default.permitted.paths += /product/${LIB}
-namespace.default.permitted.paths += /system/product/${LIB}
+namespace.default.permitted.paths += /%PRODUCT%/${LIB}
 # These are where odex files are located. libart has to be able to dlopen the files
 namespace.default.permitted.paths += /system/framework
 namespace.default.permitted.paths += /system/app
@@ -64,12 +63,9 @@
 namespace.default.permitted.paths += /odm/app
 namespace.default.permitted.paths += /odm/priv-app
 namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /product/framework
-namespace.default.permitted.paths += /product/app
-namespace.default.permitted.paths += /product/priv-app
-namespace.default.permitted.paths += /system/product/framework
-namespace.default.permitted.paths += /system/product/app
-namespace.default.permitted.paths += /system/product/priv-app
+namespace.default.permitted.paths += /%PRODUCT%/framework
+namespace.default.permitted.paths += /%PRODUCT%/app
+namespace.default.permitted.paths += /%PRODUCT%/priv-app
 namespace.default.permitted.paths += /data
 namespace.default.permitted.paths += /mnt/expand
 
@@ -92,14 +88,10 @@
 namespace.default.asan.permitted.paths += /odm/app
 namespace.default.asan.permitted.paths += /odm/priv-app
 namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /product/${LIB}
-namespace.default.asan.permitted.paths += /product/framework
-namespace.default.asan.permitted.paths += /product/app
-namespace.default.asan.permitted.paths += /product/priv-app
-namespace.default.asan.permitted.paths += /system/product/${LIB}
-namespace.default.asan.permitted.paths += /system/product/framework
-namespace.default.asan.permitted.paths += /system/product/app
-namespace.default.asan.permitted.paths += /system/product/priv-app
+namespace.default.asan.permitted.paths += /%PRODUCT%/${LIB}
+namespace.default.asan.permitted.paths += /%PRODUCT%/framework
+namespace.default.asan.permitted.paths += /%PRODUCT%/app
+namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
 namespace.default.asan.permitted.paths += /mnt/expand
 
 ###############################################################################
@@ -335,7 +327,7 @@
 namespace.system.isolated = false
 
 namespace.system.search.paths  = /system/${LIB}
-namespace.system.search.paths += /product/${LIB}
+namespace.system.search.paths += /%PRODUCT%/${LIB}
 
 namespace.system.asan.search.paths  = /data/asan/system/${LIB}
 namespace.system.asan.search.paths +=           /system/${LIB}
@@ -353,4 +345,4 @@
 [postinstall]
 namespace.default.isolated = false
 namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${LIB}
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 6438e3d..7834dd5 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -1,24 +1,46 @@
 phony {
     name: "shell_and_utilities",
     required: [
+        "shell_and_utilities_system",
+        "shell_and_utilities_recovery",
+        "shell_and_utilities_vendor",
+    ],
+}
+
+phony {
+    name: "shell_and_utilities_system",
+    required: [
         "awk",
-        "awk_vendor",
         "bzip2",
         "grep",
-        "grep_vendor",
         "logwrapper",
-        "logwrapper_vendor",
         "mkshrc",
-        "mkshrc_vendor",
+        "newfs_msdos",
         "reboot",
         "sh",
-        "sh.recovery",
-        "sh_vendor",
         "toolbox",
-        "toolbox.recovery",
-        "toolbox_vendor",
         "toybox",
+    ],
+}
+
+phony {
+    name: "shell_and_utilities_recovery",
+    required: [
+        "sh.recovery",
+        "toolbox.recovery",
         "toybox.recovery",
+    ],
+}
+
+phony {
+    name: "shell_and_utilities_vendor",
+    required: [
+        "awk_vendor",
+        "grep_vendor",
+        "logwrapper_vendor",
+        "mkshrc_vendor",
+        "sh_vendor",
+        "toolbox_vendor",
         "toybox_vendor",
     ],
 }
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index b15be1f..e310e6b 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -193,13 +193,15 @@
 Android Q
 ---------
 
+BSD: fsck\_msdos newfs\_msdos
+
 bzip2: bzcat bzip2 bunzip2
 
 one-true-awk: awk
 
 PCRE: egrep fgrep grep
 
-toolbox: getevent getprop newfs\_msdos
+toolbox: getevent getprop
 
 toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
 chroot chrt cksum clear cmp comm cp cpio cut date dd df diff dirname
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index f12c810..fc51705 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -26,7 +26,6 @@
         "toolbox.c",
         "getevent.c",
         "getprop.cpp",
-        "newfs_msdos.c",
     ],
     generated_headers: [
         "toolbox_input_labels",
@@ -39,7 +38,6 @@
     symlinks: [
         "getevent",
         "getprop",
-        "newfs_msdos",
     ],
 }
 
@@ -62,10 +60,3 @@
     defaults: ["toolbox_defaults"],
     srcs: ["r.c"],
 }
-
-cc_binary_host {
-    name: "newfs_msdos",
-    defaults: ["toolbox_defaults"],
-    srcs: ["newfs_msdos.c"],
-    cflags: ["-Dnewfs_msdos_main=main"]
-}
diff --git a/toolbox/MODULE_LICENSE_BSD b/toolbox/MODULE_LICENSE_APACHE2
similarity index 100%
rename from toolbox/MODULE_LICENSE_BSD
rename to toolbox/MODULE_LICENSE_APACHE2
diff --git a/toolbox/NOTICE b/toolbox/NOTICE
index e9ab58d..8e8a91c 100644
--- a/toolbox/NOTICE
+++ b/toolbox/NOTICE
@@ -1,4 +1,4 @@
-Copyright (C) 2010 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -14,974 +14,3 @@
 
 -------------------------------------------------------------------
 
-Copyright (C) 2014, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1987, 1993
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1987, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1988, 1993
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Jeffrey Mogul.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1988, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1988, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-David Hitz of Auspex Systems Inc.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1988, 1993, 1994, 2003
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1989, 1993
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1989, 1993
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Kevin Fall.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1989, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Chris Newcomb.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1989, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Ken Smith of The State University of New York at Buffalo.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1990, 1993, 1994, 2003
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1991, 1993
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1991, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1991, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Keith Muller of the University of California, San Diego and Lance
-Visser of Convex Computer Corporation.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1992, 1993, 1994
-   The Regents of the University of California.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of the University nor the names of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
-All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation
-by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
-NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1998 Robert Nordier
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
-OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
-IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
-Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
-Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
-All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation
-by Luke Mewburn.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2007 The NetBSD Foundation, Inc.
-All rights reserved.
-
-This code is derived from software contributed to The NetBSD Foundation
-by Luke Mewburn.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2008, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2009, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2010 The NetBSD Foundation, Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2010, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2012, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2013, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
-Copyright (c) 2014, The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
- * Neither the name of Google, Inc. nor the names of its contributors
-   may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
diff --git a/toolbox/getprop.cpp b/toolbox/getprop.cpp
index 9e324a0..ca345cb 100644
--- a/toolbox/getprop.cpp
+++ b/toolbox/getprop.cpp
@@ -1,18 +1,18 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #include <getopt.h>
 #include <sys/system_properties.h>
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
deleted file mode 100644
index 5fc8b02..0000000
--- a/toolbox/newfs_msdos.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*
- * Copyright (c) 1998 Robert Nordier
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef lint
-static const char rcsid[] =
-        "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
-#endif /* not lint */
-
-#include <sys/param.h>
-
-#ifdef __APPLE__
-#elif defined(ANDROID)
-#include <linux/fs.h>
-#include <linux/hdreg.h>
-#include <stdarg.h>
-#include <sys/ioctl.h>
-#else
-#include <sys/fdcio.h>
-#include <sys/disk.h>
-#include <sys/disklabel.h>
-#include <sys/mount.h>
-#endif
-
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <paths.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
-#define MAXU16   0xffff     /* maximum unsigned 16-bit quantity */
-#define BPN      4          /* bits per nibble */
-#define NPB      2          /* nibbles per byte */
-
-#define DOSMAGIC  0xaa55    /* DOS magic number */
-#define MINBPS    512       /* minimum bytes per sector */
-#define MAXSPC    128       /* maximum sectors per cluster */
-#define MAXNFT    16        /* maximum number of FATs */
-#define DEFBLK    4096      /* default block size */
-#define DEFBLK16  2048      /* default block size FAT16 */
-#define DEFRDE    512       /* default root directory entries */
-#define RESFTE    2         /* reserved FAT entries */
-#define MINCLS12  1         /* minimum FAT12 clusters */
-#define MINCLS16  0x1000    /* minimum FAT16 clusters */
-#define MINCLS32  2         /* minimum FAT32 clusters */
-#define MAXCLS12  0xfed     /* maximum FAT12 clusters */
-#define MAXCLS16  0xfff5    /* maximum FAT16 clusters */
-#define MAXCLS32  0xffffff5 /* maximum FAT32 clusters */
-
-#define mincls(fat)  ((fat) == 12 ? MINCLS12 :    \
-                      (fat) == 16 ? MINCLS16 :    \
-                                        MINCLS32)
-
-#define maxcls(fat)  ((fat) == 12 ? MAXCLS12 :    \
-                      (fat) == 16 ? MAXCLS16 :    \
-                                        MAXCLS32)
-
-#define mk1(p, x)                           \
-    (p) = (u_int8_t)(x)
-
-#define mk2(p, x)                           \
-    (p)[0] = (u_int8_t)(x),                 \
-    (p)[1] = (u_int8_t)((x) >> 010)
-
-#define mk4(p, x)                           \
-    (p)[0] = (u_int8_t)(x),                 \
-    (p)[1] = (u_int8_t)((x) >> 010),        \
-    (p)[2] = (u_int8_t)((x) >> 020),        \
-    (p)[3] = (u_int8_t)((x) >> 030)
-
-#define argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
-#define argto2(arg, lo, msg)  argtou(arg, lo, 0xffff, msg)
-#define argto4(arg, lo, msg)  argtou(arg, lo, 0xffffffff, msg)
-#define argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
-
-struct bs {
-    u_int8_t jmp[3];        /* bootstrap entry point */
-    u_int8_t oem[8];        /* OEM name and version */
-};
-
-struct bsbpb {
-    u_int8_t bps[2];    /* bytes per sector */
-    u_int8_t spc;       /* sectors per cluster */
-    u_int8_t res[2];    /* reserved sectors */
-    u_int8_t nft;       /* number of FATs */
-    u_int8_t rde[2];    /* root directory entries */
-    u_int8_t sec[2];    /* total sectors */
-    u_int8_t mid;       /* media descriptor */
-    u_int8_t spf[2];    /* sectors per FAT */
-    u_int8_t spt[2];    /* sectors per track */
-    u_int8_t hds[2];    /* drive heads */
-    u_int8_t hid[4];    /* hidden sectors */
-    u_int8_t bsec[4];   /* big total sectors */
-};
-
-struct bsxbpb {
-    u_int8_t bspf[4];       /* big sectors per FAT */
-    u_int8_t xflg[2];       /* FAT control flags */
-    u_int8_t vers[2];       /* file system version */
-    u_int8_t rdcl[4];       /* root directory start cluster */
-    u_int8_t infs[2];       /* file system info sector */
-    u_int8_t bkbs[2];       /* backup boot sector */
-    u_int8_t rsvd[12];      /* reserved */
-};
-
-struct bsx {
-    u_int8_t drv;           /* drive number */
-    u_int8_t rsvd;          /* reserved */
-    u_int8_t sig;           /* extended boot signature */
-    u_int8_t volid[4];      /* volume ID number */
-    u_int8_t label[11];     /* volume label */
-    u_int8_t type[8];       /* file system type */
-};
-
-struct de {
-    u_int8_t namext[11];    /* name and extension */
-    u_int8_t attr;          /* attributes */
-    u_int8_t rsvd[10];      /* reserved */
-    u_int8_t time[2];       /* creation time */
-    u_int8_t date[2];       /* creation date */
-    u_int8_t clus[2];       /* starting cluster */
-    u_int8_t size[4];       /* size */
-};
-
-struct bpb {
-    u_int bps;          /* bytes per sector */
-    u_int spc;          /* sectors per cluster */
-    u_int res;          /* reserved sectors */
-    u_int nft;          /* number of FATs */
-    u_int rde;          /* root directory entries */
-    u_int sec;          /* total sectors */
-    u_int mid;          /* media descriptor */
-    u_int spf;          /* sectors per FAT */
-    u_int spt;          /* sectors per track */
-    u_int hds;          /* drive heads */
-    u_int hid;          /* hidden sectors */
-    u_int bsec;         /* big total sectors */
-    u_int bspf;         /* big sectors per FAT */
-    u_int rdcl;         /* root directory start cluster */
-    u_int infs;         /* file system info sector */
-    u_int bkbs;         /* backup boot sector */
-};
-
-#define BPBGAP 0, 0, 0, 0, 0, 0
-
-static struct {
-    const char *name;
-    struct bpb bpb;
-} const stdfmt[] = {
-    {"160",  {512, 1, 1, 2,  64,  320, 0xfe, 1,  8, 1, BPBGAP}},
-    {"180",  {512, 1, 1, 2,  64,  360, 0xfc, 2,  9, 1, BPBGAP}},
-    {"320",  {512, 2, 1, 2, 112,  640, 0xff, 1,  8, 2, BPBGAP}},
-    {"360",  {512, 2, 1, 2, 112,  720, 0xfd, 2,  9, 2, BPBGAP}},
-    {"640",  {512, 2, 1, 2, 112, 1280, 0xfb, 2,  8, 2, BPBGAP}},
-    {"720",  {512, 2, 1, 2, 112, 1440, 0xf9, 3,  9, 2, BPBGAP}},
-    {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
-    {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2,  8, 2, BPBGAP}},
-    {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
-    {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
-};
-
-static const u_int8_t bootcode[] = {
-    0xfa,               /* cli             */
-    0x31, 0xc0,         /* xor    ax,ax    */
-    0x8e, 0xd0,         /* mov    ss,ax    */
-    0xbc, 0x00, 0x7c,   /* mov    sp,7c00h */
-    0xfb,               /* sti             */
-    0x8e, 0xd8,         /* mov    ds,ax    */
-    0xe8, 0x00, 0x00,   /* call   $ + 3    */
-    0x5e,               /* pop    si       */
-    0x83, 0xc6, 0x19,   /* add    si,+19h  */
-    0xbb, 0x07, 0x00,   /* mov    bx,0007h */
-    0xfc,               /* cld             */
-    0xac,               /* lodsb           */
-    0x84, 0xc0,         /* test   al,al    */
-    0x74, 0x06,         /* jz     $ + 8    */
-    0xb4, 0x0e,         /* mov    ah,0eh   */
-    0xcd, 0x10,         /* int    10h      */
-    0xeb, 0xf5,         /* jmp    $ - 9    */
-    0x30, 0xe4,         /* xor    ah,ah    */
-    0xcd, 0x16,         /* int    16h      */
-    0xcd, 0x19,         /* int    19h      */
-    0x0d, 0x0a,
-    'N', 'o', 'n', '-', 's', 'y', 's', 't',
-    'e', 'm', ' ', 'd', 'i', 's', 'k',
-    0x0d, 0x0a,
-    'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
-    'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
-    ' ', 'r', 'e', 'b', 'o', 'o', 't',
-    0x0d, 0x0a,
-    0
-};
-
-static void check_mounted(const char *, mode_t);
-static void getstdfmt(const char *, struct bpb *);
-static void getdiskinfo(int, const char *, const char *, int, struct bpb *);
-static void print_bpb(struct bpb *);
-static u_int ckgeom(const char *, u_int, const char *);
-static u_int argtou(const char *, u_int, u_int, const char *);
-static off_t argtooff(const char *, const char *);
-static int oklabel(const char *);
-static void mklabel(u_int8_t *, const char *);
-static void setstr(u_int8_t *, const char *, size_t);
-static void usage(void);
-
-/*
- * Construct a FAT12, FAT16, or FAT32 file system.
- */
-int newfs_msdos_main(int argc, char *argv[])
-{
-    static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
-    const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
-    u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
-    u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
-    u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
-    u_int opt_A = 0;
-    int opt_N = 0;
-    int Iflag = 0, mflag = 0, oflag = 0;
-    char buf[MAXPATHLEN];
-    struct stat sb;
-    struct timeval tv;
-    struct bpb bpb;
-    struct tm *tm;
-    struct bs *bs;
-    struct bsbpb *bsbpb;
-    struct bsxbpb *bsxbpb;
-    struct bsx *bsx;
-    struct de *de;
-    u_int8_t *img;
-    const char *fname, *dtype, *bname;
-    ssize_t n;
-    time_t now;
-    u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
-    u_int extra_res, alignment=0, set_res, set_spf, set_spc, tempx, attempts=0;
-    int ch, fd, fd1;
-    off_t opt_create = 0, opt_ofs = 0;
-
-    while ((ch = getopt(argc, argv, opts)) != -1)
-        switch (ch) {
-        case '@':
-            opt_ofs = argtooff(optarg, "offset");
-            break;
-        case 'N':
-            opt_N = 1;
-            break;
-        case 'A':
-            opt_A = 1;
-            break;
-        case 'B':
-            opt_B = optarg;
-            break;
-        case 'C':
-            opt_create = argtooff(optarg, "create size");
-            break;
-        case 'F':
-            if (strcmp(optarg, "12") &&  strcmp(optarg, "16") && strcmp(optarg, "32"))
-                errx(1, "%s: bad FAT type", optarg);
-            opt_F = atoi(optarg);
-            break;
-        case 'I':
-            opt_I = argto4(optarg, 0, "volume ID");
-            Iflag = 1;
-            break;
-        case 'L':
-            if (!oklabel(optarg))
-                errx(1, "%s: bad volume label", optarg);
-            opt_L = optarg;
-            break;
-        case 'O':
-            if (strlen(optarg) > 8)
-                errx(1, "%s: bad OEM string", optarg);
-            opt_O = optarg;
-            break;
-        case 'S':
-            opt_S = argto2(optarg, 1, "bytes/sector");
-            break;
-        case 'a':
-            opt_a = argto4(optarg, 1, "sectors/FAT");
-            break;
-        case 'b':
-            opt_b = argtox(optarg, 1, "block size");
-            opt_c = 0;
-            break;
-        case 'c':
-            opt_c = argto1(optarg, 1, "sectors/cluster");
-            opt_b = 0;
-            break;
-        case 'e':
-            opt_e = argto2(optarg, 1, "directory entries");
-            break;
-        case 'f':
-            opt_f = optarg;
-            break;
-        case 'h':
-            opt_h = argto2(optarg, 1, "drive heads");
-            break;
-        case 'i':
-            opt_i = argto2(optarg, 1, "info sector");
-            break;
-        case 'k':
-            opt_k = argto2(optarg, 1, "backup sector");
-            break;
-        case 'm':
-            opt_m = argto1(optarg, 0, "media descriptor");
-            mflag = 1;
-            break;
-        case 'n':
-            opt_n = argto1(optarg, 1, "number of FATs");
-            break;
-        case 'o':
-            opt_o = argto4(optarg, 0, "hidden sectors");
-            oflag = 1;
-            break;
-        case 'r':
-            opt_r = argto2(optarg, 1, "reserved sectors");
-            break;
-        case 's':
-            opt_s = argto4(optarg, 1, "file system size");
-            break;
-        case 'u':
-            opt_u = argto2(optarg, 1, "sectors/track");
-            break;
-        default:
-            usage();
-        }
-    argc -= optind;
-    argv += optind;
-    if (argc < 1 || argc > 2)
-        usage();
-    fname = *argv++;
-    if (!opt_create && !strchr(fname, '/')) {
-        snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
-        if (!(fname = strdup(buf)))
-            err(1, "%s", buf);
-    }
-    dtype = *argv;
-    if (opt_A) {
-        if (opt_r)
-            errx(1, "align (-A) is incompatible with -r");
-        if (opt_N)
-            errx(1, "align (-A) is incompatible with -N");
-    }
-    if (opt_create) {
-        if (opt_N)
-            errx(1, "create (-C) is incompatible with -N");
-        fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
-        if (fd == -1)
-            errx(1, "failed to create %s", fname);
-        if (ftruncate(fd, opt_create))
-            errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
-    } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1)
-        err(1, "%s", fname);
-    if (fstat(fd, &sb))
-        err(1, "%s", fname);
-    if (opt_create) {
-        if (!S_ISREG(sb.st_mode))
-            warnx("warning, %s is not a regular file", fname);
-    } else {
-        if (!S_ISCHR(sb.st_mode))
-            warnx("warning, %s is not a character device", fname);
-    }
-    if (!opt_N)
-        check_mounted(fname, sb.st_mode);
-    if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
-        errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
-    memset(&bpb, 0, sizeof(bpb));
-    if (opt_f) {
-        getstdfmt(opt_f, &bpb);
-        bpb.bsec = bpb.sec;
-        bpb.sec = 0;
-        bpb.bspf = bpb.spf;
-        bpb.spf = 0;
-    }
-    if (opt_h)
-        bpb.hds = opt_h;
-    if (opt_u)
-        bpb.spt = opt_u;
-    if (opt_S)
-        bpb.bps = opt_S;
-    if (opt_s)
-        bpb.bsec = opt_s;
-    if (oflag)
-        bpb.hid = opt_o;
-    if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
-        off_t delta;
-        getdiskinfo(fd, fname, dtype, oflag, &bpb);
-        if (opt_s) {
-            bpb.bsec = opt_s;
-        }
-        bpb.bsec -= (opt_ofs / bpb.bps);
-        delta = bpb.bsec % bpb.spt;
-        if (delta != 0) {
-            warnx("trim %d sectors from %d to adjust to a multiple of %d",
-                  (int)delta, bpb.bsec, bpb.spt);
-            bpb.bsec -= delta;
-        }
-        if (bpb.spc == 0) {    /* set defaults */
-            if (bpb.bsec <= 6000)    /* about 3MB -> 512 bytes */
-                bpb.spc = 1;
-            else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
-                bpb.spc = 8;
-            else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
-                bpb.spc = 16;
-            else if (bpb.bsec <= (1<<22)) /* 2G -> 16k, some versions of windows
-                                         require a minimum of 65527 clusters */
-                bpb.spc = 32;
-            else
-                bpb.spc = 64;        /* otherwise 32k */
-        }
-    }
-    if (!powerof2(bpb.bps))
-        errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
-    if (bpb.bps < MINBPS)
-        errx(1, "bytes/sector (%u) is too small; minimum is %u",
-             bpb.bps, MINBPS);
-    if (!(fat = opt_F)) {
-        if (opt_f)
-            fat = 12;
-        else if (!opt_e && (opt_i || opt_k))
-            fat = 32;
-    }
-    if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
-        errx(1, "-%c is not a legal FAT%s option",
-             fat == 32 ? 'e' : opt_i ? 'i' : 'k',
-                     fat == 32 ? "32" : "12/16");
-    if (opt_f && fat == 32)
-        bpb.rde = 0;
-    if (opt_b) {
-        if (!powerof2(opt_b))
-            errx(1, "block size (%u) is not a power of 2", opt_b);
-        if (opt_b < bpb.bps)
-            errx(1, "block size (%u) is too small; minimum is %u",
-                 opt_b, bpb.bps);
-        if (opt_b > bpb.bps * MAXSPC)
-            errx(1, "block size (%u) is too large; maximum is %u", opt_b, bpb.bps * MAXSPC);
-        bpb.spc = opt_b / bpb.bps;
-    }
-    if (opt_c) {
-        if (!powerof2(opt_c))
-            errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
-        bpb.spc = opt_c;
-    }
-    if (opt_r)
-        bpb.res = opt_r;
-    if (opt_n) {
-        if (opt_n > MAXNFT)
-            errx(1, "number of FATs (%u) is too large; maximum is %u", opt_n, MAXNFT);
-        bpb.nft = opt_n;
-    }
-    if (opt_e)
-        bpb.rde = opt_e;
-    if (mflag) {
-        if (opt_m < 0xf0)
-            errx(1, "illegal media descriptor (%#x)", opt_m);
-        bpb.mid = opt_m;
-    }
-    if (opt_a)
-        bpb.bspf = opt_a;
-    if (opt_i)
-        bpb.infs = opt_i;
-    if (opt_k)
-        bpb.bkbs = opt_k;
-    bss = 1;
-    bname = NULL;
-    fd1 = -1;
-    if (opt_B) {
-        bname = opt_B;
-        if (!strchr(bname, '/')) {
-            snprintf(buf, sizeof(buf), "/boot/%s", bname);
-            if (!(bname = strdup(buf)))
-                err(1, "%s", buf);
-        }
-        if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
-            err(1, "%s", bname);
-        if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
-                sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
-            errx(1, "%s: inappropriate file type or format", bname);
-        bss = sb.st_size / bpb.bps;
-    }
-    if (!bpb.nft)
-        bpb.nft = 2;
-    if (!fat) {
-        if (bpb.bsec < (bpb.res ? bpb.res : bss) +
-                howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
-                        ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
-                        bpb.nft +
-                        howmany(bpb.rde ? bpb.rde : DEFRDE,
-                                bpb.bps / sizeof(struct de)) +
-                                (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
-                                (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
-            fat = 12;
-        else if (bpb.rde || bpb.bsec <
-                (bpb.res ? bpb.res : bss) +
-                howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
-                howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
-                (MAXCLS16 + 1) *
-                (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
-            fat = 16;
-        else
-            fat = 32;
-    }
-    x = bss;
-    if (fat == 32) {
-        if (!bpb.infs) {
-            if (x == MAXU16 || x == bpb.bkbs)
-                errx(1, "no room for info sector");
-            bpb.infs = x;
-        }
-        if (bpb.infs != MAXU16 && x <= bpb.infs)
-            x = bpb.infs + 1;
-        if (!bpb.bkbs) {
-            if (x == MAXU16)
-                errx(1, "no room for backup sector");
-            bpb.bkbs = x;
-        } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
-            errx(1, "backup sector would overwrite info sector");
-        if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
-            x = bpb.bkbs + 1;
-    }
-
-    extra_res = 0;
-    set_res = !bpb.res;
-    set_spf = !bpb.bspf;
-    set_spc = !bpb.spc;
-    tempx = x;
-    /*
-     * Attempt to align if opt_A is set. This is done by increasing the number
-     * of reserved blocks. This can cause other factors to change, which can in
-     * turn change the alignment. This should take at most 2 iterations, as
-     * increasing the reserved amount may cause the FAT size to decrease by 1,
-     * requiring another nft reserved blocks. If spc changes, it will
-     * be half of its previous size, and thus will not throw off alignment.
-     */
-    do {
-        x = tempx;
-        if (set_res)
-            bpb.res = (fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x) + extra_res;
-        else if (bpb.res < x)
-            errx(1, "too few reserved sectors");
-        if (fat != 32 && !bpb.rde)
-            bpb.rde = DEFRDE;
-        rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
-        if (set_spc)
-            for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
-                    bpb.spc < MAXSPC &&
-                    bpb.res +
-                    howmany((RESFTE + maxcls(fat)) * (fat / BPN),
-                            bpb.bps * NPB) * bpb.nft +
-                            rds +
-                            (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
-                    bpb.spc <<= 1);
-        if (fat != 32 && bpb.bspf > MAXU16)
-            errx(1, "too many sectors/FAT for FAT12/16");
-        x1 = bpb.res + rds;
-        x = bpb.bspf ? bpb.bspf : 1;
-        if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
-            errx(1, "meta data exceeds file system size");
-        x1 += x * bpb.nft;
-        x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
-                (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
-        x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bps * NPB);
-        if (set_spf) {
-            if (!bpb.bspf) {
-                bpb.bspf = x2;
-            }
-            x1 += (bpb.bspf - 1) * bpb.nft;
-        }
-        if(set_res) {
-            /* attempt to align root directory */
-            alignment = (bpb.res + bpb.bspf * bpb.nft) % bpb.spc;
-            extra_res += bpb.spc - alignment;
-        }
-        attempts++;
-    } while(opt_A && alignment != 0 && attempts < 2);
-    if (alignment != 0)
-        warnx("warning: Alignment failed.");
-
-    cls = (bpb.bsec - x1) / bpb.spc;
-    x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
-    if (cls > x)
-        cls = x;
-    if (bpb.bspf < x2)
-        warnx("warning: sectors/FAT limits file system to %u clusters", cls);
-    if (cls < mincls(fat))
-        errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, mincls(fat));
-    if (cls > maxcls(fat)) {
-        cls = maxcls(fat);
-        bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
-        warnx("warning: FAT type limits file system to %u sectors", bpb.bsec);
-    }
-    printf("%s: %u sector%s in %u FAT%u cluster%s (%u bytes/cluster)\n",
-           fname, cls * bpb.spc, cls * bpb.spc == 1 ? "" : "s", cls, fat,
-           cls == 1 ? "" : "s", bpb.bps * bpb.spc);
-    if (!bpb.mid)
-        bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
-    if (fat == 32)
-        bpb.rdcl = RESFTE;
-    if (bpb.hid + bpb.bsec <= MAXU16) {
-        bpb.sec = bpb.bsec;
-        bpb.bsec = 0;
-    }
-    if (fat != 32) {
-        bpb.spf = bpb.bspf;
-        bpb.bspf = 0;
-    }
-    print_bpb(&bpb);
-    if (!opt_N) {
-        gettimeofday(&tv, NULL);
-        now = tv.tv_sec;
-        tm = localtime(&now);
-        if (!(img = malloc(bpb.bps)))
-            err(1, "%u", bpb.bps);
-        dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
-        for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
-            x = lsn;
-            if (opt_B && fat == 32 && bpb.bkbs != MAXU16 && bss <= bpb.bkbs && x >= bpb.bkbs) {
-                x -= bpb.bkbs;
-                if (!x && lseek(fd1, opt_ofs, SEEK_SET))
-                    err(1, "%s", bname);
-            }
-            if (opt_B && x < bss) {
-                if ((n = read(fd1, img, bpb.bps)) == -1)
-                    err(1, "%s", bname);
-                if ((unsigned)n != bpb.bps)
-                    errx(1, "%s: can't read sector %u", bname, x);
-            } else
-                memset(img, 0, bpb.bps);
-            if (!lsn || (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
-                x1 = sizeof(struct bs);
-                bsbpb = (struct bsbpb *)(img + x1);
-                mk2(bsbpb->bps, bpb.bps);
-                mk1(bsbpb->spc, bpb.spc);
-                mk2(bsbpb->res, bpb.res);
-                mk1(bsbpb->nft, bpb.nft);
-                mk2(bsbpb->rde, bpb.rde);
-                mk2(bsbpb->sec, bpb.sec);
-                mk1(bsbpb->mid, bpb.mid);
-                mk2(bsbpb->spf, bpb.spf);
-                mk2(bsbpb->spt, bpb.spt);
-                mk2(bsbpb->hds, bpb.hds);
-                mk4(bsbpb->hid, bpb.hid);
-                mk4(bsbpb->bsec, bpb.bsec);
-                x1 += sizeof(struct bsbpb);
-                if (fat == 32) {
-                    bsxbpb = (struct bsxbpb *)(img + x1);
-                    mk4(bsxbpb->bspf, bpb.bspf);
-                    mk2(bsxbpb->xflg, 0);
-                    mk2(bsxbpb->vers, 0);
-                    mk4(bsxbpb->rdcl, bpb.rdcl);
-                    mk2(bsxbpb->infs, bpb.infs);
-                    mk2(bsxbpb->bkbs, bpb.bkbs);
-                    x1 += sizeof(struct bsxbpb);
-                }
-                bsx = (struct bsx *)(img + x1);
-                mk1(bsx->sig, 0x29);
-                if (Iflag)
-                    x = opt_I;
-                else
-                    x = (((u_int)(1 + tm->tm_mon) << 8 |
-                            (u_int)tm->tm_mday) +
-                            ((u_int)tm->tm_sec << 8 |
-                                    (u_int)(tv.tv_usec / 10))) << 16 |
-                                    ((u_int)(1900 + tm->tm_year) +
-                                            ((u_int)tm->tm_hour << 8 |
-                                                    (u_int)tm->tm_min));
-                mk4(bsx->volid, x);
-                mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
-                snprintf(buf, sizeof(buf), "FAT%u", fat);
-                setstr(bsx->type, buf, sizeof(bsx->type));
-                if (!opt_B) {
-                    x1 += sizeof(struct bsx);
-                    bs = (struct bs *)img;
-                    mk1(bs->jmp[0], 0xeb);
-                    mk1(bs->jmp[1], x1 - 2);
-                    mk1(bs->jmp[2], 0x90);
-                    setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
-                            sizeof(bs->oem));
-                    memcpy(img + x1, bootcode, sizeof(bootcode));
-                    mk2(img + MINBPS - 2, DOSMAGIC);
-                }
-            } else if (fat == 32 && bpb.infs != MAXU16 &&
-                    (lsn == bpb.infs || (bpb.bkbs != MAXU16 &&
-                                    lsn == bpb.bkbs + bpb.infs))) {
-                mk4(img, 0x41615252);
-                mk4(img + MINBPS - 28, 0x61417272);
-                mk4(img + MINBPS - 24, 0xffffffff);
-                mk4(img + MINBPS - 20, bpb.rdcl);
-                mk2(img + MINBPS - 2, DOSMAGIC);
-            } else if (lsn >= bpb.res && lsn < dir &&
-                    !((lsn - bpb.res) % (bpb.spf ? bpb.spf : bpb.bspf))) {
-                mk1(img[0], bpb.mid);
-                for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
-                    mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
-            } else if (lsn == dir && opt_L) {
-                de = (struct de *)img;
-                mklabel(de->namext, opt_L);
-                mk1(de->attr, 050);
-                x = (u_int)tm->tm_hour << 11 |
-                        (u_int)tm->tm_min << 5 |
-                        (u_int)tm->tm_sec >> 1;
-                mk2(de->time, x);
-                x = (u_int)(tm->tm_year - 80) << 9 |
-                        (u_int)(tm->tm_mon + 1) << 5 |
-                        (u_int)tm->tm_mday;
-                mk2(de->date, x);
-            }
-            if ((n = write(fd, img, bpb.bps)) == -1)
-                err(1, "%s", fname);
-            if ((unsigned)n != bpb.bps) {
-                errx(1, "%s: can't write sector %u", fname, lsn);
-                exit(1);
-            }
-        }
-        free(img);
-    }
-    return 0;
-}
-
-/*
- * Exit with error if file system is mounted.
- */
-static void check_mounted(const char *fname, mode_t mode)
-{
-#ifdef ANDROID
-    warnx("Skipping mount checks");
-#else
-    struct statfs *mp;
-    const char *s1, *s2;
-    size_t len;
-    int n, r;
-
-    if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
-        err(1, "getmntinfo");
-    len = strlen(_PATH_DEV);
-    s1 = fname;
-    if (!strncmp(s1, _PATH_DEV, len))
-        s1 += len;
-    r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
-    for (; n--; mp++) {
-        s2 = mp->f_mntfromname;
-        if (!strncmp(s2, _PATH_DEV, len))
-            s2 += len;
-        if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || !strcmp(s1, s2))
-            errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
-    }
-#endif
-}
-
-/*
- * Get a standard format.
- */
-static void getstdfmt(const char *fmt, struct bpb *bpb)
-{
-    u_int x, i;
-
-    x = sizeof(stdfmt) / sizeof(stdfmt[0]);
-    for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
-    if (i == x)
-        errx(1, "%s: unknown standard format", fmt);
-    *bpb = stdfmt[i].bpb;
-}
-
-/*
- * Get disk slice, partition, and geometry information.
- */
-
-#ifdef __APPLE__
-static void getdiskinfo(__unused int fd, __unused const char* fname, __unused const char* dtype,
-                        __unused int oflag, __unused struct bpb* bpb) {}
-#elif ANDROID
-static void getdiskinfo(int fd, const char *fname, const char *dtype,
-                        __unused int oflag,struct bpb *bpb)
-{
-    struct hd_geometry geom;
-    u_long block_size;
-
-    if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
-        fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno));
-        exit(1);
-    }
-
-    ckgeom(fname, bpb->bps, "bytes/sector");
-
-    if (ioctl(fd, BLKGETSIZE, &block_size)) {
-        fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno));
-        exit(1);
-    }
-
-    if (block_size > UINT32_MAX) {
-        fprintf(stderr, "Error blocksize too large: %lu\n", block_size);
-        exit(1);
-    }
-
-    bpb->bsec = (u_int)block_size;
-
-    if (ioctl(fd, HDIO_GETGEO, &geom)) {
-        fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno));
-        geom.heads = 64;
-        geom.sectors = 63;
-    }
-
-    if (!geom.heads) {
-        printf("Bogus heads from kernel - setting sane value\n");
-        geom.heads = 64;
-    }
-
-    if (!geom.sectors) {
-        printf("Bogus sectors from kernel - setting sane value\n");
-        geom.sectors = 63;
-    }
-
-    bpb->spt = geom.sectors;
-    ckgeom(fname, bpb->spt, "sectors/track");
-
-    bpb->hds = geom.heads;
-    ckgeom(fname, bpb->hds, "drive heads");
-}
-
-#else
-
-static void getdiskinfo(int fd, const char *fname, const char *dtype,
-                        __unused int oflag, struct bpb *bpb)
-{
-    struct disklabel *lp, dlp;
-    struct fd_type type;
-    off_t ms, hs = 0;
-
-    lp = NULL;
-
-    /* If the user specified a disk type, try to use that */
-    if (dtype != NULL) {
-        lp = getdiskbyname(dtype);
-    }
-
-    /* Maybe it's a floppy drive */
-    if (lp == NULL) {
-        if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
-            struct stat st;
-
-            if (fstat(fd, &st))
-                err(1, "Cannot get disk size");
-            /* create a fake geometry for a file image */
-            ms = st.st_size;
-            dlp.d_secsize = 512;
-            dlp.d_nsectors = 63;
-            dlp.d_ntracks = 255;
-            dlp.d_secperunit = ms / dlp.d_secsize;
-            lp = &dlp;
-        } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
-            dlp.d_secsize = 128 << type.secsize;
-            dlp.d_nsectors = type.sectrac;
-            dlp.d_ntracks = type.heads;
-            dlp.d_secperunit = ms / dlp.d_secsize;
-            lp = &dlp;
-        }
-    }
-
-    /* Maybe it's a fixed drive */
-    if (lp == NULL) {
-        if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
-            if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
-                errx(1, "Cannot get sector size, %s", strerror(errno));
-
-            /* XXX Should we use bpb->bps if it's set? */
-            dlp.d_secperunit = ms / dlp.d_secsize;
-
-            if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
-                warnx("Cannot get number of sectors per track, %s", strerror(errno));
-                dlp.d_nsectors = 63;
-            }
-            if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
-                warnx("Cannot get number of heads, %s", strerror(errno));
-                if (dlp.d_secperunit <= 63*1*1024)
-                    dlp.d_ntracks = 1;
-                else if (dlp.d_secperunit <= 63*16*1024)
-                    dlp.d_ntracks = 16;
-                else
-                    dlp.d_ntracks = 255;
-            }
-        }
-
-        hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
-        lp = &dlp;
-    }
-
-    if (bpb->bps == 0)
-        bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
-    if (bpb->spt == 0)
-        bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
-    if (bpb->hds == 0)
-        bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
-    if (bpb->bsec == 0)
-        bpb->bsec = lp->d_secperunit;
-    if (bpb->hid == 0)
-        bpb->hid = hs;
-}
-#endif
-
-/*
- * Print out BPB values.
- */
-static void print_bpb(struct bpb *bpb)
-{
-    printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
-           bpb->nft);
-    if (bpb->rde)
-        printf(" rde=%u", bpb->rde);
-    if (bpb->sec)
-        printf(" sec=%u", bpb->sec);
-    printf(" mid=%#x", bpb->mid);
-    if (bpb->spf)
-        printf(" spf=%u", bpb->spf);
-    printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
-    if (bpb->bsec)
-        printf(" bsec=%u", bpb->bsec);
-    if (!bpb->spf) {
-        printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
-        printf(" infs=");
-        printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
-        printf(" bkbs=");
-        printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
-    }
-    printf("\n");
-}
-
-/*
- * Check a disk geometry value.
- */
-static u_int ckgeom(const char *fname, u_int val, const char *msg)
-{
-    if (!val)
-        errx(1, "%s: no default %s", fname, msg);
-    if (val > MAXU16)
-        errx(1, "%s: illegal %s %d", fname, msg, val);
-    return val;
-}
-
-/*
- * Convert and check a numeric option argument.
- */
-static u_int argtou(const char *arg, u_int lo, u_int hi, const char *msg)
-{
-    char *s;
-    u_long x;
-
-    errno = 0;
-    x = strtoul(arg, &s, 0);
-    if (errno || !*arg || *s || x < lo || x > hi)
-        errx(1, "%s: bad %s", arg, msg);
-    return x;
-}
-
-/*
- * Same for off_t, with optional skmgpP suffix
- */
-static off_t argtooff(const char *arg, const char *msg)
-{
-    char *s;
-    off_t x;
-
-    x = strtoll(arg, &s, 0);
-    /* allow at most one extra char */
-    if (errno || x < 0 || (s[0] && s[1]) )
-        errx(1, "%s: bad %s", arg, msg);
-    if (*s) {    /* the extra char is the multiplier */
-        switch (*s) {
-            default:
-                errx(1, "%s: bad %s", arg, msg);
-                /* notreached */
-
-            case 's':       /* sector */
-            case 'S':
-                x <<= 9;    /* times 512 */
-                break;
-
-            case 'k':       /* kilobyte */
-            case 'K':
-                x <<= 10;   /* times 1024 */
-                break;
-
-            case 'm':       /* megabyte */
-            case 'M':
-                x <<= 20;   /* times 1024*1024 */
-                break;
-
-            case 'g':       /* gigabyte */
-            case 'G':
-                x <<= 30;   /* times 1024*1024*1024 */
-                break;
-
-            case 'p':       /* partition start */
-            case 'P':       /* partition start */
-            case 'l':       /* partition length */
-            case 'L':       /* partition length */
-                errx(1, "%s: not supported yet %s", arg, msg);
-                /* notreached */
-        }
-    }
-    return x;
-}
-
-/*
- * Check a volume label.
- */
-static int oklabel(const char *src)
-{
-    int c, i;
-
-    for (i = 0; i <= 11; i++) {
-        c = (u_char)*src++;
-        if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
-            break;
-    }
-    return i && !c;
-}
-
-/*
- * Make a volume label.
- */
-static void mklabel(u_int8_t *dest, const char *src)
-{
-    int c, i;
-
-    for (i = 0; i < 11; i++) {
-        c = *src ? toupper(*src++) : ' ';
-        *dest++ = !i && c == '\xe5' ? 5 : c;
-    }
-}
-
-/*
- * Copy string, padding with spaces.
- */
-static void setstr(u_int8_t *dest, const char *src, size_t len)
-{
-    while (len--)
-        *dest++ = *src ? *src++ : ' ';
-}
-
-/*
- * Print usage message.
- */
-static void usage(void)
-{
-    fprintf(stderr,
-            "usage: newfs_msdos [ -options ] special [disktype]\n"
-            "where the options are:\n"
-            "\t-@ create file system at specified offset\n"
-            "\t-A Attempt to cluster align root directory\n"
-            "\t-B get bootstrap from file\n"
-            "\t-C create image file with specified size\n"
-            "\t-F FAT type (12, 16, or 32)\n"
-            "\t-I volume ID\n"
-            "\t-L volume label\n"
-            "\t-N don't create file system: just print out parameters\n"
-            "\t-O OEM string\n"
-            "\t-S bytes/sector\n"
-            "\t-a sectors/FAT\n"
-            "\t-b block size\n"
-            "\t-c sectors/cluster\n"
-            "\t-e root directory entries\n"
-            "\t-f standard format\n"
-            "\t-h drive heads\n"
-            "\t-i file system info sector\n"
-            "\t-k backup boot sector\n"
-            "\t-m media descriptor\n"
-            "\t-n number of FATs\n"
-            "\t-o hidden sectors\n"
-            "\t-r reserved sectors\n"
-            "\t-s file system size (sectors)\n"
-            "\t-u sectors/track\n");
-    exit(1);
-}
diff --git a/toolbox/tools.h b/toolbox/tools.h
index 3d4bc3e..abeb3ef 100644
--- a/toolbox/tools.h
+++ b/toolbox/tools.h
@@ -1,4 +1,3 @@
 TOOL(getevent)
 TOOL(getprop)
-TOOL(newfs_msdos)
 TOOL(toolbox)