188edb362Sopenharmony_ci/*
288edb362Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
388edb362Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
488edb362Sopenharmony_ci * you may not use this file except in compliance with the License.
588edb362Sopenharmony_ci * You may obtain a copy of the License at
688edb362Sopenharmony_ci *
788edb362Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
888edb362Sopenharmony_ci *
988edb362Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1088edb362Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1188edb362Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1288edb362Sopenharmony_ci * See the License for the specific language governing permissions and
1388edb362Sopenharmony_ci * limitations under the License.
1488edb362Sopenharmony_ci */
1588edb362Sopenharmony_ci
1688edb362Sopenharmony_ci#include "module_loop.h"
1788edb362Sopenharmony_ci#include <dirent.h>
1888edb362Sopenharmony_ci#include <fcntl.h>
1988edb362Sopenharmony_ci#include <filesystem>
2088edb362Sopenharmony_ci#include <libgen.h>
2188edb362Sopenharmony_ci#include <mutex>
2288edb362Sopenharmony_ci#include <sys/ioctl.h>
2388edb362Sopenharmony_ci#include <sys/stat.h>
2488edb362Sopenharmony_ci#include <sys/statfs.h>
2588edb362Sopenharmony_ci#include <sys/mount.h>
2688edb362Sopenharmony_ci#include <sys/types.h>
2788edb362Sopenharmony_ci#include <vector>
2888edb362Sopenharmony_ci#include <linux/fs.h>
2988edb362Sopenharmony_ci#include <linux/loop.h>
3088edb362Sopenharmony_ci#include <linux/magic.h>
3188edb362Sopenharmony_ci#include <cerrno>
3288edb362Sopenharmony_ci#include "securec.h"
3388edb362Sopenharmony_ci#include "string_ex.h"
3488edb362Sopenharmony_ci#include "log/log.h"
3588edb362Sopenharmony_ci#include "module_dm.h"
3688edb362Sopenharmony_ci#include "module_utils.h"
3788edb362Sopenharmony_ci#include "module_constants.h"
3888edb362Sopenharmony_ci#include "sys/sysmacros.h"
3988edb362Sopenharmony_ci#include "scope_guard.h"
4088edb362Sopenharmony_ci
4188edb362Sopenharmony_cinamespace OHOS {
4288edb362Sopenharmony_cinamespace SysInstaller {
4388edb362Sopenharmony_cinamespace Loop {
4488edb362Sopenharmony_ciusing namespace Updater;
4588edb362Sopenharmony_ciusing std::string;
4688edb362Sopenharmony_ci
4788edb362Sopenharmony_cinamespace {
4888edb362Sopenharmony_ciconst int LOOP_LENGTH = 4;
4988edb362Sopenharmony_ciconst int LOOP_CTL_LENGTH = 12;
5088edb362Sopenharmony_ciconstexpr const char *LOOP_CTL_PATH = "/dev/loop-control";
5188edb362Sopenharmony_ciconstexpr const char *BLOCK_DEV_PATH = "/dev/block";
5288edb362Sopenharmony_ciconstexpr const char *LOOP_PREFIX = "loop";
5388edb362Sopenharmony_ciconstexpr const char *DEVICE_PREFIX = "/dev/";
5488edb362Sopenharmony_ciconstexpr const char *SYSTEM_BLOCK_PATH = "/sys/block/";
5588edb362Sopenharmony_ciconstexpr const char *READ_AHEAD_NAME = "/queue/read_ahead_kb";
5688edb362Sopenharmony_ciconstexpr const char *READ_AHEAD_KB = "128";
5788edb362Sopenharmony_ciconstexpr const char *MODULE_LOOP_PREFIX = "module:";
5888edb362Sopenharmony_ciconstexpr const char *LOOP_DEV_PATH = "/dev/loop";
5988edb362Sopenharmony_ciconstexpr const char *LOOP_BLOCK_PATH = "/dev/block/loop";
6088edb362Sopenharmony_ciconst size_t LOOP_DEVICE_RETRY_ATTEMPTS = 6u;
6188edb362Sopenharmony_ciconst uint32_t LOOP_BLOCK_SIZE = 4096;
6288edb362Sopenharmony_ciconst std::chrono::milliseconds WAIT_FOR_DEVICE_TIME(50);
6388edb362Sopenharmony_ciconst std::chrono::seconds WAIT_FOR_LOOP_TIME(50);
6488edb362Sopenharmony_ci}
6588edb362Sopenharmony_ci
6688edb362Sopenharmony_cistatic bool IsRealPath(std::string path)
6788edb362Sopenharmony_ci{
6888edb362Sopenharmony_ci    char buf[PATH_MAX] = { 0 };
6988edb362Sopenharmony_ci    if (realpath(path.c_str(), buf) == nullptr) {
7088edb362Sopenharmony_ci        return false;
7188edb362Sopenharmony_ci    }
7288edb362Sopenharmony_ci    std::string tmpPath = buf;
7388edb362Sopenharmony_ci    return (path == tmpPath);
7488edb362Sopenharmony_ci}
7588edb362Sopenharmony_ci
7688edb362Sopenharmony_civoid LoopbackDeviceUniqueFd::MaybeCloseBad() const
7788edb362Sopenharmony_ci{
7888edb362Sopenharmony_ci    if (deviceFd.Get() != -1) {
7988edb362Sopenharmony_ci        int ret = ioctl(deviceFd.Get(), LOOP_CLR_FD);
8088edb362Sopenharmony_ci        if (ret < 0) {
8188edb362Sopenharmony_ci            LOG(ERROR) << "Failed to clear fd for loopback device";
8288edb362Sopenharmony_ci        }
8388edb362Sopenharmony_ci    }
8488edb362Sopenharmony_ci}
8588edb362Sopenharmony_ci
8688edb362Sopenharmony_cibool PreAllocateLoopDevices(const size_t num)
8788edb362Sopenharmony_ci{
8888edb362Sopenharmony_ci    if (!WaitForFile(LOOP_CTL_PATH, WAIT_FOR_LOOP_TIME)) {
8988edb362Sopenharmony_ci        LOG(ERROR) << "loop-control is not ready";
9088edb362Sopenharmony_ci        return false;
9188edb362Sopenharmony_ci    }
9288edb362Sopenharmony_ci    int fd = open(LOOP_CTL_PATH, O_RDWR | O_CLOEXEC);
9388edb362Sopenharmony_ci    if (fd == -1) {
9488edb362Sopenharmony_ci        LOG(ERROR) << "Failed to open loop-control";
9588edb362Sopenharmony_ci        return false;
9688edb362Sopenharmony_ci    }
9788edb362Sopenharmony_ci    UniqueFd ctlFd(fd);
9888edb362Sopenharmony_ci
9988edb362Sopenharmony_ci    bool found = false;
10088edb362Sopenharmony_ci    size_t startId = 0;
10188edb362Sopenharmony_ci    DIR *dir = opendir(BLOCK_DEV_PATH);
10288edb362Sopenharmony_ci    if (dir == nullptr) {
10388edb362Sopenharmony_ci        LOG(ERROR) << "Failed to open " << BLOCK_DEV_PATH;
10488edb362Sopenharmony_ci        return false;
10588edb362Sopenharmony_ci    }
10688edb362Sopenharmony_ci    struct dirent *ptr = nullptr;
10788edb362Sopenharmony_ci    while ((ptr = readdir(dir)) != nullptr) {
10888edb362Sopenharmony_ci        if (strncmp(ptr->d_name, LOOP_PREFIX, strlen(LOOP_PREFIX)) != 0) {
10988edb362Sopenharmony_ci            continue;
11088edb362Sopenharmony_ci        }
11188edb362Sopenharmony_ci        string idStr = ptr->d_name + strlen(LOOP_PREFIX);
11288edb362Sopenharmony_ci        int id = 0;
11388edb362Sopenharmony_ci        if (StrToInt(idStr, id)) {
11488edb362Sopenharmony_ci            size_t devId = static_cast<size_t>(id);
11588edb362Sopenharmony_ci            if (startId < devId) {
11688edb362Sopenharmony_ci                startId = devId;
11788edb362Sopenharmony_ci                found = true;
11888edb362Sopenharmony_ci            }
11988edb362Sopenharmony_ci        }
12088edb362Sopenharmony_ci    }
12188edb362Sopenharmony_ci    closedir(dir);
12288edb362Sopenharmony_ci    if (found) {
12388edb362Sopenharmony_ci        startId++;
12488edb362Sopenharmony_ci    }
12588edb362Sopenharmony_ci    LOG(INFO) << "start id is " << startId;
12688edb362Sopenharmony_ci
12788edb362Sopenharmony_ci    for (size_t id = startId; id < num + startId; ++id) {
12888edb362Sopenharmony_ci        int ret = ioctl(ctlFd.Get(), LOOP_CTL_ADD, id);
12988edb362Sopenharmony_ci        if (ret < 0 && errno != EEXIST) {
13088edb362Sopenharmony_ci            LOG(ERROR) << "Failed to add loop device";
13188edb362Sopenharmony_ci            return false;
13288edb362Sopenharmony_ci        }
13388edb362Sopenharmony_ci    }
13488edb362Sopenharmony_ci    LOG(INFO) << "Pre-allocated " << num << " loopback devices";
13588edb362Sopenharmony_ci    return true;
13688edb362Sopenharmony_ci}
13788edb362Sopenharmony_ci
13888edb362Sopenharmony_cibool ConfigureReadAhead(const string &devicePath)
13988edb362Sopenharmony_ci{
14088edb362Sopenharmony_ci    if (!StartsWith(devicePath, DEVICE_PREFIX)) {
14188edb362Sopenharmony_ci        LOG(ERROR) << "invalid device path " << devicePath;
14288edb362Sopenharmony_ci        return false;
14388edb362Sopenharmony_ci    }
14488edb362Sopenharmony_ci    string path(devicePath);
14588edb362Sopenharmony_ci    string deviceName = basename(&path[0]);
14688edb362Sopenharmony_ci    string sysfsDevice = SYSTEM_BLOCK_PATH + deviceName + READ_AHEAD_NAME;
14788edb362Sopenharmony_ci    string realPath = GetRealPath(sysfsDevice);
14888edb362Sopenharmony_ci    if (realPath.empty()) {
14988edb362Sopenharmony_ci        LOG(ERROR) << "invalid device path " << sysfsDevice;
15088edb362Sopenharmony_ci        return false;
15188edb362Sopenharmony_ci    }
15288edb362Sopenharmony_ci
15388edb362Sopenharmony_ci    struct stat fileState;
15488edb362Sopenharmony_ci    if (stat(realPath.c_str(), &fileState) != 0) {
15588edb362Sopenharmony_ci        LOG(ERROR) << "Fail to Stat file: " << realPath << ", errno=" << errno;
15688edb362Sopenharmony_ci        return false;
15788edb362Sopenharmony_ci    }
15888edb362Sopenharmony_ci    ON_SCOPE_EXIT(recoveryMode) {
15988edb362Sopenharmony_ci        (void)chmod(realPath.c_str(), fileState.st_mode);
16088edb362Sopenharmony_ci    };
16188edb362Sopenharmony_ci    UniqueFd sysfsFd(open(realPath.c_str(), O_RDWR | O_CLOEXEC));
16288edb362Sopenharmony_ci    if (sysfsFd.Get() == -1) {
16388edb362Sopenharmony_ci        // 0644: give permission to write
16488edb362Sopenharmony_ci        if (chmod(realPath.c_str(), 0644) != 0) {
16588edb362Sopenharmony_ci            LOG(WARNING) << "Fail to chmod file: " << realPath << ", errno=" << errno;
16688edb362Sopenharmony_ci        }
16788edb362Sopenharmony_ci        sysfsFd = UniqueFd(open(realPath.c_str(), O_RDWR | O_CLOEXEC));
16888edb362Sopenharmony_ci        if (sysfsFd.Get() == -1) {
16988edb362Sopenharmony_ci            LOG(ERROR) << "Fail to open file: " << realPath << ", errno=" << errno;
17088edb362Sopenharmony_ci            return false;
17188edb362Sopenharmony_ci        }
17288edb362Sopenharmony_ci    }
17388edb362Sopenharmony_ci    int writeBytes = write(sysfsFd.Get(), READ_AHEAD_KB, strlen(READ_AHEAD_KB) + 1);
17488edb362Sopenharmony_ci    if (writeBytes < 0) {
17588edb362Sopenharmony_ci        LOG(ERROR) << "Failed to write to " << realPath;
17688edb362Sopenharmony_ci        return false;
17788edb362Sopenharmony_ci    }
17888edb362Sopenharmony_ci    return true;
17988edb362Sopenharmony_ci}
18088edb362Sopenharmony_ci
18188edb362Sopenharmony_cibool CheckIfSupportLoopConfigure(const int deviceFd)
18288edb362Sopenharmony_ci{
18388edb362Sopenharmony_ci#ifdef LOOP_CONFIGURE
18488edb362Sopenharmony_ci    struct loop_config config;
18588edb362Sopenharmony_ci    (void)memset_s(&config, sizeof(config), 0, sizeof(config));
18688edb362Sopenharmony_ci    config.fd = -1;
18788edb362Sopenharmony_ci    return ioctl(deviceFd, LOOP_CONFIGURE, &config) == -1 && errno == EBADF;
18888edb362Sopenharmony_ci#else
18988edb362Sopenharmony_ci    return false;
19088edb362Sopenharmony_ci#endif
19188edb362Sopenharmony_ci}
19288edb362Sopenharmony_ci
19388edb362Sopenharmony_cibool ConfigureLoopDevice(const int deviceFd, const int targetFd, struct loop_info64 li, const bool useBufferedIo)
19488edb362Sopenharmony_ci{
19588edb362Sopenharmony_ci#ifdef LOOP_CONFIGURE
19688edb362Sopenharmony_ci    struct loop_config config;
19788edb362Sopenharmony_ci    (void)memset_s(&config, sizeof(config), 0, sizeof(config));
19888edb362Sopenharmony_ci    config.fd = targetFd;
19988edb362Sopenharmony_ci    config.info = li;
20088edb362Sopenharmony_ci    config.block_size = LOOP_BLOCK_SIZE;
20188edb362Sopenharmony_ci    if (!useBufferedIo) {
20288edb362Sopenharmony_ci        li.lo_flags |= LO_FLAGS_DIRECT_IO;
20388edb362Sopenharmony_ci    }
20488edb362Sopenharmony_ci    int ret = ioctl(deviceFd, LOOP_CONFIGURE, &config);
20588edb362Sopenharmony_ci    if (ret < 0) {
20688edb362Sopenharmony_ci        LOG(ERROR) << "Failed to configure loop device err=" << errno;
20788edb362Sopenharmony_ci        return false;
20888edb362Sopenharmony_ci    }
20988edb362Sopenharmony_ci    return true;
21088edb362Sopenharmony_ci#else
21188edb362Sopenharmony_ci    return false;
21288edb362Sopenharmony_ci#endif
21388edb362Sopenharmony_ci}
21488edb362Sopenharmony_ci
21588edb362Sopenharmony_cibool SetLoopDeviceStatus(const int deviceFd, const int targetFd, const struct loop_info64 *li)
21688edb362Sopenharmony_ci{
21788edb362Sopenharmony_ci    int ret = ioctl(deviceFd, LOOP_SET_FD, targetFd);
21888edb362Sopenharmony_ci    if (ret < 0) {
21988edb362Sopenharmony_ci        LOG(ERROR) << "Failed to set loop fd err=" << errno;
22088edb362Sopenharmony_ci        return false;
22188edb362Sopenharmony_ci    }
22288edb362Sopenharmony_ci    ret = ioctl(deviceFd, LOOP_SET_STATUS64, li);
22388edb362Sopenharmony_ci    if (ret < 0) {
22488edb362Sopenharmony_ci        LOG(ERROR) << "Failed to set loop status err=" << errno;
22588edb362Sopenharmony_ci        return false;
22688edb362Sopenharmony_ci    }
22788edb362Sopenharmony_ci    ret = ioctl(deviceFd, BLKFLSBUF, 0);
22888edb362Sopenharmony_ci    if (ret < 0) {
22988edb362Sopenharmony_ci        LOG(WARNING) << "Failed to flush buffers on the loop device err=" << errno;
23088edb362Sopenharmony_ci    }
23188edb362Sopenharmony_ci    ret = ioctl(deviceFd, LOOP_SET_BLOCK_SIZE, LOOP_BLOCK_SIZE);
23288edb362Sopenharmony_ci    if (ret < 0) {
23388edb362Sopenharmony_ci        LOG(WARNING) << "Failed to set block size err=" << errno;
23488edb362Sopenharmony_ci    }
23588edb362Sopenharmony_ci    return true;
23688edb362Sopenharmony_ci}
23788edb362Sopenharmony_ci
23888edb362Sopenharmony_cibool SetUpLoopDevice(const int deviceFd, const string &target, const uint32_t imageOffset, const uint32_t imageSize)
23988edb362Sopenharmony_ci{
24088edb362Sopenharmony_ci    static bool useLoopConfigure = CheckIfSupportLoopConfigure(deviceFd);
24188edb362Sopenharmony_ci    bool useBufferedIo = false;
24288edb362Sopenharmony_ci    string realPath = GetRealPath(target);
24388edb362Sopenharmony_ci    if (realPath.empty()) {
24488edb362Sopenharmony_ci        LOG(ERROR) << "invalid target " << target;
24588edb362Sopenharmony_ci        return false;
24688edb362Sopenharmony_ci    }
24788edb362Sopenharmony_ci    UniqueFd targetFd(open(realPath.c_str(), O_RDONLY | O_CLOEXEC | O_DIRECT));
24888edb362Sopenharmony_ci    if (targetFd.Get() == -1) {
24988edb362Sopenharmony_ci        struct statfs stbuf;
25088edb362Sopenharmony_ci        int savedErrno = errno;
25188edb362Sopenharmony_ci        if (statfs(realPath.c_str(), &stbuf) != 0 ||
25288edb362Sopenharmony_ci            (stbuf.f_type != EROFS_SUPER_MAGIC_V1 &&
25388edb362Sopenharmony_ci             stbuf.f_type != SQUASHFS_MAGIC &&
25488edb362Sopenharmony_ci             stbuf.f_type != OVERLAYFS_SUPER_MAGIC &&
25588edb362Sopenharmony_ci             stbuf.f_type != EXT4_SUPER_MAGIC)) {
25688edb362Sopenharmony_ci            LOG(ERROR) << "Failed to open " << realPath << " errno=" << savedErrno;
25788edb362Sopenharmony_ci            return false;
25888edb362Sopenharmony_ci        }
25988edb362Sopenharmony_ci        LOG(WARNING) << "Fallback to buffered I/O for " << realPath;
26088edb362Sopenharmony_ci        useBufferedIo = true;
26188edb362Sopenharmony_ci        targetFd = UniqueFd(open(realPath.c_str(), O_RDONLY | O_CLOEXEC));
26288edb362Sopenharmony_ci        if (targetFd.Get() == -1) {
26388edb362Sopenharmony_ci            LOG(ERROR) << "Failed to open " << realPath;
26488edb362Sopenharmony_ci            return false;
26588edb362Sopenharmony_ci        }
26688edb362Sopenharmony_ci    }
26788edb362Sopenharmony_ci
26888edb362Sopenharmony_ci    struct loop_info64 li;
26988edb362Sopenharmony_ci    (void)memset_s(&li, sizeof(li), 0, sizeof(li));
27088edb362Sopenharmony_ci    errno_t ret = strcpy_s(reinterpret_cast<char*>(li.lo_crypt_name), LO_NAME_SIZE, MODULE_LOOP_PREFIX);
27188edb362Sopenharmony_ci    if (ret != EOK) {
27288edb362Sopenharmony_ci        LOG(ERROR) << "Failed to copy loop prefix " << MODULE_LOOP_PREFIX;
27388edb362Sopenharmony_ci        return false;
27488edb362Sopenharmony_ci    }
27588edb362Sopenharmony_ci    li.lo_offset = imageOffset;
27688edb362Sopenharmony_ci    li.lo_sizelimit = imageSize;
27788edb362Sopenharmony_ci    li.lo_flags |= LO_FLAGS_AUTOCLEAR;
27888edb362Sopenharmony_ci    return useLoopConfigure ? ConfigureLoopDevice(deviceFd, targetFd.Get(), li, useBufferedIo)
27988edb362Sopenharmony_ci        : SetLoopDeviceStatus(deviceFd, targetFd.Get(), &li);
28088edb362Sopenharmony_ci}
28188edb362Sopenharmony_ci
28288edb362Sopenharmony_cistd::unique_ptr<LoopbackDeviceUniqueFd> WaitForDevice(const int num)
28388edb362Sopenharmony_ci{
28488edb362Sopenharmony_ci    const std::vector<string> candidateDevices = {
28588edb362Sopenharmony_ci        LOOP_BLOCK_PATH + std::to_string(num),
28688edb362Sopenharmony_ci        LOOP_DEV_PATH + std::to_string(num),
28788edb362Sopenharmony_ci    };
28888edb362Sopenharmony_ci
28988edb362Sopenharmony_ci    UniqueFd sysfsFd;
29088edb362Sopenharmony_ci    for (size_t i = 0; i < LOOP_DEVICE_RETRY_ATTEMPTS; ++i) {
29188edb362Sopenharmony_ci        for (const auto &device : candidateDevices) {
29288edb362Sopenharmony_ci            string realPath = GetRealPath(device);
29388edb362Sopenharmony_ci            if (realPath.empty()) {
29488edb362Sopenharmony_ci                continue;
29588edb362Sopenharmony_ci            }
29688edb362Sopenharmony_ci            sysfsFd = UniqueFd(open(realPath.c_str(), O_RDWR | O_CLOEXEC));
29788edb362Sopenharmony_ci            if (sysfsFd.Get() != -1) {
29888edb362Sopenharmony_ci                return std::make_unique<LoopbackDeviceUniqueFd>(std::move(sysfsFd), realPath);
29988edb362Sopenharmony_ci            }
30088edb362Sopenharmony_ci        }
30188edb362Sopenharmony_ci        LOG(WARNING) << "Loopback device " << num << " not ready. Waiting 50ms...";
30288edb362Sopenharmony_ci        usleep(std::chrono::duration_cast<std::chrono::microseconds>(WAIT_FOR_DEVICE_TIME).count());
30388edb362Sopenharmony_ci    }
30488edb362Sopenharmony_ci    LOG(ERROR) << "Failed to open loopback device " << num;
30588edb362Sopenharmony_ci    return nullptr;
30688edb362Sopenharmony_ci}
30788edb362Sopenharmony_ci
30888edb362Sopenharmony_cistd::unique_ptr<LoopbackDeviceUniqueFd> CreateLoopDevice(
30988edb362Sopenharmony_ci    const string &target, const uint32_t imageOffset, const uint32_t imageSize)
31088edb362Sopenharmony_ci{
31188edb362Sopenharmony_ci    UniqueFd ctlFd(open(LOOP_CTL_PATH, O_RDWR | O_CLOEXEC));
31288edb362Sopenharmony_ci    if (ctlFd.Get() == -1) {
31388edb362Sopenharmony_ci        LOG(ERROR) << "Failed to open loop-control";
31488edb362Sopenharmony_ci        return nullptr;
31588edb362Sopenharmony_ci    }
31688edb362Sopenharmony_ci    static std::mutex mlock;
31788edb362Sopenharmony_ci    std::lock_guard lock(mlock);
31888edb362Sopenharmony_ci    int num = ioctl(ctlFd.Get(), LOOP_CTL_GET_FREE);
31988edb362Sopenharmony_ci    if (num < 0) {
32088edb362Sopenharmony_ci        LOG(ERROR) << "Failed to get free loop device err=" << errno;
32188edb362Sopenharmony_ci        return nullptr;
32288edb362Sopenharmony_ci    }
32388edb362Sopenharmony_ci    LOG(INFO) << "Get free loop device num " << num;
32488edb362Sopenharmony_ci    std::unique_ptr<LoopbackDeviceUniqueFd> loopDevice = WaitForDevice(num);
32588edb362Sopenharmony_ci    if (loopDevice == nullptr) {
32688edb362Sopenharmony_ci        LOG(ERROR) << "Failed to create loop device " << num;
32788edb362Sopenharmony_ci        return nullptr;
32888edb362Sopenharmony_ci    }
32988edb362Sopenharmony_ci    if (!SetUpLoopDevice(loopDevice->deviceFd.Get(), target, imageOffset, imageSize)) {
33088edb362Sopenharmony_ci        LOG(ERROR) << "Failed to configure device";
33188edb362Sopenharmony_ci        return nullptr;
33288edb362Sopenharmony_ci    }
33388edb362Sopenharmony_ci    if (!ConfigureReadAhead(loopDevice->name)) {
33488edb362Sopenharmony_ci        LOG(ERROR) << "Failed to configure read ahead";
33588edb362Sopenharmony_ci        return nullptr;
33688edb362Sopenharmony_ci    }
33788edb362Sopenharmony_ci    return loopDevice;
33888edb362Sopenharmony_ci}
33988edb362Sopenharmony_ci
34088edb362Sopenharmony_cibool RemoveDmLoopDevice(const std::string &mountPoint, const std::string &imagePath)
34188edb362Sopenharmony_ci{
34288edb362Sopenharmony_ci    struct dirent *ent = nullptr;
34388edb362Sopenharmony_ci    DIR *dir = nullptr;
34488edb362Sopenharmony_ci
34588edb362Sopenharmony_ci    if ((dir = opendir(BLOCK_DEV_PATH)) == nullptr) {
34688edb362Sopenharmony_ci        LOG(ERROR) << "Failed to open loop dir";
34788edb362Sopenharmony_ci        return false;
34888edb362Sopenharmony_ci    }
34988edb362Sopenharmony_ci    bool ret = false;
35088edb362Sopenharmony_ci    std::string loopDevPath = "";
35188edb362Sopenharmony_ci    while ((ent = readdir(dir)) != nullptr) {
35288edb362Sopenharmony_ci        if (strncmp(ent->d_name, "loop", LOOP_LENGTH) || !strncmp(ent->d_name, "loop-control", LOOP_CTL_LENGTH)) {
35388edb362Sopenharmony_ci            continue;
35488edb362Sopenharmony_ci        }
35588edb362Sopenharmony_ci
35688edb362Sopenharmony_ci        loopDevPath = std::string(BLOCK_DEV_PATH) + "/" + std::string(ent->d_name);
35788edb362Sopenharmony_ci        if (!IsRealPath(loopDevPath)) {
35888edb362Sopenharmony_ci            LOG(ERROR) << "Dev is not exist, loopDevPath=" << loopDevPath;
35988edb362Sopenharmony_ci            loopDevPath = "";
36088edb362Sopenharmony_ci            continue;
36188edb362Sopenharmony_ci        }
36288edb362Sopenharmony_ci        if (!IsLoopDevMatchedImg(loopDevPath, imagePath)) {
36388edb362Sopenharmony_ci            loopDevPath = "";
36488edb362Sopenharmony_ci            continue;
36588edb362Sopenharmony_ci        }
36688edb362Sopenharmony_ci        if (umount(mountPoint.c_str()) != 0) {
36788edb362Sopenharmony_ci            LOG(WARNING) << "Could not umount " << mountPoint << " errno: " << errno;
36888edb362Sopenharmony_ci        }
36988edb362Sopenharmony_ci        bool clearDm = (imagePath.find(UPDATE_ACTIVE_DIR) != std::string::npos);
37088edb362Sopenharmony_ci        ret = ClearDmLoopDevice(loopDevPath, clearDm);
37188edb362Sopenharmony_ci        break;
37288edb362Sopenharmony_ci    }
37388edb362Sopenharmony_ci    closedir(dir);
37488edb362Sopenharmony_ci    return ret;
37588edb362Sopenharmony_ci}
37688edb362Sopenharmony_ci
37788edb362Sopenharmony_cibool RemoveDmLoopDevice(const std::string &loopDevPath)
37888edb362Sopenharmony_ci{
37988edb362Sopenharmony_ci#ifndef USER_DEBUG_MODE
38088edb362Sopenharmony_ci    if (!RemoveDmDevice(loopDevPath)) {
38188edb362Sopenharmony_ci        LOG(ERROR) << "Close dm error, loopDevPath=" << loopDevPath.c_str() << ", errno=" << errno;
38288edb362Sopenharmony_ci        return false;
38388edb362Sopenharmony_ci    }
38488edb362Sopenharmony_ci#endif
38588edb362Sopenharmony_ci    if (!CloseLoopDev(loopDevPath)) {
38688edb362Sopenharmony_ci        LOG(ERROR) << "Close loop error, loopDevPath=" << loopDevPath.c_str() << ", errno=" << errno;
38788edb362Sopenharmony_ci        return false;
38888edb362Sopenharmony_ci    }
38988edb362Sopenharmony_ci    return true;
39088edb362Sopenharmony_ci}
39188edb362Sopenharmony_ci
39288edb362Sopenharmony_cibool ClearDmLoopDevice(const std::string &loopDevPath, const bool clearDm)
39388edb362Sopenharmony_ci{
39488edb362Sopenharmony_ci#ifndef USER_DEBUG_MODE
39588edb362Sopenharmony_ci    if (clearDm) {
39688edb362Sopenharmony_ci        if (!RemoveDmDevice(loopDevPath)) {
39788edb362Sopenharmony_ci            LOG(ERROR) << "Close dm error, loopDevPath=" << loopDevPath.c_str() << ", errno=" << errno;
39888edb362Sopenharmony_ci            return false;
39988edb362Sopenharmony_ci        }
40088edb362Sopenharmony_ci    }
40188edb362Sopenharmony_ci#endif
40288edb362Sopenharmony_ci    if (!CloseLoopDev(loopDevPath)) {
40388edb362Sopenharmony_ci        LOG(ERROR) << "Close loop error, loopDevPath=" << loopDevPath.c_str() << ", errno=" << errno;
40488edb362Sopenharmony_ci        return false;
40588edb362Sopenharmony_ci    }
40688edb362Sopenharmony_ci    return true;
40788edb362Sopenharmony_ci}
40888edb362Sopenharmony_ci
40988edb362Sopenharmony_cibool IsLoopDevMatchedImg(const std::string &loopPath, const std::string &imgFilePath)
41088edb362Sopenharmony_ci{
41188edb362Sopenharmony_ci    struct loop_info64 info;
41288edb362Sopenharmony_ci    if (memset_s(&info, sizeof(struct loop_info64), 0, sizeof(struct loop_info64)) != EOK) {
41388edb362Sopenharmony_ci        LOG(ERROR) << "memset_s failed";
41488edb362Sopenharmony_ci        return false;
41588edb362Sopenharmony_ci    }
41688edb362Sopenharmony_ci
41788edb362Sopenharmony_ci    int fd = open(loopPath.c_str(), O_RDWR | O_CLOEXEC);
41888edb362Sopenharmony_ci    if (fd == -1) {
41988edb362Sopenharmony_ci        LOG(ERROR) << "Open failed, loopPath=" << loopPath.c_str() << ", errno=" << errno;
42088edb362Sopenharmony_ci        return false;
42188edb362Sopenharmony_ci    }
42288edb362Sopenharmony_ci
42388edb362Sopenharmony_ci    if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) {
42488edb362Sopenharmony_ci        close(fd);
42588edb362Sopenharmony_ci        return false;
42688edb362Sopenharmony_ci    }
42788edb362Sopenharmony_ci    close(fd);
42888edb362Sopenharmony_ci    return (imgFilePath == std::string(reinterpret_cast<char *>(info.lo_file_name)));
42988edb362Sopenharmony_ci}
43088edb362Sopenharmony_ci
43188edb362Sopenharmony_cibool CloseLoopDev(const std::string &loopPath)
43288edb362Sopenharmony_ci{
43388edb362Sopenharmony_ci    struct stat st;
43488edb362Sopenharmony_ci    if (stat(loopPath.c_str(), &st)) {
43588edb362Sopenharmony_ci        LOG(INFO) << "Stat error, loopPath=" << loopPath.c_str() << ", errno=" << errno;
43688edb362Sopenharmony_ci        return false;
43788edb362Sopenharmony_ci    }
43888edb362Sopenharmony_ci
43988edb362Sopenharmony_ci    int userFd = open(loopPath.c_str(), O_RDWR);
44088edb362Sopenharmony_ci    if (userFd < 0) {
44188edb362Sopenharmony_ci        LOG(ERROR) << "Open error, loopPath=" << loopPath.c_str() << ", errno=" << errno;
44288edb362Sopenharmony_ci        return false;
44388edb362Sopenharmony_ci    }
44488edb362Sopenharmony_ci
44588edb362Sopenharmony_ci    int ret = ioctl(userFd, LOOP_CLR_FD);
44688edb362Sopenharmony_ci    close(userFd);
44788edb362Sopenharmony_ci    if (ret != 0) {
44888edb362Sopenharmony_ci        LOG(ERROR) << "Clear error, loopPath=" << loopPath.c_str() << ", errno=" << errno;
44988edb362Sopenharmony_ci        return false;
45088edb362Sopenharmony_ci    }
45188edb362Sopenharmony_ci    return true;
45288edb362Sopenharmony_ci}
45388edb362Sopenharmony_ci} // Loop
45488edb362Sopenharmony_ci} // SysInstaller
45588edb362Sopenharmony_ci} // namespace OHOS