Add experimental daemon for handling dm-user requests.

Right now this is open-coded. As the API stabilizes it will be
integrated into libdm.

Bug: 154536437
Test: manual test
Change-Id: I07bb811b6fb80d85d55e218d788023634c8158b7
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 58241b3..e425284 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -42,6 +42,7 @@
             enabled: false,
         },
     },
+    ramdisk_available: true,
 }
 
 filegroup {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 95301ff..eaef180 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -310,3 +310,36 @@
     auto_gen_config: true,
     require_root: true,
 }
+
+cc_defaults {
+    name: "snapuserd_defaults",
+    srcs: [
+        "snapuserd.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror"
+    ],
+
+    static_libs: [
+        "libbase",
+        "liblog",
+        "libdm",
+    ],
+}
+
+cc_binary {
+    name: "snapuserd",
+    defaults: ["snapuserd_defaults"],
+}
+
+cc_binary {
+    name: "snapuserd_ramdisk",
+    stem: "snapuserd",
+    defaults: ["snapuserd_defaults"],
+
+    ramdisk: true,
+    static_executable: true,
+    system_shared_libs: [],
+}
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
new file mode 100644
index 0000000..a6ff4fd
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 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 <linux/types.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <libdm/dm.h>
+
+using android::base::unique_fd;
+
+#define DM_USER_MAP_READ 0
+#define DM_USER_MAP_WRITE 1
+
+struct dm_user_message {
+    __u64 seq;
+    __u64 type;
+    __u64 flags;
+    __u64 sector;
+    __u64 len;
+    __u8 buf[];
+};
+
+using namespace android::dm;
+
+static int daemon_main(const std::string& device) {
+    unique_fd block_fd(open(device.c_str(), O_RDWR));
+    if (block_fd < 0) {
+        PLOG(ERROR) << "Unable to open " << device;
+        return 1;
+    }
+
+    unique_fd ctrl_fd(open("/dev/dm-user", O_RDWR));
+    if (ctrl_fd < 0) {
+        PLOG(ERROR) << "Unable to open /dev/dm-user";
+        return 1;
+    }
+
+    size_t buf_size = 1UL << 16;
+    auto buf = std::make_unique<char>(buf_size);
+
+    /* Just keeps pumping messages between userspace and the kernel.  We won't
+     * actually be doing anything, but the sequence numbers line up so it'll at
+     * least make forward progress. */
+    while (true) {
+        struct dm_user_message* msg = (struct dm_user_message*)buf.get();
+
+        memset(buf.get(), 0, buf_size);
+
+        ssize_t readed = read(ctrl_fd.get(), buf.get(), buf_size);
+        if (readed < 0) {
+            PLOG(ERROR) << "Control read failed, trying with more space";
+            buf_size *= 2;
+            buf = std::make_unique<char>(buf_size);
+            continue;
+        }
+
+        LOG(DEBUG) << android::base::StringPrintf("read() from dm-user returned %d bytes:",
+                                                  (int)readed);
+        LOG(DEBUG) << android::base::StringPrintf("    msg->seq:    0x%016llx", msg->seq);
+        LOG(DEBUG) << android::base::StringPrintf("    msg->type:   0x%016llx", msg->type);
+        LOG(DEBUG) << android::base::StringPrintf("    msg->flags:  0x%016llx", msg->flags);
+        LOG(DEBUG) << android::base::StringPrintf("    msg->sector: 0x%016llx", msg->sector);
+        LOG(DEBUG) << android::base::StringPrintf("    msg->len:    0x%016llx", msg->len);
+
+        switch (msg->type) {
+            case DM_USER_MAP_READ: {
+                LOG(DEBUG) << android::base::StringPrintf(
+                        "Responding to read of sector %lld with %lld bytes data", msg->sector,
+                        msg->len);
+
+                if ((sizeof(*msg) + msg->len) > buf_size) {
+                    auto old_buf = std::move(buf);
+                    buf_size = sizeof(*msg) + msg->len;
+                    buf = std::make_unique<char>(buf_size);
+                    memcpy(buf.get(), old_buf.get(), sizeof(*msg));
+                    msg = (struct dm_user_message*)buf.get();
+                }
+
+                if (lseek(block_fd.get(), msg->sector * 512, SEEK_SET) < 0) {
+                    PLOG(ERROR) << "lseek failed: " << device;
+                    return 7;
+                }
+                if (!android::base::ReadFully(block_fd.get(), msg->buf, msg->len)) {
+                    PLOG(ERROR) << "read failed: " << device;
+                    return 7;
+                }
+
+                if (!android::base::WriteFully(ctrl_fd.get(), buf.get(), sizeof(*msg) + msg->len)) {
+                    PLOG(ERROR) << "write control failed";
+                    return 3;
+                }
+                break;
+            }
+
+            case DM_USER_MAP_WRITE:
+                abort();
+                break;
+        }
+
+        LOG(DEBUG) << "read() finished, next message";
+    }
+
+    return 0;
+}
+
+int main([[maybe_unused]] int argc, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+    daemon_main(argv[1]);
+    return 0;
+}