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