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 30 namespace Updater { 31 using Updater::Utils::SplitString; 32 static std::string g_defaultUpdaterFstab = ""; 33 static Fstab *g_fstab = nullptr; 34 static const std::string PARTITION_PATH = "/dev/block/by-name"; 35 GetFstabFile()36 static 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 GetMountStatusForPath(const std::string & path)48 MountStatus GetMountStatusForPath(const std::string &path) 49 { 50 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 51 if (item == nullptr) { 52 return MountStatus::MOUNT_ERROR; 53 } 54 return GetMountStatusForMountPoint(item->mountPoint); 55 } 56 LoadFstab()57 void LoadFstab() 58 { 59 std::string fstabFile = g_defaultUpdaterFstab; 60 if (fstabFile.empty()) { 61 fstabFile = GetFstabFile(); 62 if (fstabFile.empty()) { 63 fstabFile = "/etc/fstab.updater"; 64 } 65 } 66 if (g_fstab != nullptr) { 67 ReleaseFstab(g_fstab); 68 g_fstab = nullptr; 69 } 70 // Clear fstab before read fstab file. 71 if ((g_fstab = ReadFstabFromFile(fstabFile.c_str(), false)) == nullptr) { 72 LOG(WARNING) << "Read " << fstabFile << " failed"; 73 return; 74 } 75 76 LOG(DEBUG) << "Updater filesystem config info:"; 77 for (FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { 78 LOG(DEBUG) << "\tDevice: " << item->deviceName; 79 LOG(DEBUG) << "\tMount point : " << item->mountPoint; 80 LOG(DEBUG) << "\tFs type : " << item->fsType; 81 LOG(DEBUG) << "\tMount options: " << item->mountOptions; 82 } 83 } 84 LoadSpecificFstab(const std::string & fstabName)85 void LoadSpecificFstab(const std::string &fstabName) 86 { 87 g_defaultUpdaterFstab = fstabName; 88 LoadFstab(); 89 g_defaultUpdaterFstab = ""; 90 } 91 UmountForPath(const std::string & path)92 int UmountForPath(const std::string& path) 93 { 94 if (g_fstab == nullptr) { 95 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 96 return -1; 97 } 98 99 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 100 if (item == nullptr) { 101 LOG(ERROR) << "Cannot find fstab item for " << path << " to umount."; 102 return -1; 103 } 104 105 LOG(DEBUG) << "Umount for path " << path; 106 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); 107 if (rc == MOUNT_ERROR) { 108 return -1; 109 } else if (rc == MOUNT_UMOUNTED) { 110 return 0; 111 } else { 112 if (path == "/data") { 113 Utils::SetParameter("updater.data.ready", "0"); 114 } 115 int ret = umount(item->mountPoint); 116 if (ret == -1) { 117 LOG(ERROR) << "Umount " << item->mountPoint << "failed: " << errno; 118 return -1; 119 } 120 } 121 return 0; 122 } LoopToMount(char * argv[],std::string source,std::string target)123 static int LoopToMount(char *argv[], std::string source, std::string target) 124 { 125 int num = 0; 126 do { 127 pid_t child = fork(); 128 if (child == 0) { 129 if (execv(argv[0], argv)) { 130 _exit(-1); 131 } 132 } 133 int status = -1; 134 if (waitpid(child, &status, 0) < 0) { 135 LOG(ERROR) << "waitpid failed, " << child; 136 } 137 if (WIFEXITED(status)) { 138 LOG(ERROR) << "child terminated by exit " << WEXITSTATUS(status); 139 } else if (WIFSIGNALED(status)) { 140 LOG(ERROR) << "child terminated by signal " << WTERMSIG(status); 141 } else if (WIFSTOPPED(status)) { 142 LOG(ERROR) << "child stopped by signal " << WSTOPSIG(status); 143 } 144 145 if (status == 0) { 146 Utils::UsSleep(100); // 100 : Wait interval 147 LOG(INFO) << "success to mount " << source << " on " << target; 148 return 0; 149 } else { 150 if ((errno == ENOENT) || (errno == ENODEV) || (errno == ENOMEDIUM)) { 151 LOG(ERROR) << "SD card never insert, dont try again, failed to mount " << source << " on " << target; 152 return -1; 153 } 154 } 155 num++; 156 LOG(ERROR) << "failed to mount " << source << " on " << target << ", errno is " << errno; 157 } while (num < 3); // 3 : retry three times 158 return -1; 159 } 160 MountNtfsWithRetry(std::string source,std::string target)161 static int MountNtfsWithRetry(std::string source, std::string target) 162 { 163 char *argv[] = {const_cast<char *>("system/bin/mount.ntfs"), 164 const_cast<char *>(source.c_str()), const_cast<char *>(target.c_str()), nullptr}; 165 return LoopToMount(argv, source, target); 166 } 167 MountExfatWithRetry(std::string source,std::string target)168 static int MountExfatWithRetry(std::string source, std::string target) 169 { 170 char *argv[] = {const_cast<char *>("system/bin/mount.exfat"), 171 const_cast<char *>(source.c_str()), const_cast<char *>(target.c_str()), nullptr}; 172 return LoopToMount(argv, source, target); 173 } 174 MountSdcard(std::string & path,std::string & mountPoint)175 int MountSdcard(std::string &path, std::string &mountPoint) 176 { 177 if (path.empty() || mountPoint.empty()) { 178 LOG(ERROR) << "path or mountPoint is null, mount fail"; 179 return -1; 180 } 181 MountStatus rc = GetMountStatusForMountPoint(mountPoint.c_str()); 182 if (rc == MountStatus::MOUNT_ERROR) { 183 return -1; 184 } else if (rc == MountStatus::MOUNT_MOUNTED) { 185 LOG(INFO) << path << " already mounted"; 186 return 0; 187 } 188 const std::vector<const char *> fileSystemType = {"ext4", "vfat", "exfat"}; 189 for (auto type : fileSystemType) { 190 if (mount(path.c_str(), mountPoint.c_str(), type, 0, nullptr) == 0) { 191 LOG(INFO) << "mount success, sdcard type is " << type; 192 return 0; 193 } 194 } 195 if (MountNtfsWithRetry(path, mountPoint) == 0) { 196 LOG(INFO) << "mount success, sdcard type is ntfs"; 197 return 0; 198 } 199 if (MountExfatWithRetry(path, mountPoint) == 0) { 200 LOG(INFO) << "mount success, sdcard type is exfat"; 201 return 0; 202 } 203 return -1; 204 } 205 MountForPath(const std::string & path)206 int MountForPath(const std::string &path) 207 { 208 if (g_fstab == nullptr) { 209 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 210 return -1; 211 } 212 213 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 214 int ret = -1; 215 if (item == nullptr) { 216 LOG(ERROR) << "Cannot find fstab item for " << path << " to mount."; 217 return -1; 218 } 219 220 LOG(DEBUG) << "Mount for path " << path; 221 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint); 222 if (rc == MountStatus::MOUNT_ERROR) { 223 LOG(ERROR) << "GetMountStatusForMountPoint ret is MOUNT_ERROR"; 224 ret = -1; 225 } else if (rc == MountStatus::MOUNT_MOUNTED) { 226 LOG(INFO) << path << " already mounted"; 227 ret = 0; 228 } else { 229 ret = MountOneItem(item); 230 } 231 return ret; 232 } 233 ErasePartition(const std::string & devPath)234 void ErasePartition(const std::string &devPath) 235 { 236 std::string realPath {}; 237 if (!Utils::PathToRealPath(devPath, realPath)) { 238 LOG(ERROR) << "realpath failed:" << devPath; 239 return; 240 } 241 int fd = open(realPath.c_str(), O_RDWR | O_LARGEFILE); 242 if (fd == -1) { 243 LOG(ERROR) << "open failed:" << realPath; 244 return; 245 } 246 247 uint64_t size = 0; 248 int ret = ioctl(fd, BLKGETSIZE64, &size); 249 if (ret < 0) { 250 LOG(ERROR) << "get partition size failed:" << size; 251 close(fd); 252 return; 253 } 254 255 LOG(INFO) << "erase partition size:" << size; 256 257 uint64_t range[] { 0, size }; 258 ret = ioctl(fd, BLKDISCARD, &range); 259 if (ret < 0) { 260 LOG(ERROR) << "erase partition failed"; 261 } 262 close(fd); 263 264 return; 265 } 266 FormatPartition(const std::string & path,bool isZeroErase)267 int FormatPartition(const std::string &path, bool isZeroErase) 268 { 269 if (g_fstab == nullptr) { 270 LOG(ERROR) << "fstab is not loaded, g_fstab is null."; 271 return -1; 272 } 273 274 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str()); 275 if (item == nullptr) { 276 LOG(ERROR) << "Cannot find fstab item for " << path << " to format."; 277 return -1; 278 } 279 280 if (strcmp(item->mountPoint, "/") == 0) { 281 /* Can not format root */ 282 return 0; 283 } 284 285 if (!IsSupportedFilesystem(item->fsType)) { 286 LOG(ERROR) << "Try to format " << item->mountPoint << " with unsupported file system type: " << item->fsType; 287 return -1; 288 } 289 290 // Umount first 291 if (UmountForPath(path) != 0) { 292 return -1; 293 } 294 295 if (isZeroErase) { 296 ErasePartition(item->deviceName); 297 } 298 299 int ret = DoFormat(item->deviceName, item->fsType); 300 if (ret != 0) { 301 LOG(ERROR) << "Format " << path << " failed"; 302 } 303 return ((ret != 0) ? -1 : 0); 304 } 305 SetupPartitions(bool isMountData)306 int SetupPartitions(bool isMountData) 307 { 308 UPDATER_INIT_RECORD; 309 if (!Utils::IsUpdaterMode()) { 310 LOG(ERROR) << "live update mode"; 311 return 0; 312 } 313 314 if (g_fstab == NULL || g_fstab->head == NULL) { 315 LOG(ERROR) << "Fstab is invalid"; 316 UPDATER_LAST_WORD(-1); 317 return -1; 318 } 319 for (const FstabItem *item = g_fstab->head; item != nullptr; item = item->next) { 320 std::string mountPoint(item->mountPoint); 321 std::string fsType(item->fsType); 322 if (mountPoint == "/" || mountPoint == "/tmp" || fsType == "none" || 323 mountPoint == "/sdcard") { 324 continue; 325 } 326 327 if (mountPoint == "/data" && isMountData) { 328 if (MountForPath(mountPoint) != 0) { 329 LOG(ERROR) << "Expected partition " << mountPoint << " is not mounted."; 330 UPDATER_LAST_WORD(-1); 331 return -1; 332 } 333 Utils::SetParameter("updater.data.ready", "1"); 334 LOG(INFO) << "mount data not fail"; 335 continue; 336 } 337 if (UmountForPath(mountPoint) != 0) { 338 LOG(ERROR) << "Umount " << mountPoint << " failed"; 339 UPDATER_LAST_WORD(-1); 340 return -1; 341 } 342 } 343 return 0; 344 } 345 GetBlockDeviceByMountPoint(const std::string & mountPoint)346 const std::string GetBlockDeviceByMountPoint(const std::string &mountPoint) 347 { 348 if (mountPoint.empty()) { 349 LOG(ERROR) << "mountPoint empty error."; 350 return ""; 351 } 352 std::string blockDevice = PARTITION_PATH + mountPoint; 353 if (mountPoint[0] != '/') { 354 blockDevice = PARTITION_PATH + "/" + mountPoint; 355 } 356 if (g_fstab != nullptr) { 357 FstabItem *item = FindFstabItemForMountPoint(*g_fstab, mountPoint.c_str()); 358 if (item != NULL) { 359 blockDevice = item->deviceName; 360 } 361 } 362 return blockDevice; 363 } 364 GetBlockDevicesByMountPoint(const std::string & mountPoint)365 const std::vector<std::string> GetBlockDevicesByMountPoint(const std::string &mountPoint) 366 { 367 std::vector<std::string> blockDevices; 368 if (mountPoint.empty() || g_fstab == nullptr) { 369 LOG(ERROR) << "mountPoint or g_fstab empty error."; 370 return blockDevices; 371 } 372 for (FstabItem *item = g_fstab->head; item != NULL; item = item->next) { 373 if ((item->mountPoint != NULL) && item->mountPoint == mountPoint) { 374 blockDevices.push_back(item->deviceName); 375 } 376 } 377 378 if (blockDevices.empty()) { 379 std::string blockDevice = PARTITION_PATH + mountPoint; 380 if (mountPoint[0] != '/') { 381 blockDevice = PARTITION_PATH + "/" + mountPoint; 382 } 383 blockDevices.push_back(blockDevice); 384 } 385 return blockDevices; 386 } 387 } // updater 388