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