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 <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdbool.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #include <linux/limits.h>
25 #include "beget_ext.h"
26 #include "bootstage.h"
27 #include "fs_manager/fs_manager.h"
28 #include "hookmgr.h"
29 #include "list.h"
30 #include "init_utils.h"
31 #include "param/init_param.h"
32 #include "securec.h"
33 #include "switch_root.h"
34 #ifdef SUPPORT_HVB
35 #include "fs_dm.h"
36 #include "dm_verity.h"
37 #endif
38 #include "init_filesystems.h"
39 #ifdef EROFS_OVERLAY
40 #include "erofs_mount_overlay.h"
41 #endif
42 #ifdef __cplusplus
43 #if __cplusplus
44 extern "C" {
45 #endif
46 #endif
47
48 #define FS_MANAGER_BUFFER_SIZE 512
49 #define BLOCK_SIZE_BUFFER (64)
50 #define RESIZE_BUFFER_SIZE 1024
51 #define MAX_GCALLOWNANCE 100
52 #define GCALLOWANCE_INCREACE 10
53 const off_t PARTITION_ACTIVE_SLOT_OFFSET = 1024;
54 const off_t PARTITION_ACTIVE_SLOT_SIZE = 4;
55 int g_bootSlots = -1;
56 int g_currentSlot = -1;
57
InitPostMount(const char * mountPoint,int rc)58 __attribute__((weak)) void InitPostMount(const char *mountPoint, int rc)
59 {
60 }
61
InitTimerControl(bool isSuspend)62 __attribute__((weak)) void InitTimerControl(bool isSuspend)
63 {
64 }
65
NeedDoAllResize(const unsigned int fsManagerFlags)66 __attribute__((weak)) bool NeedDoAllResize(const unsigned int fsManagerFlags)
67 {
68 BEGET_LOGW("kdump: static");
69 return true;
70 }
71
72 static const SUPPORTED_FILE_SYSTEM supportedFileSystems[] = {
73 { "ext4", 0 },
74 { "f2fs", 1 },
75 { "overlay", 0 },
76 { NULL, 0 }
77 };
78
79 static void **extendedFileSystems_ = NULL;
80
InitSetExtendedFileSystems(const SUPPORTED_FILE_SYSTEM * extendedFileSystems[])81 void InitSetExtendedFileSystems(const SUPPORTED_FILE_SYSTEM *extendedFileSystems[])
82 {
83 extendedFileSystems_ = (void **)extendedFileSystems;
84 }
85
GetSupportedFileSystemInfo(const char * fsType)86 static const SUPPORTED_FILE_SYSTEM *GetSupportedFileSystemInfo(const char *fsType)
87 {
88 return (const SUPPORTED_FILE_SYSTEM *)OH_ExtendableStrDictGet((void **)supportedFileSystems,
89 sizeof(SUPPORTED_FILE_SYSTEM), fsType, 0, extendedFileSystems_);
90 }
91
IsSupportedDataType(const char * fsType)92 static bool IsSupportedDataType(const char *fsType)
93 {
94 const SUPPORTED_FILE_SYSTEM *item = GetSupportedFileSystemInfo(fsType);
95 if (item == NULL) {
96 return false;
97 }
98 if (item->for_userdata) {
99 return true;
100 }
101 return false;
102 }
103
IsSupportedFilesystem(const char * fsType)104 bool IsSupportedFilesystem(const char *fsType)
105 {
106 const SUPPORTED_FILE_SYSTEM *item = GetSupportedFileSystemInfo(fsType);
107 if (item == NULL) {
108 return false;
109 }
110 return true;
111 }
112
113 /* 1024(stdout buffer size) - 256(log tag max size approximately) */
114 #define LOG_LINE_SZ 768
115 #define PIPE_FDS 2
116
LogToKmsg(int fd)117 static void LogToKmsg(int fd)
118 {
119 char buffer[LOG_LINE_SZ] = {0};
120 int lineMaxSize = LOG_LINE_SZ - 1;
121 int pos = 0;
122
123 do {
124 ssize_t lineSize = read(fd, buffer, lineMaxSize);
125 if (lineSize < 0) {
126 BEGET_LOGE("Failed to read, errno: %d", errno);
127 break;
128 }
129 if (!lineSize) {
130 /* No more lines, just break */
131 break;
132 }
133 if (lineSize > lineMaxSize) {
134 BEGET_LOGE("Invalid read size, ret: %d is larger than buffer size: %d", lineSize, lineMaxSize);
135 lineSize = lineMaxSize;
136 }
137 /* Make sure that each line terminates with '\0' */
138 buffer[lineSize] = '\0';
139 int posStart = 0;
140 for (pos = posStart; pos < lineSize; pos++) {
141 if (buffer[pos] == '\n') {
142 buffer[pos] = '\0';
143 BEGET_LOGI("%s", &buffer[posStart]);
144 posStart = pos + 1;
145 }
146 }
147 if (posStart < pos) {
148 BEGET_LOGI("%s", &buffer[posStart]);
149 }
150 } while (1);
151 (void)close(fd);
152 }
153
RedirectToStdFd(int fd)154 static void RedirectToStdFd(int fd)
155 {
156 if (dup2(fd, STDOUT_FILENO) < 0) {
157 BEGET_LOGE("Failed to dup2 stdout, errno: %d, just continue", errno);
158 }
159 if (dup2(fd, STDERR_FILENO) < 0) {
160 BEGET_LOGE("Failed to dup2 stderr, errno: %d, just continue", errno);
161 }
162 (void)close(fd);
163 }
164
ExecCommand(int argc,char ** argv)165 static int ExecCommand(int argc, char **argv)
166 {
167 BEGET_CHECK(!(argc == 0 || argv == NULL || argv[0] == NULL), return -1);
168
169 bool logToKmsg = false;
170 int pipeFds[PIPE_FDS];
171 if (pipe2(pipeFds, O_CLOEXEC) < 0) {
172 BEGET_LOGE("Failed to create pipe, errno: %d, just continue", errno);
173 } else {
174 logToKmsg = true;
175 }
176
177 BEGET_LOGI("Execute %s begin", argv[0]);
178 pid_t pid = fork();
179 BEGET_ERROR_CHECK(pid >= 0, return -1, "Fork new process to format failed: %d", errno);
180 if (pid == 0) {
181 if (logToKmsg) {
182 (void)close(pipeFds[0]);
183 RedirectToStdFd(pipeFds[1]);
184 }
185 execv(argv[0], argv);
186 BEGET_LOGE("Failed to execv, errno: %d", errno);
187 exit(-1);
188 }
189 if (logToKmsg) {
190 (void)close(pipeFds[1]);
191 LogToKmsg(pipeFds[0]);
192 }
193 int status = 0;
194 waitpid(pid, &status, 0);
195 if (WIFEXITED(status)) {
196 BEGET_LOGI("Execute success, status: %d, command: %s", WEXITSTATUS(status), argv[0]);
197 return WEXITSTATUS(status);
198 }
199 BEGET_LOGE("Failed to execute %s", argv[0]);
200 return -1;
201 }
202
DoFormat(const char * devPath,const char * fsType)203 int DoFormat(const char *devPath, const char *fsType)
204 {
205 if (devPath == NULL || fsType == NULL) {
206 return -1;
207 }
208
209 if (!IsSupportedFilesystem(fsType)) {
210 BEGET_LOGE("Do not support filesystem \" %s \"", fsType);
211 return -1;
212 }
213 int ret = 0;
214 if (strcmp(fsType, "ext4") == 0) {
215 char blockSizeBuffer[BLOCK_SIZE_BUFFER] = {0};
216 const unsigned int blockSize = 4096;
217 ret = snprintf_s(blockSizeBuffer, BLOCK_SIZE_BUFFER, BLOCK_SIZE_BUFFER - 1, "%u", blockSize);
218 BEGET_ERROR_CHECK(ret != -1, return -1, "Failed to build block size buffer");
219
220 char *formatCmds[] = {
221 "/bin/mke2fs", "-F", "-t", (char *)fsType, "-b", blockSizeBuffer, (char *)devPath, NULL
222 };
223 int argc = ARRAY_LENGTH(formatCmds);
224 char **argv = (char **)formatCmds;
225 ret = ExecCommand(argc, argv);
226 } else if (IsSupportedDataType(fsType)) {
227 #ifdef __MUSL__
228 char *formatCmds[] = {
229 "/bin/mkfs.f2fs", "-d1", "-O", "encrypt", "-O", "quota", "-O", "verity", "-O", "project_quota,extra_attr",
230 "-O", "sb_checksum", (char *)devPath, NULL
231 };
232 #else
233 char *formatCmds[] = {
234 "/bin/make_f2fs", "-d1", "-O", "encrypt", "-O", "quota", "-O", "verity", "-O", "project_quota,extra_attr",
235 "-O", "sb_checksum", (char *)devPath, NULL
236 };
237 #endif
238 int argc = ARRAY_LENGTH(formatCmds);
239 char **argv = (char **)formatCmds;
240 ret = ExecCommand(argc, argv);
241 }
242 return ret;
243 }
244
GetMountStatusForMountPoint(const char * mp)245 MountStatus GetMountStatusForMountPoint(const char *mp)
246 {
247 if (mp == NULL) {
248 return MOUNT_ERROR;
249 }
250 char buffer[FS_MANAGER_BUFFER_SIZE] = {0};
251 const int expectedItems = 6;
252 int count = 0;
253 char **mountItems = NULL;
254 MountStatus status = MOUNT_ERROR;
255 bool found = false;
256
257 FILE *fp = fopen("/proc/mounts", "r");
258 BEGET_CHECK(fp != NULL, return status);
259
260 while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
261 size_t n = strlen(buffer);
262 if (buffer[n - 1] == '\n') {
263 buffer[n - 1] = '\0';
264 }
265 mountItems = SplitStringExt(buffer, " ", &count, expectedItems);
266 if (mountItems != NULL && count == expectedItems) {
267 // Second item in /proc/mounts is mount point
268 if (strcmp(mountItems[1], mp) == 0) {
269 FreeStringVector(mountItems, count);
270 found = true;
271 break;
272 }
273 FreeStringVector(mountItems, count);
274 }
275 }
276 if (found) {
277 status = MOUNT_MOUNTED;
278 } else if (feof(fp) > 0) {
279 status = MOUNT_UMOUNTED;
280 }
281 (void)fclose(fp);
282 fp = NULL;
283 return status;
284 }
285
286 INIT_STATIC int DoMountOneItem(FstabItem *item);
287 #define MAX_RESIZE_PARAM_NUM 20
DoResizeF2fs(FstabItem * item,const unsigned long long size)288 static int DoResizeF2fs(FstabItem *item, const unsigned long long size)
289 {
290 char *file = "/system/bin/resize.f2fs";
291 char sizeStr[RESIZE_BUFFER_SIZE] = {0};
292 char *argv[MAX_RESIZE_PARAM_NUM] = {NULL};
293 int argc = 0;
294
295 BEGET_ERROR_CHECK(NeedDoAllResize(item->fsManagerFlags), return -1, "no need do resize, bucause kdump has done");
296 BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "resize.f2fs is not exists.");
297
298 argv[argc++] = file;
299 if (item->fsManagerFlags & FS_MANAGER_PROJQUOTA) {
300 argv[argc++] = "-O";
301 argv[argc++] = "extra_attr,project_quota";
302 }
303 if (item->fsManagerFlags & FS_MANAGER_CASEFOLD) {
304 argv[argc++] = "-O";
305 argv[argc++] = "casefold";
306 argv[argc++] = "-C";
307 argv[argc++] = "utf8";
308 }
309 if (item->fsManagerFlags & FS_MANAGER_COMPRESSION) {
310 argv[argc++] = "-O";
311 argv[argc++] = "extra_attr,compression";
312 }
313 if (item->fsManagerFlags & FS_MANAGER_DEDUP) {
314 argv[argc++] = "-O";
315 argv[argc++] = "extra_attr,dedup";
316 }
317
318 if (size != 0) {
319 unsigned long long realSize = size *
320 ((unsigned long long)RESIZE_BUFFER_SIZE * RESIZE_BUFFER_SIZE / FS_MANAGER_BUFFER_SIZE);
321 int len = sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%llu", realSize);
322 if (len <= 0) {
323 BEGET_LOGE("Write buffer size failed.");
324 }
325 argv[argc++] = "-t";
326 argv[argc++] = sizeStr;
327 }
328
329 argv[argc++] = (char*)(item->deviceName);
330 BEGET_ERROR_CHECK(argc <= MAX_RESIZE_PARAM_NUM, return -1, "argc: %d is too big.", argc);
331 int ret = ExecCommand(argc, argv);
332 if (ret == 0) {
333 BEGET_LOGI("resize success.");
334 return ret;
335 }
336 DoMountOneItem(item);
337 umount(item->mountPoint);
338 BEGET_LOGE("remount and resize again.");
339 return ExecCommand(argc, argv);
340 }
341
DoFsckF2fs(const char * device)342 static int DoFsckF2fs(const char* device)
343 {
344 char *file = "/system/bin/fsck.f2fs";
345 BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "fsck.f2fs is not exists.");
346
347 char *cmd[] = {
348 file, "-p1", (char *)device, NULL
349 };
350 int argc = ARRAY_LENGTH(cmd);
351 char **argv = (char **)cmd;
352 InitTimerControl(true);
353 int ret = ExecCommand(argc, argv);
354 InitTimerControl(false);
355 return ret;
356 }
357
DoResizeExt(const char * device,const unsigned long long size)358 static int DoResizeExt(const char* device, const unsigned long long size)
359 {
360 char *file = "/system/bin/resize2fs";
361 BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "resize2fs is not exists.");
362
363 int ret = 0;
364 if (size == 0) {
365 char *cmd[] = {
366 file, "-f", (char *)device, NULL
367 };
368 int argc = ARRAY_LENGTH(cmd);
369 char **argv = (char **)cmd;
370 ret = ExecCommand(argc, argv);
371 } else {
372 char sizeStr[RESIZE_BUFFER_SIZE] = {0};
373 int len = sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%lluM", size);
374 if (len <= 0) {
375 BEGET_LOGE("Write buffer size failed.");
376 }
377 char *cmd[] = {
378 file, "-f", (char *)device, sizeStr, NULL
379 };
380 int argc = ARRAY_LENGTH(cmd);
381 char **argv = (char **)cmd;
382 ret = ExecCommand(argc, argv);
383 }
384 return ret;
385 }
386
DoFsckExt(const char * device)387 static int DoFsckExt(const char* device)
388 {
389 char *file = "/system/bin/e2fsck";
390 BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "e2fsck is not exists.");
391
392 char *cmd[] = {
393 file, "-y", (char *)device, NULL
394 };
395 int argc = ARRAY_LENGTH(cmd);
396 char **argv = (char **)cmd;
397 return ExecCommand(argc, argv);
398 }
399
Mount(const char * source,const char * target,const char * fsType,unsigned long flags,const char * data)400 static int Mount(const char *source, const char *target, const char *fsType,
401 unsigned long flags, const char *data)
402 {
403 struct stat st = {};
404 int rc = -1;
405
406 bool isTrue = source == NULL || target == NULL || fsType == NULL;
407 BEGET_ERROR_CHECK(!isTrue, return -1, "Invalid argument for mount.");
408
409 isTrue = stat(target, &st) != 0 && errno != ENOENT;
410 BEGET_ERROR_CHECK(!isTrue, return -1, "Cannot get stat of \" %s \", err = %d", target, errno);
411
412 BEGET_CHECK((st.st_mode & S_IFMT) != S_IFLNK, unlink(target)); // link, delete it.
413
414 if (mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
415 BEGET_ERROR_CHECK(errno == EEXIST, return -1, "Failed to create dir \" %s \", err = %d", target, errno);
416 }
417 errno = 0;
418 if ((rc = mount(source, target, fsType, flags, data)) != 0) {
419 BEGET_WARNING_CHECK(errno != EBUSY, rc = 0, "Mount %s to %s busy, ignore", source, target);
420 }
421 return rc;
422 }
423
MountWithCheckpoint(const char * source,const char * target,const char * fsType,unsigned long flags,const char * data)424 INIT_STATIC int MountWithCheckpoint(const char *source, const char *target, const char *fsType,
425 unsigned long flags, const char *data)
426 {
427 struct stat st = {};
428 int rc = -1;
429
430 bool isTrue = source == NULL || target == NULL || fsType == NULL;
431 BEGET_ERROR_CHECK(!isTrue, return -1, "Invalid argument for mount.");
432
433 isTrue = stat(target, &st) != 0 && errno != ENOENT;
434 BEGET_ERROR_CHECK(!isTrue, return -1, "Cannot get stat of \" %s \", err = %d", target, errno);
435
436 BEGET_CHECK((st.st_mode & S_IFMT) != S_IFLNK, unlink(target)); // link, delete it.
437
438 if (mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
439 BEGET_ERROR_CHECK(errno == EEXIST, return -1, "Failed to create dir \" %s \", err = %d", target, errno);
440 }
441
442 int gcAllowance = 0;
443 do {
444 char realData[FS_MANAGER_BUFFER_SIZE] = {0};
445 int bytes = snprintf_s(realData, FS_MANAGER_BUFFER_SIZE, FS_MANAGER_BUFFER_SIZE - 1, "%s,%s:%d%%",
446 data, "checkpoint=disable", gcAllowance);
447 if (bytes <= 0) {
448 BEGET_LOGE("build realData failed");
449 break;
450 }
451 rc = mount(source, target, fsType, flags, realData);
452 BEGET_LOGI("MountWithCheckpoint %s %d %d", realData, rc, errno);
453
454 if (rc != 0 && errno == EBUSY) {
455 rc = 0;
456 }
457 gcAllowance += GCALLOWANCE_INCREACE;
458 } while (rc != 0 && errno == EAGAIN && gcAllowance <= MAX_GCALLOWNANCE);
459
460 return rc;
461 }
462
GetSlotInfoFromCmdLine(const char * slotInfoName)463 static int GetSlotInfoFromCmdLine(const char *slotInfoName)
464 {
465 char value[MAX_BUFFER_LEN] = {0};
466 BEGET_INFO_CHECK(GetParameterFromCmdLine(slotInfoName, value, MAX_BUFFER_LEN) == 0,
467 return -1, "Failed to get %s value from cmdline", slotInfoName);
468 return atoi(value);
469 }
470
GetSlotInfoFromBootctrl(off_t offset,off_t size)471 static int GetSlotInfoFromBootctrl(off_t offset, off_t size)
472 {
473 char bootctrlDev[MAX_BUFFER_LEN] = {0};
474 BEGET_ERROR_CHECK(GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) == 0,
475 return -1, "Failed to get bootctrl device");
476 char *realPath = GetRealPath(bootctrlDev);
477 BEGET_ERROR_CHECK(realPath != NULL, return -1, "Failed to get bootctrl device real path");
478 int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
479 free(realPath);
480 BEGET_ERROR_CHECK(fd >= 0, return -1, "Failed to open bootctrl device, errno %d", errno);
481 BEGET_ERROR_CHECK(lseek(fd, offset, SEEK_SET) >= 0, close(fd); return -1,
482 "Failed to lseek bootctrl device fd, errno %d", errno);
483 int slotInfo = 0;
484 BEGET_INFO_CHECK(read(fd, &slotInfo, sizeof(slotInfo)) == size, close(fd); return -1,
485 "Failed to read current slot from bootctrl, errno %d", errno);
486 close(fd);
487 return slotInfo;
488 }
489
GetBootSlots(void)490 int GetBootSlots(void)
491 {
492 if (g_bootSlots != -1) {
493 return g_bootSlots;
494 }
495 g_bootSlots = GetSlotInfoFromCmdLine("bootslots");
496 return g_bootSlots;
497 }
498
GetCurrentSlot(void)499 int GetCurrentSlot(void)
500 {
501 if (g_currentSlot != -1) {
502 return g_currentSlot;
503 }
504 // get current slot from cmdline
505 int currentSlot = GetSlotInfoFromCmdLine("currentslot");
506 BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
507 BEGET_LOGI("No valid slot value found from cmdline, try to get it from bootctrl");
508
509 // get current slot from bootctrl
510 return GetSlotInfoFromBootctrl(PARTITION_ACTIVE_SLOT_OFFSET, PARTITION_ACTIVE_SLOT_SIZE);
511 }
512
GetDataWithoutCheckpoint(char * fsSpecificData,size_t fsSpecificDataSize,char * checkpointData,size_t checkpointDataSize)513 INIT_STATIC int GetDataWithoutCheckpoint(char *fsSpecificData, size_t fsSpecificDataSize,
514 char *checkpointData, size_t checkpointDataSize)
515 {
516 if (fsSpecificData == NULL || strstr(fsSpecificData, "checkpoint=disable") == NULL) {
517 BEGET_LOGI("Not checkpoint Mount info");
518 return -1;
519 }
520 if (checkpointData == NULL) {
521 BEGET_LOGE("invalid outData");
522 return -1;
523 }
524 int flagCount = 0;
525 const int maxCount = 15;
526 char *splitStr = strdup(fsSpecificData);
527 if (splitStr == NULL) {
528 BEGET_LOGI("dump fsData failed");
529 return -1;
530 }
531 char **flagsVector = SplitStringExt(splitStr, ",", &flagCount, maxCount);
532 if (flagsVector == NULL || flagCount <= 0) {
533 free(splitStr);
534 BEGET_LOGE("split fsData failed");
535 return -1;
536 }
537 const char *disableCheckpoint = "checkpoint=disable";
538 int rc = 0;
539 for (int i = 0; i < flagCount; i++) {
540 char *p = flagsVector[i];
541 if (strncmp(p, disableCheckpoint, strlen(disableCheckpoint)) == 0) {
542 continue;
543 }
544 if (strcmp(checkpointData, "") != 0 &&
545 strncat_s(checkpointData, checkpointDataSize - 1, ",", 1) != EOK) {
546 BEGET_LOGW("failed to append comma.");
547 rc = -1;
548 break;
549 }
550 if (strncat_s(checkpointData, checkpointDataSize - 1, p, strlen(p)) != EOK) {
551 BEGET_LOGW("Failed to append mountflags \" %s \", ignore it.", p);
552 rc = -1;
553 break;
554 }
555 }
556 FreeStringVector(flagsVector, flagCount);
557 free(splitStr);
558 BEGET_LOGI("removeCheckpoint with fsData %s", fsSpecificData);
559 BEGET_LOGI("removeCheckpoint with resultData %s", checkpointData);
560 return rc;
561 }
562
DoMountOneItem(FstabItem * item)563 INIT_STATIC int DoMountOneItem(FstabItem *item)
564 {
565 BEGET_LOGI("Mount device %s to %s", item->deviceName, item->mountPoint);
566 unsigned long mountFlags;
567 char fsSpecificData[FS_MANAGER_BUFFER_SIZE] = {0};
568 char checkpointData[FS_MANAGER_BUFFER_SIZE] = {0};
569
570 bool isCheckpoint = false;
571 mountFlags = GetMountFlags(item->mountOptions, fsSpecificData, sizeof(fsSpecificData),
572 item->mountPoint);
573
574 // 是否包含checkpoint + 文件系统类型
575 if (strcmp(item->fsType, "hmfs") == 0 && strstr(fsSpecificData, "checkpoint=disable") != NULL &&
576 GetDataWithoutCheckpoint(fsSpecificData, FS_MANAGER_BUFFER_SIZE,
577 checkpointData, FS_MANAGER_BUFFER_SIZE) == 0) {
578 isCheckpoint = true;
579 }
580
581 int retryCount = 3;
582 int rc = 0;
583 while (retryCount-- > 0) {
584 if (isCheckpoint) {
585 rc = MountWithCheckpoint(item->deviceName, item->mountPoint, item->fsType, mountFlags, checkpointData);
586 } else {
587 rc = Mount(item->deviceName, item->mountPoint, item->fsType, mountFlags, fsSpecificData);
588 }
589
590 if (rc == 0) {
591 return rc;
592 }
593
594 if (FM_MANAGER_FORMATTABLE_ENABLED(item->fsManagerFlags)) {
595 BEGET_LOGI("Device is formattable");
596 int ret = DoFormat(item->deviceName, item->fsType);
597 BEGET_LOGI("End format image ret %d", ret);
598 if (ret != 0) {
599 continue;
600 }
601 rc = Mount(item->deviceName, item->mountPoint, item->fsType, mountFlags, fsSpecificData);
602 if (rc == 0) {
603 return rc;
604 }
605 }
606 BEGET_LOGE("Mount device %s to %s failed, err = %d, retry", item->deviceName, item->mountPoint, errno);
607 }
608 return rc;
609 }
610
611 #ifdef EROFS_OVERLAY
MountItemByFsType(FstabItem * item)612 static int MountItemByFsType(FstabItem *item)
613 {
614 if (CheckIsErofs(item->deviceName)) {
615 if (strcmp(item->fsType, "erofs") == 0) {
616 if (IsOverlayEnable()) {
617 return DoMountOverlayDevice(item);
618 }
619 int rc = DoMountOneItem(item);
620 if (rc == 0 && strcmp(item->mountPoint, "/usr") == 0) {
621 SwitchRoot("/usr");
622 }
623 return rc;
624 } else {
625 BEGET_LOGI("fsType not erofs system, device [%s] skip erofs mount process", item->deviceName);
626 return 0;
627 }
628 }
629
630 if (strcmp(item->fsType, "erofs") != 0) {
631 int rc = DoMountOneItem(item);
632 if (rc == 0 && strcmp(item->mountPoint, "/usr") == 0) {
633 SwitchRoot("/usr");
634 }
635 return rc;
636 }
637
638 BEGET_LOGI("fsType is erofs system, device [%s] skip ext4 or hms mount process", item->deviceName);
639 return 0;
640 }
641 #endif
642
ExecCheckpointHook(FstabItem * item)643 static int ExecCheckpointHook(FstabItem *item)
644 {
645 HOOK_EXEC_OPTIONS options;
646 options.flags = TRAVERSE_STOP_WHEN_ERROR;
647 options.postHook = NULL;
648 options.preHook = NULL;
649 int ret = HookMgrExecute(GetBootStageHookMgr(), INIT_DISABLE_CHECKPOINT, (void*)item, &options);
650 BEGET_LOGI("ExecCheckpointHook ret %d", ret);
651 return ret;
652 }
MountOneItem(FstabItem * item)653 int MountOneItem(FstabItem *item)
654 {
655 if (item == NULL) {
656 return -1;
657 }
658
659 if (FM_MANAGER_WAIT_ENABLED(item->fsManagerFlags)) {
660 WaitForFile(item->deviceName, WAIT_MAX_SECOND);
661 }
662
663 int disableCheckpointRet = -1;
664 if (strcmp(item->mountPoint, "/data") == 0 && IsSupportedDataType(item->fsType)) {
665 int ret = DoFsckF2fs(item->deviceName);
666 if (ret != 0) {
667 BEGET_LOGE("Failed to fsck.f2fs dir %s , ret = %d", item->deviceName, ret);
668 }
669 ret = DoResizeF2fs(item, 0);
670 if (ret != 0) {
671 BEGET_LOGE("Failed to resize.f2fs dir %s , ret = %d", item->deviceName, ret);
672 }
673 disableCheckpointRet = ExecCheckpointHook(item);
674 } else if (strcmp(item->fsType, "ext4") == 0 && strcmp(item->mountPoint, "/data") == 0) {
675 int ret = DoResizeExt(item->deviceName, 0);
676 if (ret != 0) {
677 BEGET_LOGE("Failed to resize2fs dir %s , ret = %d", item->deviceName, ret);
678 }
679 ret = DoFsckExt(item->deviceName);
680 if (ret != 0) {
681 BEGET_LOGE("Failed to e2fsck dir %s , ret = %d", item->deviceName, ret);
682 }
683 }
684
685 int rc = 0;
686 #ifdef EROFS_OVERLAY
687 rc = MountItemByFsType(item);
688 #else
689 rc = DoMountOneItem(item);
690 if (rc == 0 && (strcmp(item->mountPoint, "/usr") == 0)) {
691 SwitchRoot("/usr");
692 }
693 #endif
694 if (disableCheckpointRet == 0 && rc == 0) {
695 BEGET_LOGI("start health check process");
696 HookMgrExecute(GetBootStageHookMgr(), INIT_HEALTH_CHECK_ACTIVE, NULL, NULL);
697 }
698 InitPostMount(item->mountPoint, rc);
699 if (rc != 0) {
700 if (FM_MANAGER_NOFAIL_ENABLED(item->fsManagerFlags)) {
701 BEGET_LOGE("Mount no fail device %s to %s failed, err = %d", item->deviceName, item->mountPoint, errno);
702 } else {
703 BEGET_LOGW("Mount %s to %s failed, err = %d. Ignore failure", item->deviceName, item->mountPoint, errno);
704 rc = 0;
705 }
706 } else {
707 BEGET_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint);
708 }
709 return rc;
710 }
711
712 #if defined EROFS_OVERLAY && defined SUPPORT_HVB
NeedDmVerity(FstabItem * item)713 static bool NeedDmVerity(FstabItem *item)
714 {
715 if (CheckIsErofs(item->deviceName)) {
716 if (strcmp(item->fsType, "erofs") == 0) {
717 return true;
718 }
719 } else {
720 if (strcmp(item->fsType, "erofs") != 0) {
721 return true;
722 }
723 }
724 return false;
725 }
726 #endif
727
AdjustPartitionNameByPartitionSlot(FstabItem * item)728 static void AdjustPartitionNameByPartitionSlot(FstabItem *item)
729 {
730 char buffer[MAX_BUFFER_LEN] = {0};
731 g_currentSlot = GetCurrentSlot();
732 BEGET_ERROR_CHECK(g_currentSlot > 0 && g_currentSlot <= MAX_SLOT, g_currentSlot = 1,
733 "slot value %d is invalid, set default value", g_currentSlot);
734 BEGET_ERROR_CHECK(sprintf_s(buffer, sizeof(buffer), "%s_%c", item->deviceName, 'a' + g_currentSlot - 1) > 0,
735 return, "Failed to format partition name suffix, use default partition name");
736 if (access(buffer, F_OK) != 0) {
737 BEGET_LOGW("not support AB partition: %s", item->deviceName);
738 return;
739 }
740 free(item->deviceName);
741 item->deviceName = strdup(buffer);
742 if (item->deviceName == NULL) {
743 BEGET_LOGE("failed dup devicename");
744 return;
745 }
746 BEGET_LOGI("partition name with slot suffix: %s", item->deviceName);
747 }
748
CheckRequiredAndMount(FstabItem * item,bool required)749 static int CheckRequiredAndMount(FstabItem *item, bool required)
750 {
751 int rc = 0;
752 if (item == NULL) {
753 return -1;
754 }
755
756 // Mount partition during second startup.
757 if (!required) {
758 if (!FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
759 BEGET_INFO_CHECK(GetBootSlots() <= 1, AdjustPartitionNameByPartitionSlot(item),
760 "boot slots is %d, now adjust partition name according to current slot", GetBootSlots());
761 rc = MountOneItem(item);
762 }
763 return rc;
764 }
765
766 // Mount partition during one startup.
767 if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
768 BEGET_INFO_CHECK(GetBootSlots() <= 1, AdjustPartitionNameByPartitionSlot(item),
769 "boot slots is %d, now adjust partition name according to current slot", GetBootSlots());
770 #ifdef SUPPORT_HVB
771 #ifdef EROFS_OVERLAY
772 if (!NeedDmVerity(item)) {
773 BEGET_LOGI("not need dm verity, do mount item %s", item->deviceName);
774 return MountOneItem(item);
775 }
776 #endif
777 rc = HvbDmVeritySetUp(item);
778 if (rc != 0) {
779 BEGET_LOGE("set dm_verity err, ret = 0x%x", rc);
780 if (!FM_MANAGER_NOFAIL_ENABLED(item->fsManagerFlags)) {
781 rc = 0;
782 BEGET_LOGW("DmVeritySetUp fail for %s, ignore error and do not mount", item->deviceName);
783 } else {
784 BEGET_LOGE("DmVeritySetUp fail for no fail devices %s, error!", item->deviceName);
785 }
786 return rc;
787 }
788 #endif
789 rc = MountOneItem(item);
790 }
791 return rc;
792 }
793
MountAllWithFstab(const Fstab * fstab,bool required)794 int MountAllWithFstab(const Fstab *fstab, bool required)
795 {
796 BEGET_CHECK(fstab != NULL, return -1);
797
798 FstabItem *item = NULL;
799 int rc = -1;
800
801 #ifdef SUPPORT_HVB
802 if (required) {
803 rc = HvbDmVerityinit(fstab);
804 if (rc != 0) {
805 BEGET_LOGE("set dm_verity init, ret = 0x%x", rc);
806 return rc;
807 }
808 }
809 #endif
810
811 for (item = fstab->head; item != NULL; item = item->next) {
812 rc = CheckRequiredAndMount(item, required);
813 if (required && (rc < 0)) { // Init fail to mount in the first stage and exit directly.
814 break;
815 }
816 }
817
818 #ifdef SUPPORT_HVB
819 if (required)
820 HvbDmVerityFinal();
821 #endif
822
823 return rc;
824 }
825
MountAllWithFstabFile(const char * fstabFile,bool required)826 int MountAllWithFstabFile(const char *fstabFile, bool required)
827 {
828 bool isFile = fstabFile == NULL || *fstabFile == '\0';
829 BEGET_CHECK(!isFile, return -1);
830
831 Fstab *fstab = NULL;
832 if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) {
833 BEGET_LOGE("[fs_manager][error] Read fstab file \" %s \" failed\n", fstabFile);
834 return -1;
835 }
836
837 int rc = MountAllWithFstab(fstab, required);
838 if (rc != 0) {
839 BEGET_LOGE("[startup_failed]MountAllWithFstab failed %s %d %d %d", fstabFile,
840 FSTAB_MOUNT_FAILED, required, rc);
841 }
842 ReleaseFstab(fstab);
843 fstab = NULL;
844 return rc;
845 }
846
UmountAllWithFstabFile(const char * fstabFile)847 int UmountAllWithFstabFile(const char *fstabFile)
848 {
849 bool isFile = fstabFile == NULL || *fstabFile == '\0';
850 BEGET_CHECK(!isFile, return -1);
851
852 Fstab *fstab = NULL;
853 fstab = ReadFstabFromFile(fstabFile, false);
854 BEGET_ERROR_CHECK(fstab != NULL, return -1, "Read fstab file \" %s \" failed.", fstabFile);
855
856 FstabItem *item = NULL;
857 int rc = -1;
858 for (item = fstab->head; item != NULL; item = item->next) {
859 BEGET_LOGI("Umount %s.", item->mountPoint);
860 MountStatus status = GetMountStatusForMountPoint(item->mountPoint);
861 if (status == MOUNT_ERROR) {
862 BEGET_LOGW("Cannot get mount status of mount point \" %s \"", item->mountPoint);
863 continue; // Cannot get mount status, just ignore it and try next one.
864 } else if (status == MOUNT_UMOUNTED) {
865 BEGET_LOGI("Mount point \" %s \" already unmounted. device path: %s, fs type: %s.",
866 item->mountPoint, item->deviceName, item->fsType);
867 continue;
868 } else {
869 rc = umount(item->mountPoint);
870 if (rc == -1) {
871 BEGET_LOGE("Umount %s failed, device path: %s, fs type: %s, err = %d.",
872 item->mountPoint, item->deviceName, item->fsType, errno);
873 } else {
874 BEGET_LOGE("Umount %s successfully.", item->mountPoint);
875 }
876 }
877 }
878 ReleaseFstab(fstab);
879 fstab = NULL;
880 return rc;
881 }
882
FsManagerDmRemoveDevice(const char * devName)883 int FsManagerDmRemoveDevice(const char *devName)
884 {
885 #ifdef SUPPORT_HVB
886 return FsDmRemoveDevice(devName);
887 #endif
888 return 0;
889 }
890
MountOneWithFstabFile(const char * fstabFile,const char * devName,bool required)891 int MountOneWithFstabFile(const char *fstabFile, const char *devName, bool required)
892 {
893 bool isFile = fstabFile == NULL || *fstabFile == '\0';
894 BEGET_CHECK(!isFile, return -1);
895
896 Fstab *fstab = NULL;
897 fstab = ReadFstabFromFile(fstabFile, false);
898 BEGET_ERROR_CHECK(fstab != NULL, return -1, "Read fstab file \" %s \" failed.", fstabFile);
899
900 FstabItem *item = NULL;
901 int rc = -1;
902
903 #ifdef SUPPORT_HVB
904 if (required) {
905 rc = HvbDmVerityinit(fstab);
906 if (rc != 0) {
907 BEGET_LOGE("set dm_verity init, ret = 0x%x", rc);
908 ReleaseFstab(fstab);
909 fstab = NULL;
910 return rc;
911 }
912 }
913 #endif
914
915 for (item = fstab->head; item != NULL; item = item->next) {
916 if (strcmp(item->mountPoint, devName) == 0) {
917 rc = CheckRequiredAndMount(item, required);
918 break;
919 }
920 }
921
922 #ifdef SUPPORT_HVB
923 if (required) {
924 HvbDmVerityFinal();
925 }
926 #endif
927
928 ReleaseFstab(fstab);
929 fstab = NULL;
930 return rc;
931 }
932
933 #ifdef __cplusplus
934 #if __cplusplus
935 }
936 #endif
937 #endif
938