1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "fs_manager/mount.h" 17#include <cerrno> 18#include <fcntl.h> 19#include <string> 20#include <sys/mount.h> 21#include <sys/stat.h> 22#include <sys/wait.h> 23#include <unistd.h> 24#include <vector> 25#include <linux/fs.h> 26#include "log/dump.h" 27#include "log/log.h" 28#include "utils.h" 29 30namespace Updater { 31using Updater::Utils::SplitString; 32static std::string g_defaultUpdaterFstab = ""; 33static Fstab *g_fstab = nullptr; 34static const std::string PARTITION_PATH = "/dev/block/by-name"; 35 36static std::string GetFstabFile() 37{ 38 /* check vendor fstab files from specific directory */ 39 std::vector<const std::string> specificFstabFiles = {"/vendor/etc/fstab.updater"}; 40 for (auto& fstabFile : specificFstabFiles) { 41 if (access(fstabFile.c_str(), F_OK) == 0) { 42 return fstabFile; 43 } 44 } 45 return ""; 46} 47 48#ifndef UPDATE_PATCH_SHARED 49MountStatus GetMountStatusForPath(const std::string &path) 50{ 51 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 52 if (item == nullptr) { 53 return MountStatus::MOUNT_ERROR; 54 } 55 return GetMountStatusForMountPoint(item->mountPoint); 56} 57#endif 58 59void LoadFstab() 60{ 61 std::string fstabFile = g_defaultUpdaterFstab; 62 if (fstabFile.empty()) { 63 fstabFile = GetFstabFile(); 64 if (fstabFile.empty()) { 65 fstabFile = "/etc/fstab.updater"; 66 } 67 } 68 if (g_fstab != nullptr) { 69 ReleaseFstab(g_fstab); 70 g_fstab = nullptr; 71 } 72 // Clear fstab before read fstab file. 73 if ((g_fstab = ReadFstabFromFile(fstabFile.c_str(), false)) == nullptr) { 74 LOG(WARNING) << "Read " << fstabFile << " failed"; 75 return; 76 } 77 78 LOG(DEBUG) << "Updater filesystem config info:"; 79 for (FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { 80 LOG(DEBUG) << "\tDevice: " << item->deviceName; 81 LOG(DEBUG) << "\tMount point : " << item->mountPoint; 82 LOG(DEBUG) << "\tFs type : " << item->fsType; 83 LOG(DEBUG) << "\tMount options: " << item->mountOptions; 84 } 85} 86 87void LoadSpecificFstab(const std::string &fstabName) 88{ 89 g_defaultUpdaterFstab = fstabName; 90 LoadFstab(); 91 g_defaultUpdaterFstab = ""; 92} 93 94int UmountForPath(const std::string& path) 95{ 96 if (g_fstab == nullptr) { 97 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 98 return -1; 99 } 100 101 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 102 if (item == nullptr) { 103 LOG(ERROR) << "Cannot find fstab item for " << path << " to umount."; 104 return -1; 105 } 106 107 LOG(DEBUG) << "Umount for path " << path; 108 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); 109 if (rc == MOUNT_ERROR) { 110 return -1; 111 } else if (rc == MOUNT_UMOUNTED) { 112 return 0; 113 } else { 114 if (path == "/data") { 115 Utils::SetParameter("updater.data.ready", "0"); 116 } 117 int ret = umount(item->mountPoint); 118 if (ret == -1) { 119 LOG(ERROR) << "Umount " << item->mountPoint << "failed: " << errno; 120 return -1; 121 } 122 } 123 return 0; 124} 125 126static int MountNtfsWithRetry(std::string source, std::string target) 127{ 128 char *argv[] = {const_cast<char *>("system/bin/mount.ntfs"), 129 const_cast<char *>(source.c_str()), const_cast<char *>(target.c_str()), nullptr}; 130 int num = 0; 131 do { 132 pid_t child = fork(); 133 if (child == 0) { 134 if (execv(argv[0], argv)) { 135 _exit(-1); 136 } 137 } 138 int status = -1; 139 if (waitpid(child, &status, 0) < 0) { 140 LOG(ERROR) << "waitpid failed, " << child; 141 } 142 if (WIFEXITED(status)) { 143 LOG(ERROR) << "child terminated by exit " << WEXITSTATUS(status); 144 } else if (WIFSIGNALED(status)) { 145 LOG(ERROR) << "child terminated by signal " << WTERMSIG(status); 146 } else if (WIFSTOPPED(status)) { 147 LOG(ERROR) << "child stopped by signal " << WSTOPSIG(status); 148 } 149 150 if (status == 0) { 151 Utils::UsSleep(100); // 100 : Wait interval 152 LOG(INFO) << "success to mount " << source << " on " << target; 153 return 0; 154 } else { 155 if ((errno == ENOENT) || (errno == ENODEV) || (errno == ENOMEDIUM)) { 156 LOG(ERROR) << "SD card never insert, dont try again, failed to mount " << source << " on " << target; 157 return -1; 158 } 159 } 160 num++; 161 LOG(ERROR) << "failed to mount " << source << " on " << target << ", errno is " << errno; 162 } while (num < 3); // 3 : retry three times 163 return -1; 164} 165 166int MountSdcard(std::string &path, std::string &mountPoint) 167{ 168 if (path.empty() || mountPoint.empty()) { 169 LOG(ERROR) << "path or mountPoint is null, mount fail"; 170 return -1; 171 } 172 MountStatus rc = GetMountStatusForMountPoint(mountPoint.c_str()); 173 if (rc == MountStatus::MOUNT_ERROR) { 174 return -1; 175 } else if (rc == MountStatus::MOUNT_MOUNTED) { 176 LOG(INFO) << path << " already mounted"; 177 return 0; 178 } 179 const std::vector<const char *> fileSystemType = {"ext4", "vfat", "exfat"}; 180 for (auto type : fileSystemType) { 181 if (mount(path.c_str(), mountPoint.c_str(), type, 0, nullptr) == 0) { 182 LOG(INFO) << "mount success, sdcard type is " << type; 183 return 0; 184 } 185 } 186 if (MountNtfsWithRetry(path, mountPoint) == 0) { 187 LOG(INFO) << "mount success, sdcard type is ntfs"; 188 return 0; 189 } 190 return -1; 191} 192 193int MountForPath(const std::string &path) 194{ 195 if (g_fstab == nullptr) { 196 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 197 return -1; 198 } 199 200 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 201 int ret = -1; 202 if (item == nullptr) { 203 LOG(ERROR) << "Cannot find fstab item for " << path << " to mount."; 204 return -1; 205 } 206 207 LOG(DEBUG) << "Mount for path " << path; 208 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); 209 if (rc == MountStatus::MOUNT_ERROR) { 210 LOG(ERROR) << "GetMountStatusForMountPoint ret is MOUNT_ERROR"; 211 ret = -1; 212 } else if (rc == MountStatus::MOUNT_MOUNTED) { 213 LOG(INFO) << path << " already mounted"; 214 ret = 0; 215 } else { 216 ret = MountOneItem(item); 217 } 218 return ret; 219} 220 221void ErasePartition(const std::string &devPath) 222{ 223 std::string realPath {}; 224 if (!Utils::PathToRealPath(devPath, realPath)) { 225 LOG(ERROR) << "realpath failed:" << devPath; 226 return; 227 } 228 int fd = open(realPath.c_str(), O_RDWR | O_LARGEFILE); 229 if (fd == -1) { 230 LOG(ERROR) << "open failed:" << realPath; 231 return; 232 } 233 234 uint64_t size = 0; 235 int ret = ioctl(fd, BLKGETSIZE64, &size); 236 if (ret < 0) { 237 LOG(ERROR) << "get partition size failed:" << size; 238 close(fd); 239 return; 240 } 241 242 LOG(INFO) << "erase partition size:" << size; 243 244 uint64_t range[] { 0, size }; 245 ret = ioctl(fd, BLKDISCARD, &range); 246 if (ret < 0) { 247 LOG(ERROR) << "erase partition failed"; 248 } 249 close(fd); 250 251 return; 252} 253 254int FormatPartition(const std::string &path, bool isZeroErase) 255{ 256 if (g_fstab == nullptr) { 257 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 258 return -1; 259 } 260 261 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 262 if (item == nullptr) { 263 LOG(ERROR) << "Cannot find fstab item for " << path << " to format."; 264 return -1; 265 } 266 267 if (strcmp(item->mountPoint, "/") == 0) { 268 /* Can not format root */ 269 return 0; 270 } 271 272 if (!IsSupportedFilesystem(item->fsType)) { 273 LOG(ERROR) << "Try to format " << item->mountPoint << " with unsupported file system type: " << item->fsType; 274 return -1; 275 } 276 277 // Umount first 278 if (UmountForPath(path) != 0) { 279 return -1; 280 } 281 282 if (isZeroErase) { 283 ErasePartition(item->deviceName); 284 } 285 286 int ret = DoFormat(item->deviceName, item->fsType); 287 if (ret != 0) { 288 LOG(ERROR) << "Format " << path << " failed"; 289 } 290 return ((ret != 0) ? -1 : 0); 291} 292 293int SetupPartitions(bool isMountData) 294{ 295 UPDATER_INIT_RECORD; 296 if (!Utils::IsUpdaterMode()) { 297 LOG(ERROR) << "live update mode"; 298 return 0; 299 } 300 301 if (g_fstab == NULL || g_fstab->head == NULL) { 302 LOG(ERROR) << "Fstab is invalid"; 303 UPDATER_LAST_WORD(-1); 304 return -1; 305 } 306 for (const FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { 307 std::string mountPoint(item->mountPoint); 308 std::string fsType(item->fsType); 309 if (mountPoint == "/" || mountPoint == "/tmp" || fsType == "none" || 310 mountPoint == "/sdcard") { 311 continue; 312 } 313 314 if (mountPoint == "/data" && isMountData) { 315 if (MountForPath(mountPoint) != 0) { 316 LOG(ERROR) << "Expected partition " << mountPoint << " is not mounted."; 317 UPDATER_LAST_WORD(-1); 318 return -1; 319 } 320 Utils::SetParameter("updater.data.ready", "1"); 321 LOG(INFO) << "mount data not fail"; 322 continue; 323 } 324 if (UmountForPath(mountPoint) != 0) { 325 LOG(ERROR) << "Umount " << mountPoint << " failed"; 326 UPDATER_LAST_WORD(-1); 327 return -1; 328 } 329 } 330 return 0; 331} 332 333const std::string GetBlockDeviceByMountPoint(const std::string &mountPoint) 334{ 335 if (mountPoint.empty()) { 336 LOG(ERROR) << "mountPoint empty error."; 337 return ""; 338 } 339 std::string blockDevice = PARTITION_PATH + mountPoint; 340 if (mountPoint[0] != '/') { 341 blockDevice = PARTITION_PATH + "/" + mountPoint; 342 } 343 if (g_fstab != nullptr) { 344 FstabItem *item = FindFstabItemForMountPoint(*g_fstab, mountPoint.c_str()); 345 if (item != NULL) { 346 blockDevice = item->deviceName; 347 } 348 } 349 return blockDevice; 350} 351 352const std::vector<std::string> GetBlockDevicesByMountPoint(const std::string &mountPoint) 353{ 354 std::vector<std::string> blockDevices; 355 if (mountPoint.empty() || g_fstab == nullptr) { 356 LOG(ERROR) << "mountPoint or g_fstab empty error."; 357 return blockDevices; 358 } 359 for (FstabItem *item = g_fstab->head; item != NULL; item = item->next) { 360 if ((item->mountPoint != NULL) && item->mountPoint == mountPoint) { 361 blockDevices.push_back(item->deviceName); 362 } 363 } 364 365 if (blockDevices.empty()) { 366 std::string blockDevice = PARTITION_PATH + mountPoint; 367 if (mountPoint[0] != '/') { 368 blockDevice = PARTITION_PATH + "/" + mountPoint; 369 } 370 blockDevices.push_back(blockDevice); 371 } 372 return blockDevices; 373} 374} // updater 375