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