/* * Copyright (c) 2021 Huawei Device Co., Ltd. * 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 "fs_manager/mount.h" #include #include #include #include #include #include #include #include #include #include "log/dump.h" #include "log/log.h" #include "utils.h" namespace Updater { using Updater::Utils::SplitString; static std::string g_defaultUpdaterFstab = ""; static Fstab *g_fstab = nullptr; static const std::string PARTITION_PATH = "/dev/block/by-name"; static std::string GetFstabFile() { /* check vendor fstab files from specific directory */ std::vector specificFstabFiles = {"/vendor/etc/fstab.updater"}; for (auto& fstabFile : specificFstabFiles) { if (access(fstabFile.c_str(), F_OK) == 0) { return fstabFile; } } return ""; } MountStatus GetMountStatusForPath(const std::string &path) { FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); if (item == nullptr) { return MountStatus::MOUNT_ERROR; } return GetMountStatusForMountPoint(item->mountPoint); } void LoadFstab() { std::string fstabFile = g_defaultUpdaterFstab; if (fstabFile.empty()) { fstabFile = GetFstabFile(); if (fstabFile.empty()) { fstabFile = "/etc/fstab.updater"; } } if (g_fstab != nullptr) { ReleaseFstab(g_fstab); g_fstab = nullptr; } // Clear fstab before read fstab file. if ((g_fstab = ReadFstabFromFile(fstabFile.c_str(), false)) == nullptr) { LOG(WARNING) << "Read " << fstabFile << " failed"; return; } LOG(DEBUG) << "Updater filesystem config info:"; for (FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { LOG(DEBUG) << "\tDevice: " << item->deviceName; LOG(DEBUG) << "\tMount point : " << item->mountPoint; LOG(DEBUG) << "\tFs type : " << item->fsType; LOG(DEBUG) << "\tMount options: " << item->mountOptions; } } void LoadSpecificFstab(const std::string &fstabName) { g_defaultUpdaterFstab = fstabName; LoadFstab(); g_defaultUpdaterFstab = ""; } int UmountForPath(const std::string& path) { if (g_fstab == nullptr) { LOG(ERROR) << "fstab is not loaded, g_fstab is null."; return -1; } FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); if (item == nullptr) { LOG(ERROR) << "Cannot find fstab item for " << path << " to umount."; return -1; } LOG(DEBUG) << "Umount for path " << path; MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); if (rc == MOUNT_ERROR) { return -1; } else if (rc == MOUNT_UMOUNTED) { return 0; } else { if (path == "/data") { Utils::SetParameter("updater.data.ready", "0"); } int ret = umount(item->mountPoint); if (ret == -1) { LOG(ERROR) << "Umount " << item->mountPoint << "failed: " << errno; return -1; } } return 0; } static int LoopToMount(char *argv[], std::string source, std::string target) { int num = 0; do { pid_t child = fork(); if (child == 0) { if (execv(argv[0], argv)) { _exit(-1); } } int status = -1; if (waitpid(child, &status, 0) < 0) { LOG(ERROR) << "waitpid failed, " << child; } if (WIFEXITED(status)) { LOG(ERROR) << "child terminated by exit " << WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { LOG(ERROR) << "child terminated by signal " << WTERMSIG(status); } else if (WIFSTOPPED(status)) { LOG(ERROR) << "child stopped by signal " << WSTOPSIG(status); } if (status == 0) { Utils::UsSleep(100); // 100 : Wait interval LOG(INFO) << "success to mount " << source << " on " << target; return 0; } else { if ((errno == ENOENT) || (errno == ENODEV) || (errno == ENOMEDIUM)) { LOG(ERROR) << "SD card never insert, dont try again, failed to mount " << source << " on " << target; return -1; } } num++; LOG(ERROR) << "failed to mount " << source << " on " << target << ", errno is " << errno; } while (num < 3); // 3 : retry three times return -1; } static int MountNtfsWithRetry(std::string source, std::string target) { char *argv[] = {const_cast("system/bin/mount.ntfs"), const_cast(source.c_str()), const_cast(target.c_str()), nullptr}; return LoopToMount(argv, source, target); } static int MountExfatWithRetry(std::string source, std::string target) { char *argv[] = {const_cast("system/bin/mount.exfat"), const_cast(source.c_str()), const_cast(target.c_str()), nullptr}; return LoopToMount(argv, source, target); } int MountSdcard(std::string &path, std::string &mountPoint) { if (path.empty() || mountPoint.empty()) { LOG(ERROR) << "path or mountPoint is null, mount fail"; return -1; } MountStatus rc = GetMountStatusForMountPoint(mountPoint.c_str()); if (rc == MountStatus::MOUNT_ERROR) { return -1; } else if (rc == MountStatus::MOUNT_MOUNTED) { LOG(INFO) << path << " already mounted"; return 0; } const std::vector fileSystemType = {"ext4", "vfat", "exfat"}; for (auto type : fileSystemType) { if (mount(path.c_str(), mountPoint.c_str(), type, 0, nullptr) == 0) { LOG(INFO) << "mount success, sdcard type is " << type; return 0; } } if (MountNtfsWithRetry(path, mountPoint) == 0) { LOG(INFO) << "mount success, sdcard type is ntfs"; return 0; } if (MountExfatWithRetry(path, mountPoint) == 0) { LOG(INFO) << "mount success, sdcard type is exfat"; return 0; } return -1; } int MountForPath(const std::string &path) { if (g_fstab == nullptr) { LOG(ERROR) << "fstab is not loaded, g_fstab is null."; return -1; } FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); int ret = -1; if (item == nullptr) { LOG(ERROR) << "Cannot find fstab item for " << path << " to mount."; return -1; } LOG(DEBUG) << "Mount for path " << path; MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); if (rc == MountStatus::MOUNT_ERROR) { LOG(ERROR) << "GetMountStatusForMountPoint ret is MOUNT_ERROR"; ret = -1; } else if (rc == MountStatus::MOUNT_MOUNTED) { LOG(INFO) << path << " already mounted"; ret = 0; } else { ret = MountOneItem(item); } return ret; } void ErasePartition(const std::string &devPath) { std::string realPath {}; if (!Utils::PathToRealPath(devPath, realPath)) { LOG(ERROR) << "realpath failed:" << devPath; return; } int fd = open(realPath.c_str(), O_RDWR | O_LARGEFILE); if (fd == -1) { LOG(ERROR) << "open failed:" << realPath; return; } uint64_t size = 0; int ret = ioctl(fd, BLKGETSIZE64, &size); if (ret < 0) { LOG(ERROR) << "get partition size failed:" << size; close(fd); return; } LOG(INFO) << "erase partition size:" << size; uint64_t range[] { 0, size }; ret = ioctl(fd, BLKDISCARD, &range); if (ret < 0) { LOG(ERROR) << "erase partition failed"; } close(fd); return; } int FormatPartition(const std::string &path, bool isZeroErase) { if (g_fstab == nullptr) { LOG(ERROR) << "fstab is not loaded, g_fstab is null."; return -1; } FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); if (item == nullptr) { LOG(ERROR) << "Cannot find fstab item for " << path << " to format."; return -1; } if (strcmp(item->mountPoint, "/") == 0) { /* Can not format root */ return 0; } if (!IsSupportedFilesystem(item->fsType)) { LOG(ERROR) << "Try to format " << item->mountPoint << " with unsupported file system type: " << item->fsType; return -1; } // Umount first if (UmountForPath(path) != 0) { return -1; } if (isZeroErase) { ErasePartition(item->deviceName); } int ret = DoFormat(item->deviceName, item->fsType); if (ret != 0) { LOG(ERROR) << "Format " << path << " failed"; } return ((ret != 0) ? -1 : 0); } int SetupPartitions(bool isMountData) { UPDATER_INIT_RECORD; if (!Utils::IsUpdaterMode()) { LOG(ERROR) << "live update mode"; return 0; } if (g_fstab == NULL || g_fstab->head == NULL) { LOG(ERROR) << "Fstab is invalid"; UPDATER_LAST_WORD(-1); return -1; } for (const FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { std::string mountPoint(item->mountPoint); std::string fsType(item->fsType); if (mountPoint == "/" || mountPoint == "/tmp" || fsType == "none" || mountPoint == "/sdcard") { continue; } if (mountPoint == "/data" && isMountData) { if (MountForPath(mountPoint) != 0) { LOG(ERROR) << "Expected partition " << mountPoint << " is not mounted."; UPDATER_LAST_WORD(-1); return -1; } Utils::SetParameter("updater.data.ready", "1"); LOG(INFO) << "mount data not fail"; continue; } if (UmountForPath(mountPoint) != 0) { LOG(ERROR) << "Umount " << mountPoint << " failed"; UPDATER_LAST_WORD(-1); return -1; } } return 0; } const std::string GetBlockDeviceByMountPoint(const std::string &mountPoint) { if (mountPoint.empty()) { LOG(ERROR) << "mountPoint empty error."; return ""; } std::string blockDevice = PARTITION_PATH + mountPoint; if (mountPoint[0] != '/') { blockDevice = PARTITION_PATH + "/" + mountPoint; } if (g_fstab != nullptr) { FstabItem *item = FindFstabItemForMountPoint(*g_fstab, mountPoint.c_str()); if (item != NULL) { blockDevice = item->deviceName; } } return blockDevice; } const std::vector GetBlockDevicesByMountPoint(const std::string &mountPoint) { std::vector blockDevices; if (mountPoint.empty() || g_fstab == nullptr) { LOG(ERROR) << "mountPoint or g_fstab empty error."; return blockDevices; } for (FstabItem *item = g_fstab->head; item != NULL; item = item->next) { if ((item->mountPoint != NULL) && item->mountPoint == mountPoint) { blockDevices.push_back(item->deviceName); } } if (blockDevices.empty()) { std::string blockDevice = PARTITION_PATH + mountPoint; if (mountPoint[0] != '/') { blockDevice = PARTITION_PATH + "/" + mountPoint; } blockDevices.push_back(blockDevice); } return blockDevices; } } // updater