• 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 <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