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