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