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
48 #ifndef UPDATE_PATCH_SHARED
GetMountStatusForPath(const std::string &path)49 MountStatus 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
LoadFstab()59 void 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
LoadSpecificFstab(const std::string &fstabName)87 void LoadSpecificFstab(const std::string &fstabName)
88 {
89 g_defaultUpdaterFstab = fstabName;
90 LoadFstab();
91 g_defaultUpdaterFstab = "";
92 }
93
UmountForPath(const std::string& path)94 int 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
MountNtfsWithRetry(std::string source, std::string target)126 static 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
MountSdcard(std::string &path, std::string &mountPoint)166 int 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
MountForPath(const std::string &path)193 int 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
ErasePartition(const std::string &devPath)221 void 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
FormatPartition(const std::string &path, bool isZeroErase)254 int 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
SetupPartitions(bool isMountData)293 int 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
GetBlockDeviceByMountPoint(const std::string &mountPoint)333 const 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
GetBlockDevicesByMountPoint(const std::string &mountPoint)352 const 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