Merge "logcat: error on multiple PID argument"
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 4fb0b83..2738457 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -197,19 +197,12 @@
     char** argv_;
 };
 
-static int DmCreateCmdHandler(int argc, char** argv) {
-    if (argc < 1) {
-        std::cerr << "Usage: dmctl create <dm-name> [-ro] <targets...>" << std::endl;
-        return -EINVAL;
-    }
-    std::string name = argv[0];
-
+static bool parse_table_args(DmTable* table, int argc, char** argv) {
     // Parse extended options first.
-    DmTable table;
     int arg_index = 1;
     while (arg_index < argc && argv[arg_index][0] == '-') {
         if (strcmp(argv[arg_index], "-ro") == 0) {
-            table.set_readonly(true);
+            table->set_readonly(true);
             arg_index++;
         } else {
             std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
@@ -221,15 +214,30 @@
     TargetParser parser(argc - arg_index, argv + arg_index);
     while (parser.More()) {
         std::unique_ptr<DmTarget> target = parser.Next();
-        if (!target || !table.AddTarget(std::move(target))) {
+        if (!target || !table->AddTarget(std::move(target))) {
             return -EINVAL;
         }
     }
 
-    if (table.num_targets() == 0) {
+    if (table->num_targets() == 0) {
         std::cerr << "Must define at least one target." << std::endl;
         return -EINVAL;
     }
+    return 0;
+}
+
+static int DmCreateCmdHandler(int argc, char** argv) {
+    if (argc < 1) {
+        std::cerr << "Usage: dmctl create <dm-name> [-ro] <targets...>" << std::endl;
+        return -EINVAL;
+    }
+    std::string name = argv[0];
+
+    DmTable table;
+    int ret = parse_table_args(&table, argc, argv);
+    if (ret) {
+        return ret;
+    }
 
     DeviceMapper& dm = DeviceMapper::Instance();
     if (!dm.CreateDevice(name, table)) {
@@ -255,6 +263,27 @@
     return 0;
 }
 
+static int DmReplaceCmdHandler(int argc, char** argv) {
+    if (argc < 1) {
+        std::cerr << "Usage: dmctl replace <dm-name> <targets...>" << std::endl;
+        return -EINVAL;
+    }
+    std::string name = argv[0];
+
+    DmTable table;
+    int ret = parse_table_args(&table, argc, argv);
+    if (ret) {
+        return ret;
+    }
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    if (!dm.LoadTableAndActivate(name, table)) {
+        std::cerr << "Failed to replace device-mapper table to: " << name << std::endl;
+        return -EIO;
+    }
+    return 0;
+}
+
 static int DmListTargets(DeviceMapper& dm, [[maybe_unused]] int argc,
                          [[maybe_unused]] char** argv) {
     std::vector<DmTargetTypeInfo> targets;
@@ -469,6 +498,7 @@
         // clang-format off
         {"create", DmCreateCmdHandler},
         {"delete", DmDeleteCmdHandler},
+        {"replace", DmReplaceCmdHandler},
         {"list", DmListCmdHandler},
         {"help", HelpCmdHandler},
         {"getpath", GetPathCmdHandler},
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 24a745a..b08e061 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -452,48 +452,6 @@
     *codePoint |= 0x3F & byte;
 }
 
-size_t utf8_to_utf32_length(const char *src, size_t src_len)
-{
-    if (src == nullptr || src_len == 0) {
-        return 0;
-    }
-    size_t ret = 0;
-    const char* cur;
-    const char* end;
-    size_t num_to_skip;
-    for (cur = src, end = src + src_len, num_to_skip = 1;
-         cur < end;
-         cur += num_to_skip, ret++) {
-        const char first_char = *cur;
-        num_to_skip = 1;
-        if ((first_char & 0x80) == 0) {  // ASCII
-            continue;
-        }
-        int32_t mask;
-
-        for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) {
-        }
-    }
-    return ret;
-}
-
-void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst)
-{
-    if (src == nullptr || src_len == 0 || dst == nullptr) {
-        return;
-    }
-
-    const char* cur = src;
-    const char* const end = src + src_len;
-    char32_t* cur_utf32 = dst;
-    while (cur < end) {
-        size_t num_read;
-        *cur_utf32++ = static_cast<char32_t>(utf32_at_internal(cur, &num_read));
-        cur += num_read;
-    }
-    *cur_utf32 = 0;
-}
-
 static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length)
 {
     uint32_t unicode;
diff --git a/libutils/include/utils/Unicode.h b/libutils/include/utils/Unicode.h
index a2aaa47..fc6712d 100644
--- a/libutils/include/utils/Unicode.h
+++ b/libutils/include/utils/Unicode.h
@@ -129,18 +129,6 @@
 ssize_t utf8_length(const char *src);
 
 /**
- * Measure the length of a UTF-32 string.
- */
-size_t utf8_to_utf32_length(const char *src, size_t src_len);
-
-/**
- * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large
- * enough to store the entire converted string as measured by
- * utf8_to_utf32_length plus space for a NUL terminator.
- */
-void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst);
-
-/**
  * Returns the UTF-16 length of UTF-8 string "src". Returns -1 in case
  * it's invalid utf8. No buffer over-read occurs because of bound checks. Using overreadIsFatal you
  * can ask to log a message and fail in case the invalid utf8 could have caused an override if no