Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c942daf1 authored by David Anderson's avatar David Anderson
Browse files

snapuserd: Add an extractor tool.

This is similar to inspect_cow --extract-to, except it uses snapuserd.
It is a diagnostic host tool and uses the tooling added for host
testing.

Usage: snapuserd_extractor -cow COW_FILE -base BASE_FILE -out OUT_FILE
                           -num_sectors NUM_SECTORS

Unlike inspect_cow, this supports xor/copy operations.

The extractor code is separated into a utility file so we can use it for
additional tests later on.

Bug: N/A
Test: manual test
Change-Id: Ib7509508cba45e6c3a0db8c75454e33c2a503e03
parent 8a28163d
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
@@ -293,3 +293,48 @@ cc_test {
        "vts",
        "vts",
    ],
    ],
}
}

cc_binary_host {
    name: "snapuserd_extractor",
    defaults: [
        "fs_mgr_defaults",
        "libsnapshot_cow_defaults",
    ],
    srcs: [
        "testing/dm_user_harness.cpp",
        "testing/harness.cpp",
        "testing/host_harness.cpp",
        "user-space-merge/extractor.cpp",
        "snapuserd_extractor.cpp",
    ],
    cflags: [
        "-D_FILE_OFFSET_BITS=64",
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "liblog",
    ],
    static_libs: [
        "libbrotli",
        "libcutils_sockets",
        "libdm",
        "libext2_uuid",
        "libext4_utils",
        "libfs_mgr_file_wait",
        "libgflags",
        "libsnapshot_cow",
        "libsnapuserd",
        "liburing",
        "libz",
    ],
    include_dirs: [
        "bionic/libc/kernel",
        ".",
    ],
    header_libs: [
        "libstorage_literals_headers",
        "libfiemap_headers",
    ],
}
+68 −0
Original line number Original line Diff line number Diff line
// Copyright (C) 2023 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 <linux/fs.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <iostream>
#include <memory>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <gflags/gflags.h>
#include "user-space-merge/extractor.h"

using namespace std::string_literals;

DEFINE_string(base, "", "Base device/image");
DEFINE_string(cow, "", "COW device/image");
DEFINE_string(out, "", "Output path");
DEFINE_int32(num_sectors, 0, "Number of sectors to read");

int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
    android::base::InitLogging(argv);
    gflags::ParseCommandLineFlags(&argc, &argv, true);

    if (FLAGS_out.empty()) {
        LOG(ERROR) << "Missing -out argument.";
        return 1;
    }
    if (FLAGS_base.empty()) {
        LOG(ERROR) << "Missing -base argument.";
        return 1;
    }
    if (FLAGS_cow.empty()) {
        LOG(ERROR) << "missing -out argument.";
        return 1;
    }
    if (!FLAGS_num_sectors) {
        LOG(ERROR) << "missing -num_sectors argument.";
        return 1;
    }

    android::snapshot::Extractor extractor(FLAGS_base, FLAGS_cow);
    if (!extractor.Init()) {
        return 1;
    }
    if (!extractor.Extract(FLAGS_num_sectors, FLAGS_out)) {
        return 1;
    }
    return 0;
}
+90 −0
Original line number Original line Diff line number Diff line
// Copyright (C) 2023 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 "extractor.h"

#include <fcntl.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <iostream>
#include <memory>

#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>

using android::base::unique_fd;
using namespace std::string_literals;

namespace android {
namespace snapshot {

Extractor::Extractor(const std::string& base_path, const std::string& cow_path)
    : base_path_(base_path), cow_path_(cow_path), control_name_("test") {}

bool Extractor::Init() {
    auto opener = factory_.CreateTestOpener(control_name_);
    handler_ = std::make_shared<SnapshotHandler>(control_name_, cow_path_, base_path_, base_path_,
                                                 opener, 1, false, false);
    if (!handler_->InitCowDevice()) {
        return false;
    }
    if (!handler_->InitializeWorkers()) {
        return false;
    }

    read_worker_ = std::make_unique<ReadWorker>(cow_path_, base_path_, control_name_, base_path_,
                                                handler_->GetSharedPtr(), opener);
    if (!read_worker_->Init()) {
        return false;
    }
    block_server_ = static_cast<TestBlockServer*>(read_worker_->block_server());

    handler_thread_ = std::async(std::launch::async, &SnapshotHandler::Start, handler_.get());
    return true;
}

Extractor::~Extractor() {
    factory_.DeleteQueue(control_name_);
}

bool Extractor::Extract(off_t num_sectors, const std::string& out_path) {
    unique_fd out_fd(open(out_path.c_str(), O_RDWR | O_CLOEXEC | O_TRUNC | O_CREAT, 0664));
    if (out_fd < 0) {
        PLOG(ERROR) << "Could not open for writing: " << out_path;
        return false;
    }

    for (off_t i = 0; i < num_sectors; i++) {
        if (!read_worker_->RequestSectors(i, 512)) {
            LOG(ERROR) << "Read sector " << i << " failed.";
            return false;
        }
        std::string result = std::move(block_server_->sent_io());
        off_t offset = i * 512;
        if (!android::base::WriteFullyAtOffset(out_fd, result.data(), result.size(), offset)) {
            PLOG(ERROR) << "write failed";
            return false;
        }
    }
    return true;
}

}  // namespace snapshot
}  // namespace android
+51 −0
Original line number Original line Diff line number Diff line
// Copyright (C) 2023 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.

#pragma once

#include <string>
#include <thread>

#include <android-base/unique_fd.h>
#include "merge_worker.h"
#include "read_worker.h"
#include "snapuserd_core.h"
#include "testing/host_harness.h"

namespace android {
namespace snapshot {

class Extractor final {
  public:
    Extractor(const std::string& base_path, const std::string& cow_path);
    ~Extractor();

    bool Init();
    bool Extract(off_t num_sectors, const std::string& out_path);

  private:
    std::string base_path_;
    std::string cow_path_;

    TestBlockServerFactory factory_;
    HostTestHarness harness_;
    std::string control_name_;
    std::shared_ptr<SnapshotHandler> handler_;
    std::unique_ptr<ReadWorker> read_worker_;
    std::future<bool> handler_thread_;
    TestBlockServer* block_server_ = nullptr;
};

}  // namespace snapshot
}  // namespace android