• 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 "fs_manager/fs_manager.h"
27 #include "init_utils.h"
28 #include "param/init_param.h"
29 #include "securec.h"
30 #ifdef SUPPORT_HVB
31 #include "dm_verity.h"
32 #endif
33 #include "init_filesystems.h"
34 
35 #ifdef __cplusplus
36 #if __cplusplus
37 extern "C" {
38 #endif
39 #endif
40 
41 #define FS_MANAGER_BUFFER_SIZE 512
42 #define BLOCK_SIZE_BUFFER (64)
43 #define RESIZE_BUFFER_SIZE 1024
44 const off_t PARTITION_ACTIVE_SLOT_OFFSET = 1024;
45 const off_t PARTITION_ACTIVE_SLOT_SIZE = 4;
46 
InitPostMount(const char * mountPoint,int rc)47 __attribute__((weak)) void InitPostMount(const char *mountPoint, int rc)
48 {
49 }
50 
51 static const SUPPORTED_FILE_SYSTEM supportedFileSystems[] = {
52     { "ext4", 0 },
53     { "f2fs", 1 },
54     { "overlay", 0 },
55     { NULL, 0 }
56 };
57 
58 static void **extendedFileSystems_ = NULL;
59 
InitSetExtendedFileSystems(const SUPPORTED_FILE_SYSTEM * extendedFileSystems[])60 void InitSetExtendedFileSystems(const SUPPORTED_FILE_SYSTEM *extendedFileSystems[])
61 {
62     extendedFileSystems_ = (void **)extendedFileSystems;
63 }
64 
GetSupportedFileSystemInfo(const char * fsType)65 static const SUPPORTED_FILE_SYSTEM *GetSupportedFileSystemInfo(const char *fsType)
66 {
67     return (const SUPPORTED_FILE_SYSTEM *)OH_ExtendableStrDictGet((void **)supportedFileSystems,
68            sizeof(SUPPORTED_FILE_SYSTEM), fsType, 0, extendedFileSystems_);
69 }
70 
IsSupportedDataType(const char * fsType)71 static bool IsSupportedDataType(const char *fsType)
72 {
73     const SUPPORTED_FILE_SYSTEM *item = GetSupportedFileSystemInfo(fsType);
74     if (item == NULL) {
75         return false;
76     }
77     if (item->for_userdata) {
78         return true;
79     }
80     return false;
81 }
82 
IsSupportedFilesystem(const char * fsType)83 bool IsSupportedFilesystem(const char *fsType)
84 {
85     const SUPPORTED_FILE_SYSTEM *item = GetSupportedFileSystemInfo(fsType);
86     if (item == NULL) {
87         return false;
88     }
89     return true;
90 }
91 
ExecCommand(int argc,char ** argv)92 static int ExecCommand(int argc, char **argv)
93 {
94     BEGET_CHECK(!(argc == 0 || argv == NULL || argv[0] == NULL), return -1);
95 
96     BEGET_LOGI("Execute %s begin", argv[0]);
97     pid_t pid = fork();
98     BEGET_ERROR_CHECK(pid >= 0, return -1, "Fork new process to format failed: %d", errno);
99 
100     if (pid == 0) {
101         execv(argv[0], argv);
102         exit(-1);
103     }
104     int status;
105     waitpid(pid, &status, 0);
106     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
107         BEGET_LOGE("Command %s failed with status %d", argv[0], WEXITSTATUS(status));
108     }
109     BEGET_LOGI("Execute %s end", argv[0]);
110     return WEXITSTATUS(status);
111 }
112 
DoFormat(const char * devPath,const char * fsType)113 int DoFormat(const char *devPath, const char *fsType)
114 {
115     if (devPath == NULL || fsType == NULL) {
116         return -1;
117     }
118 
119     if (!IsSupportedFilesystem(fsType)) {
120         BEGET_LOGE("Do not support filesystem \" %s \"", fsType);
121         return -1;
122     }
123     int ret = 0;
124     if (strcmp(fsType, "ext4") == 0) {
125         char blockSizeBuffer[BLOCK_SIZE_BUFFER] = {0};
126         const unsigned int blockSize = 4096;
127         ret = snprintf_s(blockSizeBuffer, BLOCK_SIZE_BUFFER, BLOCK_SIZE_BUFFER - 1, "%u", blockSize);
128         BEGET_ERROR_CHECK(ret != -1, return -1, "Failed to build block size buffer");
129 
130         char *formatCmds[] = {
131             "/bin/mke2fs", "-F", "-t", (char *)fsType, "-b", blockSizeBuffer, (char *)devPath, NULL
132         };
133         int argc = ARRAY_LENGTH(formatCmds);
134         char **argv = (char **)formatCmds;
135         ret = ExecCommand(argc, argv);
136     } else if (IsSupportedDataType(fsType)) {
137 #ifdef __MUSL__
138         char *formatCmds[] = {
139             "/bin/mkfs.f2fs", "-d1", "-O", "encrypt", "-O", "quota", "-O", "verity", "-O", "project_quota,extra_attr",
140             "-O", "sb_checksum", (char *)devPath, NULL
141         };
142 #else
143         char *formatCmds[] = {
144             "/bin/make_f2fs", "-d1", "-O", "encrypt", "-O", "quota", "-O", "verity",  "-O", "project_quota,extra_attr",
145             "-O", "sb_checksum", (char *)devPath, NULL
146         };
147 #endif
148         int argc = ARRAY_LENGTH(formatCmds);
149         char **argv = (char **)formatCmds;
150         ret = ExecCommand(argc, argv);
151     }
152     return ret;
153 }
154 
GetMountStatusForMountPoint(const char * mp)155 MountStatus GetMountStatusForMountPoint(const char *mp)
156 {
157     if (mp == NULL) {
158         return MOUNT_ERROR;
159     }
160     char buffer[FS_MANAGER_BUFFER_SIZE] = {0};
161     const int expectedItems = 6;
162     int count = 0;
163     char **mountItems = NULL;
164     MountStatus status = MOUNT_ERROR;
165     bool found = false;
166 
167     FILE *fp = fopen("/proc/mounts", "r");
168     BEGET_CHECK(fp != NULL, return status);
169 
170     while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
171         size_t n = strlen(buffer);
172         if (buffer[n - 1] == '\n') {
173             buffer[n - 1] = '\0';
174         }
175         mountItems = SplitStringExt(buffer, " ", &count, expectedItems);
176         if (mountItems != NULL && count == expectedItems) {
177             // Second item in /proc/mounts is mount point
178             if (strcmp(mountItems[1], mp) == 0) {
179                 FreeStringVector(mountItems, count);
180                 found = true;
181                 break;
182             }
183             FreeStringVector(mountItems, count);
184         }
185     }
186     if (found) {
187         status = MOUNT_MOUNTED;
188     } else if (feof(fp) > 0) {
189         status = MOUNT_UMOUNTED;
190     }
191     (void)fclose(fp);
192     fp = NULL;
193     return status;
194 }
195 
196 #define MAX_RESIZE_PARAM_NUM 20
DoResizeF2fs(const char * device,const unsigned long long size,const unsigned int fsManagerFlags)197 static int DoResizeF2fs(const char* device, const unsigned long long size, const unsigned int fsManagerFlags)
198 {
199     char *file = "/system/bin/resize.f2fs";
200     char sizeStr[RESIZE_BUFFER_SIZE] = {0};
201     char *argv[MAX_RESIZE_PARAM_NUM] = {NULL};
202     int argc = 0;
203 
204     BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "resize.f2fs is not exists.");
205 
206     argv[argc++] = file;
207     if (fsManagerFlags & FS_MANAGER_PROJQUOTA) {
208         argv[argc++] = "-O";
209         argv[argc++] = "extra_attr,project_quota";
210     }
211     if (fsManagerFlags & FS_MANAGER_CASEFOLD) {
212         argv[argc++] = "-O";
213         argv[argc++] = "casefold";
214         argv[argc++] = "-C";
215         argv[argc++] = "utf8";
216     }
217     if (fsManagerFlags & FS_MANAGER_COMPRESSION) {
218         argv[argc++] = "-O";
219         argv[argc++] = "extra_attr,compression";
220     }
221     if (fsManagerFlags & FS_MANAGER_DEDUP) {
222         argv[argc++] = "-O";
223         argv[argc++] = "extra_attr,dedup";
224     }
225 
226     if (size != 0) {
227         unsigned long long realSize = size *
228             ((unsigned long long)RESIZE_BUFFER_SIZE * RESIZE_BUFFER_SIZE / FS_MANAGER_BUFFER_SIZE);
229         int len = sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%llu", realSize);
230         if (len <= 0) {
231             BEGET_LOGE("Write buffer size failed.");
232         }
233         argv[argc++] = "-t";
234         argv[argc++] = sizeStr;
235     }
236 
237     argv[argc++] = (char*)device;
238     BEGET_ERROR_CHECK(argc <= MAX_RESIZE_PARAM_NUM, return -1, "argc: %d is too big.", argc);
239     return ExecCommand(argc, argv);
240 }
241 
DoFsckF2fs(const char * device)242 static int DoFsckF2fs(const char* device)
243 {
244     char *file = "/system/bin/fsck.f2fs";
245     BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "fsck.f2fs is not exists.");
246 
247     char *cmd[] = {
248         file, "-p1", (char *)device, NULL
249     };
250     int argc = ARRAY_LENGTH(cmd);
251     char **argv = (char **)cmd;
252     return ExecCommand(argc, argv);
253 }
254 
DoResizeExt(const char * device,const unsigned long long size)255 static int DoResizeExt(const char* device, const unsigned long long size)
256 {
257     char *file = "/system/bin/resize2fs";
258     BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "resize2fs is not exists.");
259 
260     int ret = 0;
261     if (size == 0) {
262         char *cmd[] = {
263             file, "-f", (char *)device, NULL
264         };
265         int argc = ARRAY_LENGTH(cmd);
266         char **argv = (char **)cmd;
267         ret = ExecCommand(argc, argv);
268     } else {
269         char sizeStr[RESIZE_BUFFER_SIZE] = {0};
270         int len = sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%lluM", size);
271         if (len <= 0) {
272             BEGET_LOGE("Write buffer size failed.");
273         }
274         char *cmd[] = {
275             file, "-f", (char *)device, sizeStr, NULL
276         };
277         int argc = ARRAY_LENGTH(cmd);
278         char **argv = (char **)cmd;
279         ret = ExecCommand(argc, argv);
280     }
281     return ret;
282 }
283 
DoFsckExt(const char * device)284 static int DoFsckExt(const char* device)
285 {
286     char *file = "/system/bin/e2fsck";
287     BEGET_ERROR_CHECK(access(file, F_OK) == 0, return -1, "e2fsck is not exists.");
288 
289     char *cmd[] = {
290         file, "-y", (char *)device, NULL
291     };
292     int argc = ARRAY_LENGTH(cmd);
293     char **argv = (char **)cmd;
294     return ExecCommand(argc, argv);
295 }
296 
Mount(const char * source,const char * target,const char * fsType,unsigned long flags,const char * data)297 static int Mount(const char *source, const char *target, const char *fsType,
298     unsigned long flags, const char *data)
299 {
300     struct stat st = {};
301     int rc = -1;
302 
303     bool isTrue = source == NULL || target == NULL || fsType == NULL;
304     BEGET_ERROR_CHECK(!isTrue, return -1, "Invalid argument for mount.");
305 
306     isTrue = stat(target, &st) != 0 && errno != ENOENT;
307     BEGET_ERROR_CHECK(!isTrue, return -1, "Cannot get stat of \" %s \", err = %d", target, errno);
308 
309     BEGET_CHECK((st.st_mode & S_IFMT) != S_IFLNK, unlink(target)); // link, delete it.
310 
311     if (mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
312         BEGET_ERROR_CHECK(errno == EEXIST, return -1, "Failed to create dir \" %s \", err = %d", target, errno);
313     }
314     errno = 0;
315     if ((rc = mount(source, target, fsType, flags, data)) != 0) {
316         BEGET_WARNING_CHECK(errno != EBUSY, rc = 0, "Mount %s to %s busy, ignore", source, target);
317     }
318     return rc;
319 }
320 
GetSlotInfoFromCmdLine(const char * slotInfoName)321 static int GetSlotInfoFromCmdLine(const char *slotInfoName)
322 {
323     char value[MAX_BUFFER_LEN] = {0};
324     BEGET_INFO_CHECK(GetParameterFromCmdLine(slotInfoName, value, MAX_BUFFER_LEN) == 0,
325         return -1, "Failed to get %s value from cmdline", slotInfoName);
326     return atoi(value);
327 }
328 
GetSlotInfoFromBootctrl(off_t offset,off_t size)329 static int GetSlotInfoFromBootctrl(off_t offset, off_t size)
330 {
331     char bootctrlDev[MAX_BUFFER_LEN] = {0};
332     BEGET_ERROR_CHECK(GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) == 0,
333         return -1, "Failed to get bootctrl device");
334     char *realPath = GetRealPath(bootctrlDev);
335     BEGET_ERROR_CHECK(realPath != NULL, return -1, "Failed to get bootctrl device real path");
336     int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
337     free(realPath);
338     BEGET_ERROR_CHECK(fd >= 0, return -1, "Failed to open bootctrl device, errno %d", errno);
339     BEGET_ERROR_CHECK(lseek(fd, offset, SEEK_SET) >= 0, close(fd); return -1,
340         "Failed to lseek bootctrl device fd, errno %d", errno);
341     int slotInfo = 0;
342     BEGET_INFO_CHECK(read(fd, &slotInfo, sizeof(slotInfo)) == size, close(fd); return -1,
343         "Failed to read current slot from bootctrl, errno %d", errno);
344     close(fd);
345     return slotInfo;
346 }
347 
GetBootSlots(void)348 int GetBootSlots(void)
349 {
350     return GetSlotInfoFromCmdLine("bootslots");
351 }
352 
GetCurrentSlot(void)353 int GetCurrentSlot(void)
354 {
355     // get current slot from cmdline
356     int currentSlot = GetSlotInfoFromCmdLine("currentslot");
357     BEGET_CHECK_RETURN_VALUE(currentSlot <= 0, currentSlot);
358     BEGET_LOGI("No valid slot value found from cmdline, try to get it from bootctrl");
359 
360     // get current slot from bootctrl
361     return GetSlotInfoFromBootctrl(PARTITION_ACTIVE_SLOT_OFFSET, PARTITION_ACTIVE_SLOT_SIZE);
362 }
363 
MountOneItem(FstabItem * item)364 int MountOneItem(FstabItem *item)
365 {
366     if (item == NULL) {
367         return -1;
368     }
369     unsigned long mountFlags;
370     char fsSpecificData[FS_MANAGER_BUFFER_SIZE] = {0};
371 
372     mountFlags = GetMountFlags(item->mountOptions, fsSpecificData, sizeof(fsSpecificData),
373         item->mountPoint);
374     if (!IsSupportedFilesystem(item->fsType)) {
375         BEGET_LOGE("Unsupported file system \" %s \"", item->fsType);
376         return 0;
377     }
378     if (FM_MANAGER_WAIT_ENABLED(item->fsManagerFlags)) {
379         WaitForFile(item->deviceName, WAIT_MAX_SECOND);
380     }
381 
382     if (strcmp(item->mountPoint, "/data") == 0 && IsSupportedDataType(item->fsType)) {
383         int ret = DoResizeF2fs(item->deviceName, 0, item->fsManagerFlags);
384         if (ret != 0) {
385             BEGET_LOGE("Failed to resize.f2fs dir %s , ret = %d", item->deviceName, ret);
386         }
387 
388         ret = DoFsckF2fs(item->deviceName);
389         if (ret != 0) {
390             BEGET_LOGE("Failed to fsck.f2fs dir %s , ret = %d", item->deviceName, ret);
391         }
392     } else if (strcmp(item->fsType, "ext4") == 0 && strcmp(item->mountPoint, "/data") == 0) {
393         int ret = DoResizeExt(item->deviceName, 0);
394         if (ret != 0) {
395             BEGET_LOGE("Failed to resize2fs dir %s , ret = %d", item->deviceName, ret);
396         }
397         ret = DoFsckExt(item->deviceName);
398         if (ret != 0) {
399             BEGET_LOGE("Failed to e2fsck dir %s , ret = %d", item->deviceName, ret);
400         }
401     }
402 
403     int retryCount = 3;
404     int rc = 0;
405     while (retryCount-- > 0) {
406         rc = Mount(item->deviceName, item->mountPoint, item->fsType, mountFlags, fsSpecificData);
407         if (rc == 0) {
408             break;
409         }
410         BEGET_LOGE("Mount device %s to %s failed, err = %d, retry", item->deviceName, item->mountPoint, errno);
411     }
412     InitPostMount(item->mountPoint, rc);
413     if (rc != 0) {
414         if (FM_MANAGER_NOFAIL_ENABLED(item->fsManagerFlags)) {
415             BEGET_LOGE("Mount no fail device %s to %s failed, err = %d", item->deviceName, item->mountPoint, errno);
416         } else {
417             BEGET_LOGW("Mount %s to %s failed, err = %d. Ignore failure", item->deviceName, item->mountPoint, errno);
418             rc = 0;
419         }
420     } else {
421         BEGET_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint);
422     }
423     return rc;
424 }
425 
AdjustPartitionNameByPartitionSlot(FstabItem * item)426 static void AdjustPartitionNameByPartitionSlot(FstabItem *item)
427 {
428     BEGET_CHECK_ONLY_RETURN(strstr(item->deviceName, "/system") != NULL ||
429         strstr(item->deviceName, "/vendor") != NULL);
430     char buffer[MAX_BUFFER_LEN] = {0};
431     int slot = GetCurrentSlot();
432     BEGET_ERROR_CHECK(slot > 0 && slot <= MAX_SLOT, slot = 1, "slot value %d is invalid, set default value", slot);
433     BEGET_ERROR_CHECK(sprintf_s(buffer, sizeof(buffer), "%s_%c", item->deviceName, 'a' + slot - 1) > 0,
434         return, "Failed to format partition name suffix, use default partition name");
435     free(item->deviceName);
436     item->deviceName = strdup(buffer);
437     BEGET_LOGI("partition name with slot suffix: %s", item->deviceName);
438 }
439 
CheckRequiredAndMount(FstabItem * item,bool required)440 static int CheckRequiredAndMount(FstabItem *item, bool required)
441 {
442     int rc = 0;
443     if (item == NULL) {
444         return -1;
445     }
446     if (required) { // Mount partition during first startup.
447         if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
448             int bootSlots = GetBootSlots();
449             BEGET_INFO_CHECK(bootSlots <= 1, AdjustPartitionNameByPartitionSlot(item),
450                 "boot slots is %d, now adjust partition name according to current slot", bootSlots);
451         #ifdef SUPPORT_HVB
452             rc = HvbDmVeritySetUp(item);
453             if (rc != 0) {
454                 BEGET_LOGE("set dm_verity err, ret = 0x%x", rc);
455                 return rc;
456             }
457         #endif
458             rc = MountOneItem(item);
459         }
460     } else { // Mount partition during second startup.
461         if (!FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
462             rc = MountOneItem(item);
463         }
464     }
465     return rc;
466 }
467 
MountAllWithFstab(const Fstab * fstab,bool required)468 int MountAllWithFstab(const Fstab *fstab, bool required)
469 {
470     BEGET_CHECK(fstab != NULL, return -1);
471 
472     FstabItem *item = NULL;
473     int rc = -1;
474 
475 #ifdef SUPPORT_HVB
476     if (required) {
477         rc = HvbDmVerityinit(fstab);
478         if (rc != 0) {
479             BEGET_LOGE("set dm_verity init, ret = 0x%x", rc);
480             return rc;
481         }
482     }
483 #endif
484 
485     for (item = fstab->head; item != NULL; item = item->next) {
486         rc = CheckRequiredAndMount(item, required);
487         if (required && (rc < 0)) { // Init fail to mount in the first stage and exit directly.
488             break;
489         }
490     }
491 
492 #ifdef SUPPORT_HVB
493     if (required)
494         HvbDmVerityFinal();
495 #endif
496 
497     return rc;
498 }
499 
MountAllWithFstabFile(const char * fstabFile,bool required)500 int MountAllWithFstabFile(const char *fstabFile, bool required)
501 {
502     bool isFile = fstabFile == NULL || *fstabFile == '\0';
503     BEGET_CHECK(!isFile, return -1);
504 
505     Fstab *fstab = NULL;
506     if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) {
507         BEGET_LOGE("[fs_manager][error] Read fstab file \" %s \" failed\n", fstabFile);
508         return -1;
509     }
510 
511     int rc = MountAllWithFstab(fstab, required);
512     ReleaseFstab(fstab);
513     fstab = NULL;
514     return rc;
515 }
516 
UmountAllWithFstabFile(const char * fstabFile)517 int UmountAllWithFstabFile(const char *fstabFile)
518 {
519     bool isFile = fstabFile == NULL || *fstabFile == '\0';
520     BEGET_CHECK(!isFile, return -1);
521 
522     Fstab *fstab = NULL;
523     fstab = ReadFstabFromFile(fstabFile, false);
524     BEGET_ERROR_CHECK(fstab != NULL, return -1, "Read fstab file \" %s \" failed.", fstabFile);
525 
526     FstabItem *item = NULL;
527     int rc = -1;
528     for (item = fstab->head; item != NULL; item = item->next) {
529         BEGET_LOGI("Umount %s.", item->mountPoint);
530         MountStatus status = GetMountStatusForMountPoint(item->mountPoint);
531         if (status == MOUNT_ERROR) {
532             BEGET_LOGW("Cannot get mount status of mount point \" %s \"", item->mountPoint);
533             continue; // Cannot get mount status, just ignore it and try next one.
534         } else if (status == MOUNT_UMOUNTED) {
535             BEGET_LOGI("Mount point \" %s \" already unmounted. device path: %s, fs type: %s.",
536                 item->mountPoint, item->deviceName, item->fsType);
537             continue;
538         } else {
539             rc = umount(item->mountPoint);
540             if (rc == -1) {
541                 BEGET_LOGE("Umount %s failed, device path: %s, fs type: %s, err = %d.",
542                     item->mountPoint, item->deviceName, item->fsType, errno);
543             } else {
544                 BEGET_LOGE("Umount %s successfully.", item->mountPoint);
545             }
546         }
547     }
548     ReleaseFstab(fstab);
549     fstab = NULL;
550     return rc;
551 }
552 #ifdef __cplusplus
553 #if __cplusplus
554 }
555 #endif
556 #endif
557