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