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